使用local-name()在XSLT中获取第一个子节点

时间:2011-11-08 23:03:24

标签: xml xslt xpath xslt-1.0 xalan

假设我们有这个简单的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

3 个答案:

答案 0 :(得分:12)

这是一个常见问题解答 - 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"/>

答案 1 :(得分:11)

您说的路径表达式适用于您

//books[1]/*

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

相同
/books/*

返回两个&lt; book&gt;节点,所以说你只返回一个节点就错了。

很难知道您需要什么,就像您始终将local-name应用于根节点一样,您不需要知道其名称,只需/*即可访问它,所以你只想

/*/*[1]

但是要访问&lt; books&gt;的第一个子节点您要编写的文档中的任何位置

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

您应该小心尽可能地限制您的上下文,因为使用//启动XPath表达式将强制搜索整个文档,如果有问题的节点总是如此,这将是毫无意义且耗时的在根。

答案 2 :(得分:0)

我必须遇到同样的担忧。我解决了如下:

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

度过愉快的一天。