获取子节点包含属性的节点


116

假设我有以下XML:

<book category="CLASSICS">
  <title lang="it">Purgatorio</title>
  <author>Dante Alighieri</author>
  <year>1308</year>
  <price>30.00</price>
</book>

<book category="CLASSICS">
  <title lang="it">Inferno</title>
  <author>Dante Alighieri</author>
  <year>1308</year>
  <price>30.00</price>
</book>

<book category="CHILDREN">
  <title lang="en">Harry Potter</title>
  <author>J K. Rowling</author>
  <year>2005</year>
  <price>29.99</price>
</book>

<book category="WEB">
  <title lang="en">XQuery Kick Start</title>
  <author>James McGovern</author>
  <author>Per Bothner</author>
  <author>Kurt Cagle</author>
  <author>James Linn</author>
  <author>Vaidyanathan Nagarajan</author>
  <year>2003</year>
  <price>49.99</price>
</book>

<book category="WEB">
  <title lang="en">Learning XML</title>
  <author>Erik T. Ray</author>
  <year>2003</year>
  <price>39.95</price>
</book>

我想做一个xpath,以获取所有具有title节点且语言属性为“ it”的书节点。

我的尝试看起来像这样:

//book[title[@lang='it']]

但这没有用。我希望得到节点:

<book category="CLASSICS">
  <title lang="it">Purgatorio</title>
  <author>Dante Alighieri</author>
  <year>1308</year>
  <price>30.00</price>
</book>

<book category="CLASSICS">
  <title lang="it">Inferno</title>
  <author>Dante Alighieri</author>
  <year>1308</year>
  <price>30.00</price>
</book>

有什么提示吗?


这是什么XPath实现?
Pavel Minaev 09年

Answers:


175

尝试

//book[title/@lang = 'it']

内容为:

  • 获取所有book元素
    • 至少有一个 title
      • 有一个属性 lang
        • 的值为 "it"

您可能会发现很有帮助-这是Ronald Bourret 撰写的标题为“五个段落中的XPath”的文章。

//book[title[@lang='it']]实际上,除非您的XPath引擎出现“问题”,否则上述内容应等效。因此,可能是您未向我们展示的代码或示例XML中的某些内容-例如,您的示例是XML片段。可能是根元素具有名称空间,而您没有在查询中计入该名称空间吗?您只是告诉我们这没有用,但没有告诉我们您得到了什么结果。


4
如果title不是的直接子代book,但在更深的地方又不知道确切在哪里,该怎么做?//book[/title/@lang = 'it']似乎不起作用?
Martin Konicek 2013年

5
马丁,您可以使用//book[.//title/@lang ='it']。我相信诀窍是“。” 在病情开始时。
布鲁诺·卡波尼

1
感谢您的链接,优秀的文章。我已经使用xPath多年了,但这确实帮助我了解了基本逻辑!
swensor

57

几年后,但是一个有用的选择是利用XPath Axes(https://www.w3schools.com/xml/xpath_axes.asp)。更具体地说,您正在寻找使用后代轴。

我相信这个例子可以解决问题:

//book[descendant::title[@lang='it']]

这样,您就可以选择所有book包含子title元素的元素(无论其嵌套深度如何),而子元素的语言属性值等于“ it”。

我不能肯定地说这个答案是否与2009年有关,因为我不确定100%当时是否存在XPath轴。我可以确认的是它们确实存在,并且我发现它们在XPath导航中非常有用,并且我相信您也将如此。


12
//book[title[@lang='it']]

实际上相当于

 //book[title/@lang = 'it']

我使用vtd-xml进行了尝试,两个表达式都吐出了相同的结果……您使用了什么xpath处理引擎?我猜它有一致性问题下面是代码

import com.ximpleware.*;
public class test1 {
  public static void main(String[] s) throws Exception{
      VTDGen vg = new VTDGen();
      if (vg.parseFile("c:/books.xml", true)){
          VTDNav vn = vg.getNav();
          AutoPilot ap = new AutoPilot(vn);
          ap.selectXPath("//book[title[@lang='it']]");
                  //ap.selectXPath("//book[title/@lang='it']");

          int i;
          while((i=ap.evalXPath())!=-1){
              System.out.println("index ==>"+i);
          }
          /*if (vn.endsWith(i, "< test")){
             System.out.println(" good ");  
          }else
              System.out.println(" bad ");*/

      }
  }
}

+1表示其依从性问题,并且语法生成相同的节点集。C#中的类似代码也可以使用。
Zach Bonham

-1:张先生,我试图通过删除与该问题无关的代码来帮您一个忙。它使我不必对您投反对票,我现在觉得必须这样做。请注意,没有其他答案包含要调用的代码来调用查询。
约翰·桑德斯

6
+1:因为我不知道桑德斯先生在说什么-没有其他答案添加了任何代码,并且此答案显示了所使用的代码,因此我们可以1:验证他的方法,2:自己进行测试。该代码简短易读。我没看到问题。
DuckPuppy

4

我认为您自己的建议是正确的,但是xml不太有效。如果您正在运行//book[title[@lang='it']]<root>[Your"XML"Here]</root>则免费的在线xPath测试器(例如此处的测试器)将找到预期的结果。


2

尝试使用此xPath表达式:

//book/title[@lang='it']/..

那应该给你“ it” lang中的所有书节点


2
该表达式的结果是标题节点,而不是书本节点
Caleth,2016年

2
那是不对的。它将返回书本节点(最后两个点瞄准标题节点的上层节点)。
user1113000 '19
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.