使用Java更新XML文档

时间:2015-01-14 19:19:54

标签: java xml xpath

在互联网上,我找到了很多关于如何实现这一功能的例子,但是在我的案例中似乎都没有。我有一个包含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);

代码应该像上面那样,但是我没有得到结果,

你能说出我错过的东西吗?

亲切的问候 最大

1 个答案:

答案 0 :(得分:0)

在使用命名空间评估XPATH表达式之前,您还需要做两件事。

  1. 默认情况下,DocumentBuilderFactory实例不支持名称空间。所以你必须致电setNamespaceAware(true)
  2. 创建您自己的界面NamespaceContext实施,并将其传递给您的XPath实例。
  3. 这里有一个简单的NamespaceContext实现作为静态内部类。此处仅实现getNamespaceURI()方法。 (有关更多详细信息和替代实现,请参阅此IBM developerWorks文章: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();
      }
    }
    

    此处包含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实现中同时声明这两个前缀。