在互联网上,我找到了很多如何实现这个功能的例子,但是在我的情况下它们似乎都没有。 我有一个包含XML数据的字符串,我知道结果的XPath应该是什么样子。 比方说,我有一个xml结构,如下所示:
<?xml version="1.0"?> <m:parent xmlns:m="http://www.somescheme"> <doc:header xmlns:doc="http://www.somescheme"> <doc:documentId>137</doc:documentId> <doc:documentDescription>Some Description</doc:documentDescription> <doc:task> <doc:id>49</doc:id> <doc:name>Some Name</doc:name> <doc:description>Some Task Description</doc:description> <doc:outcome/> <doc:dueDate/> <doc:priority>50</doc:priority> </doc:task> </doc:header> <m:otherinfo>234324</m:otherInfo> </m:parent>比方说,我需要访问和更新otherInfo,XPath将是'm:parent / m:otherInfo',我应该能够读取和设置。 对于doc:results,它将是'm:parent / doc:header / doc:task / doc:outcome'这是我需要在运行时设置的值。
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse( new InputSource("data.xml")); XPath xpath = XPathFactory.newInstance().newXPath(); NodeList nodes = (NodeList) xpath.evaluate("//m:parent/doc:header/doc:task/doc:outcome", doc, XPathConstants.NODESET);代码应该像上面那样,但是我没有得到结果,
你能指出我错过的东西吗?
亲切的问候Max
On the internet I am finding a lot of examples of how to achieve this functionality, however none of them seem to work in my case. I have an string containing XML data, and I know what the XPath of the result should look like. Say for example I have an xml structure looking like this:
<?xml version="1.0"?> <m:parent xmlns:m="http://www.somescheme"> <doc:header xmlns:doc="http://www.somescheme"> <doc:documentId>137</doc:documentId> <doc:documentDescription>Some Description</doc:documentDescription> <doc:task> <doc:id>49</doc:id> <doc:name>Some Name</doc:name> <doc:description>Some Task Description</doc:description> <doc:outcome/> <doc:dueDate/> <doc:priority>50</doc:priority> </doc:task> </doc:header> <m:otherinfo>234324</m:otherInfo> </m:parent>Say for example I need to access and update otherInfo the XPath would be 'm:parent/m:otherInfo' which I should be able to read and set. For doc:outcome it would be 'm:parent/doc:header/doc:task/doc:outcome' This is a value I need to set at runtime.
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse( new InputSource("data.xml")); XPath xpath = XPathFactory.newInstance().newXPath(); NodeList nodes = (NodeList) xpath.evaluate("//m:parent/doc:header/doc:task/doc:outcome", doc, XPathConstants.NODESET);The code should be something like above, however I am not getting results,
Can you point out what I am missing ?
Kind Regards Max
最满意答案
在使用命名空间评估XPATH表达式之前,您还需要做两件事。
默认情况下, DocumentBuilderFactory实例不支持名称空间。 所以你必须调用setNamespaceAware(true) 。 创建自己的NamespaceContext接口实现并将其传递给XPath实例。这里有一个简单的NamespaceContext实现作为静态内部类。 这里只实现了getNamespaceURI()方法。 ( 有关更多详细信息和替代实现,请参阅此IBM developerWorks文章: 在XPath中使用Java语言NamespaceContext对象 )
static class MyNamespaceContext implements NamespaceContext { @Override public String getNamespaceURI(String prefix) { if(prefix == null) { throw new IllegalArgumentException(); } else if(prefix.equals(XMLConstants.DEFAULT_NS_PREFIX)) { return XMLConstants.NULL_NS_URI; } else if(prefix.equals(XMLConstants.XML_NS_PREFIX)) { return XMLConstants.XML_NS_URI; } else if(prefix.equals(XMLConstants.XMLNS_ATTRIBUTE)) { return XMLConstants.XMLNS_ATTRIBUTE_NS_URI; } else if(prefix.equals("m")) { return "http://www.somescheme"; } else if(prefix.equals("doc")) { return "http://www.somescheme"; } else { return XMLConstants.NULL_NS_URI; } } @Override public String getPrefix(String namespaceURI) { throw new UnsupportedOperationException(); } @Override public Iterator getPrefixes(String namespaceURI) { throw new UnsupportedOperationException(); } }这里是DocumentBuilderFactory的部分:
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); documentBuilderFactory.setNamespaceAware(true); Document doc = documentBuilderFactory.newDocumentBuilder().parse( new InputSource("data.xml")); XPath xpath = XPathFactory.newInstance().newXPath(); xpath.setNamespaceContext(new MyNamespaceContext()); NodeList nodes = (NodeList) xpath.evaluate( "//m:parent/doc:header/doc:task/doc:outcome", doc, XPathConstants.NODESET);两个名称空间前缀实际上链接到相同的名称空间URI。 实际上,您只能在XPATH表达式中使用一个前缀,例如"//doc:parent/doc:header/doc:task/doc:outcome"并且您不需要在NamespaceContext实现中声明这两个前缀。
You have to do two additional things before you can evaluate XPATH expressions with namespaces.
The DocumentBuilderFactory instance is not namespace aware by default. So you have to call setNamespaceAware(true). Create your own implementation of the interface NamespaceContext and pass it to your XPath instance.Here a simple NamespaceContext implementation as a static inner class. Only the getNamespaceURI() method is implemented here. (See this IBM developerWorks article for more details and alternative implementations: Using the Java language NamespaceContext object with XPath)
static class MyNamespaceContext implements NamespaceContext { @Override public String getNamespaceURI(String prefix) { if(prefix == null) { throw new IllegalArgumentException(); } else if(prefix.equals(XMLConstants.DEFAULT_NS_PREFIX)) { return XMLConstants.NULL_NS_URI; } else if(prefix.equals(XMLConstants.XML_NS_PREFIX)) { return XMLConstants.XML_NS_URI; } else if(prefix.equals(XMLConstants.XMLNS_ATTRIBUTE)) { return XMLConstants.XMLNS_ATTRIBUTE_NS_URI; } else if(prefix.equals("m")) { return "http://www.somescheme"; } else if(prefix.equals("doc")) { return "http://www.somescheme"; } else { return XMLConstants.NULL_NS_URI; } } @Override public String getPrefix(String namespaceURI) { throw new UnsupportedOperationException(); } @Override public Iterator getPrefixes(String namespaceURI) { throw new UnsupportedOperationException(); } }Here the part with the DocumentBuilderFactory:
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance(); documentBuilderFactory.setNamespaceAware(true); Document doc = documentBuilderFactory.newDocumentBuilder().parse( new InputSource("data.xml")); XPath xpath = XPathFactory.newInstance().newXPath(); xpath.setNamespaceContext(new MyNamespaceContext()); NodeList nodes = (NodeList) xpath.evaluate( "//m:parent/doc:header/doc:task/doc:outcome", doc, XPathConstants.NODESET);The two namespace prefixes are actually linked to the same namespace URI. In fact you can use only one prefix in your XPATH expression like "//doc:parent/doc:header/doc:task/doc:outcome" and you don't need to declare both in your NamespaceContext implementation.
更多推荐
发布评论