6

假设我们有这个简单的 xml ...

 <books>   
    <book>
       <author/>
       <title/>
    </book>
    <book>
       <author/>
       <title/>
    </book>
 </books>

我正在使用这个 xpath 来获取第一本书实例的元素。

//books[1]/*

退货

<author/>
<title/>

这很好用,但我必须使用 local-name() 让它工作。我尝试了以下方法,但这些都不起作用......

//*[local-name()='books']/*

这会返回重复的作者和标题元素,不好,我只需要第一个孩子的

//*[local-name()='books'][0]/*

这不会返回任何东西

基本上,我想创建一个 CSV 文件,因此输出中的第一行将是一个标题,其中列出了书籍属性名称,后跟任意数据值。我只需要让标题部分工作。

author,title
john,The End is Near
sally,Looking for Answers
4

3 回答 3

13

这是一个常见问题解答——XPath[]运算符的优先级(优先级)高于//伪运算符。

所以:

//someElemName[1]

选择每个命名someElemName为其父元素的第一个子元素的元素——并且,根据 XML 文档,可以有多个这样的元素。

要改变这一点,必须使用括号。

使用

(//*[local-name() = 'book'])[1]/*

另请注意:在 XPath 中,位置是从 1 开始的,而不是从 0 开始的。

基于 XSLT 的验证:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

 <xsl:template match="/">
  <xsl:copy-of select=
  "(//*[local-name() = 'book'])[1]/*"/>
 </xsl:template>
</xsl:stylesheet>

当此转换应用于以下 XML 文档时

<books>
    <book num="1">
        <author num="1"/>
        <title num="1"/>
    </book>
    <book num="2">
        <author num="2"/>
        <title num="2"/>
    </book>
</books>

选择想要的节点并将其复制到输出

<author num="1"/>
<title num="1"/>
于 2011-11-09T03:34:33.707 回答
12

你说的路径表达式对你有用

//books[1]/*

生成任何 <books> 节点的第一次(并且仅在这种情况下)出现的所有子节点的列表。因为,在您的数据中,<books> 的唯一出现是在根,它与

/books/*

它返回两个 <book> 节点,所以说它只返回一个节点是错误的。

很难知道你需要什么,就好像你总是申请local-name根节点那么你不需要知道它的名字并且可以用 just 来访问它/*,所以你想要简单

/*/*[1]

但是,要访问文档中任何位置的 <books> 节点的第一个子节点,您将编写

//*[local-name()='books']/*[1]

您应该尽可能小心地限制您的上下文,因为以 开头的 XPath 表达式//将强制搜索整个文档,如果所讨论的节点始终位于根目录,这将毫无意义且耗时。

于 2011-11-09T01:54:09.190 回答
0

我必须面对同样的担忧。我解决如下:

//*[local-name()='MYNODENAME' and position()=X]

祝你今天过得愉快。

于 2014-10-07T07:27:44.590 回答