如何从xpath表达式获取实际的Node顺序(java)

时间:2011-03-31 08:37:33

标签: java xslt xpath

如果我有一个使用preceding-sibling::的XPath表达式,则NodeList的顺序不正确。我怎样才能得到正确的订单?例如:

<library>
  <book name="book1">
    hello
  </book>
  <book name="book2">
    world
  </book>
  <book name="book3">
    !!!
  </book>
</library>

如果我尝试评估XPath表达式:/library/book[3]/preceding-sibling::book,我会收到此订单:

  • BOOK1
  • 第二册

但如果我尝试评估:/library/book[3]/preceding-sibling::book[1],我会得到Node

  • 第二册

那么,我怎样才能从这种表达式中获得真正的顺序:

/library/book[3]/preceding-sibling::book

3 个答案:

答案 0 :(得分:5)

来自http://www.w3.org/TR/xpath/#predicates

  

轴是前轴或   反转轴。一个永远的轴   包含上下文节点或节点   在上下文节点之后   文档顺序是前进轴。一个   只包含的轴   上下文节点或之前的节点   文档顺序中的上下文节点是   反转轴。因此,祖先,   祖先或自我,先于,和   前兄弟轴是反向的   轴;所有其他轴都是前轴。   由于自身轴始终包含at   大多数节点,它没有任何区别   无论是前进还是后退   轴。 a的接近位置   相对于节点集的成员   轴被定义为位置   在...中排序的节点集中的节点   如果轴是a,则为文档顺序   前进轴和反向排序   如果轴是a,则为文档顺序   反转轴。第一个位置是1.

关于使用特定XPath引擎评估某些XPath表达式后结果节点集的顺序,这完全取决于实现。在XSLT中,当指令处理按文档顺序排序的节点集时,会明确定义它。在XPath中,这是在http://www.w3.org/TR/xpath/#section-Introduction中定义节点集的方式:

  

node-set(无序集合   没有重复的节点)

这就是为什么在标准DOM API中有settings来获取有序和无序结果以及XQuery

答案 1 :(得分:3)

节点集没有顺序(根据定义,集合是无序的)。大多数XPath API通过在文档顺序中评估XPath表达式来呈现节点集结果,这是您在问题中观察和报告的内容。

XPath是一种查询(只读)语言,因此它永远不会修改源XML文档的结构 - 所选节点的节点集中的节点与源XML文档中的结构相同。除其他外,结构包括 order

如果您需要在XML文档中以与原始顺序不同的顺序返回的节点,则无法单独使用XPath

可以将XSLT用于此目的:

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

 <xsl:template match="node()|@*">
     <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match="library">
  <xsl:apply-templates select="*[not(position() >2)]">
   <xsl:sort select="position()"
   data-type="number" order="descending"/>
  </xsl:apply-templates>
 </xsl:template>
</xsl:stylesheet>

在提供的XML文档上应用此转换时:

<library>
    <book name="book1">     hello   </book>
    <book name="book2">     world   </book>
    <book name="book3">     !!!   </book>
</library>

产生了想要的正确结果:

<book name="book2">     world   </book>
<book name="book1">     hello   </book>

答案 2 :(得分:2)

preceding-sibling轴按相反顺序编制索引。 preceding-sibling::*[1]是先前的兄弟节点,即上下文节点之前的兄弟节点。

显然,Java按文档顺序返回NodeList。有关节点集顺序(及其在宿主语言中的表示)的更多详细信息,请参阅@ Alejandro的答案。

因此,从另一端迭代NodeList将是一种选择。也试试这个XPath。

/library/book[position() < 3]

结果将再次按文档顺序排列,但表达式不如您的复杂。