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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8058308/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-06 15:01:04  来源:igfitidea点击:

Get first child node in XSLT using local-name()

xmlxsltxpathxslt-1.0xalan

提问by raffian

Assume we have this simple xml ...

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

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

I'm using this xpath to get the elements of the first book instance.

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

//books[1]/*

Returns

退货

<author/>
<title/>

And that works fine, but I have to get it working using local-name(). I've tried the following but none of these work...

这工作正常,但我必须使用 local-name() 让它工作。我已经尝试了以下但这些都不起作用......

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

this returns repeating author and title elements, not good, I only need them from the first child

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

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

this does not return anything

这不会返回任何东西

Basically, I want to create a CSV file, so the first line in the output will be a header listing the book attribute names followed by the arbitrary data values. I only need to get the header part working.

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

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

回答by Dimitre Novatchev

This is a FAQ-- the XPath []operator has higher precedence (priority) than the //pseudo-operator.

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

So:

所以:

//someElemName[1]

selects every element named someElemNamethat is the first child of its parent -- and, depending on the XML document, there can be more than one such elements.

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

To change this, one must use brackets.

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

Use:

使用

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

Also note: In XPath positions are 1-based, not 0-based.

另请注意:在 XPath 中,位置是基于 1 的,而不是基于 0 的。

XSLT-based verification:

基于 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>

when this transformation is applied on the following XML document:

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

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

the wanted nodes are selected and copied to the output:

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

<author num="1"/>
<title num="1"/>

回答by Borodin

The path expression you say works for you

你说的路径表达式适合你

//books[1]/*

generates a list of all child nodes of the first (and only in this case) occurrence of any <books> node. Because, in your data, the only occurrence of <books> is at the root, it is the same as

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

/books/*

which returns two <book> nodes, and so you are wrong to say that it returns only one node.

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

It is hard to know what you need, as if you are always applying local-nameto the root node then you do not need to know its name and can access it with just /*, so you would want simply

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

/*/*[1]

However to access the first child node of a <books> node anywhere in the document you would write

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

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

You should be careful to confine your context as much as possible, as starting the XPath expression with //will force a search of the entire document, which is pointless and time-consuming if the node in question is always at the root.

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

回答by I_am_an_invited_person

I have to meet same concerns. I solved as follows:

我必须满足同样的担忧。我解决如下:

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

Have a nice day.

祝你今天过得愉快。