我有以下XML文件:
<foo:a xmlns:foo=\"http://www.foo.com\">
<foo:b foo:bar=\"zar\">
</foo:b>
</foo:a>
要获取 b 节点,其属性 bar 的值为&#34; zar&#34; (所有在正确的命名空间中),我可以使用XPath表达式:
/foo:a/foo:b[@foo:bar=\"zar\"]
(&#34; foo&#34;正确绑定到&#34; http://www.foo.com&#34; - 请参阅最后的代码)
但是,当我想以名称空间不知情的方式做同样的事情时,虽然我可以依靠local-name()
函数从元素中删除命名空间,但是我无法从属性中删除它们。
这是我能想到的最好的:
/*[local-name()='a']/*[local-name()='b' and @foo:bar=\"zar\"]
(令人遗憾的是,foo
用于限定bar
属性。
如何在完全删除命名空间的情况下编写上述表达式?
下面的代码已经在CLASSPATH上使用和不使用 Saxon-HE-9.4.jar 进行了测试并产生了正确的结果,但我无法获得“foo”#39 ;名称空间前缀超出第二个XPath表达式!
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 = "<foo:a xmlns:foo=\"http://www.foo.com\"><foo:b foo:bar=\"zar\"></foo:b></foo:a>";
XPath xpath = namespaceAwareXpath("foo", "http://www.foo.com");
{
System.out.printf("[NS-aware ] Number of 'b' nodes with foo:bar attribute having the value \"zar\" is: %d\n",
((NodeList) xpath.compile("/foo:a/foo:b[@foo:bar=\"zar\"]").evaluate(stringToXML(xmlSample, true),
XPathConstants.NODESET)).getLength());
}
{
System.out.printf("[NS-aware but using local-name() ] Number of 'b' nodes with foo:bar attribute having the value \"zar\" is: %d\n",
((NodeList) xpath.compile("/*[local-name()='a']/*[local-name()='b' and @foo:bar=\"zar\"]").evaluate(stringToXML(xmlSample, true),
XPathConstants.NODESET)).getLength());
}
}
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")));
}
}
答案 0 :(得分:14)
/*[local-name()='a']/*[local-name()='b' and @*[local-name() = 'bar']=\"zar\"]