Can anyone explain what's the difference between
/root/a[position()=1 or position()=2
and
/root/a[1 or 2]
? I'd assume the 2nd开发者_JAVA技巧 to be abbreviated form of the 1st, but Java XPath (Sun JDK 1.6.0) processor thinks otherwise. Following is my test application.
libxml2 library and also db2 XPath processor consider these paths different too. So it doesn't look like JDK bug.
import java.io.*;
import javax.xml.xpath.*;
import org.w3c.dom.*;
import org.xml.sax.InputSource;
public class XPathTest {
public static void main(String[] args) throws Exception {
//String xpathStr = "/root/a[position()=1 or position()=2]";
String xpathStr = "/root/a[1 or 2]";
XPathFactory xpf = XPathFactory.newInstance();
XPath xp = xpf.newXPath();
Reader irdr = new StringReader(
"<root><a name=\"first\"/><a name=\"second\"/><a name=\"third\"/></root>");
InputSource isrc = new InputSource(irdr);
XPathExpression expr = xp.compile(xpathStr);
Object result = expr.evaluate(isrc, XPathConstants.NODESET);
NodeList nodes = (NodeList) result;
for (int i = 0; i < nodes.getLength(); i++) {
Node node = nodes.item(i);
Element element = (Element) node;
System.out.print(element.getNodeName() + " " + element.getAttributeNode("name"));
System.out.println();
}
}
}
I don't think [1 or 2]
is evaluating how you think it is evaluating. or
works on two boolean values. I suspect both 1
and 2
are evaluating as true. Therefore this expression is evaluating as true and essentially doing nothing, and will return all elements.
In general, position()
can be used in expressions like [position() <= 5]
whereas the index address can only ever select one element like [5]
.
If the value in square brackets is a number [N]
, it is interpreted as [position()=N]
. But [1 or 2]
is not a number, so this rule does not apply.
[1 or 2]
evaluates to an "always true" predicate in .Net as well, so this behaviour appears consistent:
Here's the output from a the XPath of a .NET 3.5 XmlDocument
// Returns first, second
var ndl = dom.SelectNodes(@"/root/a[position()=1 or position()=2]");
// Returns first, second and third
ndl = dom.SelectNodes(@"/root/a[1 or 2]");
// Returns first, second
ndl = dom.SelectNodes(@"/root/a[1] | /root/a[2]");
Edit
In XPath 2, you can use the sequence functions index-of
and exists
to determine whether the given position is contained in a sequence of values:
/root/a[exists(index-of((1,2), position()))]
A numeric value in []
is treated as an index. The OR
doesn't work for indexes on a way like yours ( [1 or 2]
). The right way is using position()
.
精彩评论