How to get the real Node order from xpath expression (java)
If I have an XPath expression that use preceding-sibling::
, I get the NodeList
not in the right order. How can I get the right order? Example:
<library>
<book name="book1">
hello
</book>
<book name="book2">
world
</book>
<book name="book3">
!!!
</book>
</library>
If I try to eval开发者_如何学Cuate the XPath expression: /library/book[3]/preceding-sibling::book
, I get this order:
- book1
- book2
But if I try to evaluate : /library/book[3]/preceding-sibling::book[1]
, I get the Node
:
- book2
So, how can I get the real order from this kind of expression:
/library/book[3]/preceding-sibling::book
?
From http://www.w3.org/TR/xpath/#predicates
An axis is either a forward axis or a reverse axis. An axis that only ever contains the context node or nodes that are after the context node in document order is a forward axis. An axis that only ever contains the context node or nodes that are before the context node in document order is a reverse axis. Thus, the ancestor, ancestor-or-self, preceding, and preceding-sibling axes are reverse axes; all other axes are forward axes. Since the self axis always contains at most one node, it makes no difference whether it is a forward or reverse axis. The proximity position of a member of a node-set with respect to an axis is defined to be the position of the node in the node-set ordered in document order if the axis is a forward axis and ordered in reverse document order if the axis is a reverse axis. The first position is 1.
About the order of the result node set after evaluation of some XPath expression with an specific XPath engine, that's completely implementation dependant. In XSLT, it's explicitly defined when instructions treats node set sorted in document order. In XPath this is how node sets are defined in http://www.w3.org/TR/xpath/#section-Introduction :
node-set (an unordered collection of nodes without duplicates)
That's why in the standard DOM API there are settings to get ordered and unordered results as well as in XQuery
A node-set doesn't have order (sets are unordered by definition). Most XPath APIs present the node-set result from evaluating an XPath expression in document order, which is what you observe and report in your question.
XPath is a query (read-only) language and as such it never modifies the structure of the source XML document -- the nodes in the nodeset of selected nodes is the same as their structure in the source XML document. Structure, among other things, includes order.
In case you need the nodes returned in another order than their original order in the XML document, this cannot be done with XPath alone.
One can use XSLT for this purpose:
<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>
when this transformation is applied on the provided XML document:
<library>
<book name="book1"> hello </book>
<book name="book2"> world </book>
<book name="book3"> !!! </book>
</library>
the wanted, correct result is produced:
<book name="book2"> world </book>
<book name="book1"> hello </book>
The preceding-sibling
axis is indexed in reversed order. preceding-sibling::*[1]
is the first preceding sibling, i.e. the one right before the context node.
Apparently, Java returns the NodeList
in document order. See @Alejandro's answer for more details about the order of node sets (and their representation in the host language).
So iterating the NodeList
from the other end would be an option. Also try this XPath.
/library/book[position() < 3]
The result will be in document order again, but the expression is less complex than your's.
精彩评论