使用根元素语法中的名称空间前缀解析XML-Java
我有一个使用根元素语法中的名称空间前缀解析XML-Java,java,xml,xpath,xml-namespaces,Java,Xml,Xpath,Xml Namespaces,我有一个XML格式: <?xml version="1.0" encoding="UTF-8"?> <semseg:Envelope xmlns:semseg="http://a-random-URL" xmlns="http://another-random-URL"> <semseg:subject>Subject</semseg:subject> <semseg:Sender> <semseg
XML
格式:
<?xml version="1.0" encoding="UTF-8"?>
<semseg:Envelope xmlns:semseg="http://a-random-URL" xmlns="http://another-random-URL">
<semseg:subject>Subject</semseg:subject>
<semseg:Sender>
<semseg:name>Me</semseg:name>
</semseg:Sender>
<Triangle>
<Triangle time='2017-11-29'>
<Triangle key='a' value='b'/>
<Triangle key='c' value='d'/>
<Triangle key='e' value='f'/>
<Triangle key='g' value='h'/>
</Triangle>
</Triangle>
</semseg:Envelope>
不幸的是,由于没有选择任何元素,我尝试了许多可能的XPath组合。然而,使用在线XPath
检查器和相同的XML
文件测试相同的XPath
,可以得到我想要的结果。它甚至可以使用XPath之类的工具进行属性检索
/semseg:Envelope/Triangle/Triangle/@time
似乎名称空间前缀有问题。解析XML
s而不使用任何名称空间前缀,对于XPath
很好,这对我来说很有用
/\*[local-name()='Envelope']/\*[local-name()='Triangle']/\*[local-name()='Triangle']/@time
您的XML输入实际上有两个名称
默认名称空间
第一个是默认值,声明如下:
<semseg:Envelope ... xmlns="http://another-random-URL" ...
<semseg:Envelope xmlns:semseg="http://a-random-URL" ...
这是有效的:
XPathFactory xPathFactory = XPathFactory.newInstance();
XPath xPath = xPathFactory.newXPath();
xPath.setNamespaceContext(new NamespaceContext() {
@Override
public String getNamespaceURI(String prefix) {
if ("main".equals(prefix)) {
return "http://a-random-URL";
}
if ("secondary".equals(prefix)) {
return "http://another-random-URL";
}
return null;
}
@Override
public String getPrefix(String namespaceURI) {
// This should be implemented but I'm lazy and this sample works without it
return null;
}
@Override
public Iterator getPrefixes(String namespaceURI) {
// This should be implemented but I'm lazy and this sample works without it
return null;
}
});
XPathExpression xpr = xPath.compile("/main:Envelope/secondary:Triangle");
NodeList nodes = (NodeList)xpr.evaluate(doc, XPathConstants.NODESET);
System.out.println(nodes.getLength());
产出:
1
在这里,我实现了一个非常愚蠢的名称空间上下文,但是如果您有Spring框架、CXF、guava(我想)或其他reach框架,您通常会有类似于
SimpleNamespaceContext
或MapBasedNamespaceContext
的东西,这可能是更好的选择。您看过了吗?我想您可以尝试一下,“//三角形[不是(@*)]“作为你的xpath@reflexdemon这行不通unfortunately@GPI我不能真正使用名称空间上下文,因为前缀只适用于XML中的某些元素。你可以看到,Envelope
确实有这样一个前缀,但Triangle
没有。这确实有效,但我一直在寻找更优雅和简洁的答案,这就是为什么我对它进行了投票,但没有将其标记为可接受的答案。不过非常感谢!
XPathFactory xPathFactory = XPathFactory.newInstance();
XPath xPath = xPathFactory.newXPath();
xPath.setNamespaceContext(new NamespaceContext() {
@Override
public String getNamespaceURI(String prefix) {
if ("main".equals(prefix)) {
return "http://a-random-URL";
}
if ("secondary".equals(prefix)) {
return "http://another-random-URL";
}
return null;
}
@Override
public String getPrefix(String namespaceURI) {
// This should be implemented but I'm lazy and this sample works without it
return null;
}
@Override
public Iterator getPrefixes(String namespaceURI) {
// This should be implemented but I'm lazy and this sample works without it
return null;
}
});
XPathExpression xpr = xPath.compile("/main:Envelope/secondary:Triangle");
NodeList nodes = (NodeList)xpr.evaluate(doc, XPathConstants.NODESET);
System.out.println(nodes.getLength());
1