XPath表达式,如果NodeA存在,则选择NodeA,否则返回NodeB

bon*_*zai 2 xpath

解析POM文件时,我想读取/project/groupId它是否存在.但是,如果它不存在我想阅读/project/parent/groupId.怎么办?

Ian*_*rts 5

如果您有XPath 2.0,那么很容易:

(/project/groupId, /project/parent/groupId)[1]
Run Code Online (Sandbox Code Playgroud)

在XPath 1.0中,它更加狡猾,因为没有像XPath 2.0那样的有序节点序列的概念 - 你可以构建节点集的联合,但位置谓词总是引用文档顺序,所以

(/project/groupId | /project/parent/groupId)[1]
Run Code Online (Sandbox Code Playgroud)

会给你XML文档中的任何一个/project/groupId/project/parent/groupId第一个.

对于这种情况,您可以使用一个技巧,基于以下事实:当您将布尔值视为XPath中的数字时,true变为1,false变为0:

substring(concat(/project/parent/groupId, /project/groupId),
          boolean(/project/groupId) * string-length(/project/parent/groupId) + 1)
Run Code Online (Sandbox Code Playgroud)

为了解释这是做什么,举一个例子 - 父groupId是"foo",项目groupId是"bar".首先我们连接两个,父母首先 - "foobar".接下来,我们检查项目groupId元素是否存在,以及它是否存在

  • boolean(/project/groupId) * string-length(/project/parent/groupId) + 1= 3 + 1=4

所以我们从第四个字符开始获取子字符串,给出结果"bar".

现在假设父groupId是"foo"并且没有项目groupId.在这种情况下

  • concat(/project/parent/groupId, /project/groupId) 只是"foo"
  • boolean(/project/groupId) * string-length(/project/parent/groupId) + 1= 0 + 1=1

由于"从第一个字符开始的子字符串"是整个字符串,因此这给出了"foo"的正确结果.


PS记住你需要考虑命名空间 - Maven POM文件通常声明http://maven.apache.org/POM/4.0.0为默认命名空间,因此你需要使用XPath库提供的任何机制来将其设置为默认命名空间(如果可能)或将其绑定到合适的前缀并使用像这样的路径/pom:project/pom:groupId