我有以下示例XML文件:
<a xmlns="http://www.foo.com">
<b>
</b>
</a>
使用
XPath
表达式/foo:a/foo:b
(在'foo'
中正确配置了NamespaceContext
),我可以正确计算b
节点的数量,并且当Saxon-HE-9.4.jar
在CLASSPATH上以及不在CLASSPATH上时,该代码都可以工作。但是,当我使用名称空间-而不知道
DocumentBuilderFactory
解析同一文件时,只有当CLASSPATH上的b
是而不是时,XPath表达式“/ a / b”才能正确计算Saxon-HE-9.4.jar
节点的数量。代码如下:
import java.io.*;
import java.util.*;
import javax.xml.xpath.*;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import javax.xml.namespace.NamespaceContext;
public class FooMain {
public static void main(String args[]) throws Exception {
String xmlSample = "<a xmlns=\"http://www.foo.com\"><b></b></a>";
{
XPath xpath = namespaceUnawareXpath();
System.out.printf("[NS-unaware] Number of 'b' nodes is: %d\n",
((NodeList) xpath.compile("/a/b").evaluate(stringToXML(xmlSample, false),
XPathConstants.NODESET)).getLength());
}
{
XPath xpath = namespaceAwareXpath("foo", "http://www.foo.com");
System.out.printf("[NS-aware ] Number of 'b' nodes is: %d\n",
((NodeList) xpath.compile("/foo:a/foo:b").evaluate(stringToXML(xmlSample, true),
XPathConstants.NODESET)).getLength());
}
}
public static XPath namespaceUnawareXpath() {
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
return xpath;
}
public static XPath namespaceAwareXpath(final String prefix, final String nsURI) {
XPathFactory xPathfactory = XPathFactory.newInstance();
XPath xpath = xPathfactory.newXPath();
NamespaceContext ctx = new NamespaceContext() {
@Override
public String getNamespaceURI(String aPrefix) {
if (aPrefix.equals(prefix))
return nsURI;
else
return null;
}
@Override
public Iterator getPrefixes(String val) {
throw new UnsupportedOperationException();
}
@Override
public String getPrefix(String uri) {
throw new UnsupportedOperationException();
}
};
xpath.setNamespaceContext(ctx);
return xpath;
}
private static Document stringToXML(String s, boolean nsAware) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(nsAware);
DocumentBuilder builder = factory.newDocumentBuilder();
return builder.parse(new ByteArrayInputStream(s.getBytes("UTF-8")));
}
}
使用以下命令运行以上命令:
java -classpath dist/foo.jar FooMain
..产生:
[NS-unaware] Number of 'b' nodes is: 1
[NS-aware ] Number of 'b' nodes is: 1
运行:
java -classpath Saxon-HE-9.4.jar:dist/foo.jar FooMain
...产生:
[NS-unaware] Number of 'b' nodes is: 0
[NS-aware ] Number of 'b' nodes is: 1
最佳答案
XPath语言仅在命名空间格式良好的XML上定义,因此,不同处理器在非命名空间感知的DOM树上的行为(即使像<a><b/></a>
这样的树,如果以命名空间感知的方式进行解析,也不会实际使用任何名称空间)最多是特定于实现的,最坏的情况是完全未定义。