java - 使用 xPath 修改 XML 文件

标签 java xml file xslt xpath

我想使用 xPath 修改现有的 XML 文件。如果该节点不存在,则应创建它(如果需要,连同它的父节点)。一个例子:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <param0>true</param0>
  <param1>1.0</param1>
</configuration>

这里有几个我想插入/修改的 xPath:

/configuration/param1/text()         -> 4.0
/configuration/param2/text()         -> "asdf"
/configuration/test/param3/text()    -> true

之后的 XML 文件应该如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <param0>true</param0>
  <param1>4.0</param1>
  <param2>asdf</param2>
  <test>
    <param3>true</param3>
  </test>
</configuration>

我试过这个:

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

try {
  DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
  Document doc = domFactory.newDocumentBuilder().parse(file.getAbsolutePath());
  XPath xpath = XPathFactory.newInstance().newXPath();

  String xPathStr = "/configuration/param1/text()";
  Node node = ((NodeList) xpath.compile(xPathStr).evaluate(doc, XPathConstants.NODESET)).item(0);
  System.out.printf("node value: %s\n", node.getNodeValue());
  node.setNodeValue("4.0");

  TransformerFactory transformerFactory = TransformerFactory.newInstance();
  Transformer transformer = transformerFactory.newTransformer();
  transformer.transform(new DOMSource(doc), new StreamResult(file));
} catch (Exception e) {
  e.printStackTrace();
}

运行此代码后,文件中的节点发生更改。正是我想要的。但是,如果我使用以下路径之一,node 为 null(因此抛出 NullPointerException):

/configuration/param2/text()
/configuration/test/param3/text()

如何更改此代码以便创建节点(以及不存在的父节点)?

编辑:好的,澄清一下:我有一组要保存到 XML 的参数。在开发过程中,这个集合可以改变(一些参数被添加,一些被移动,一些被删除)。所以我基本上想要一个函数来将当前的参数集写入一个已经存在的文件中。它应该覆盖文件中已存在的参数,添加新参数并保留旧参数。

对于阅读来说也是如此,我可以只拥有 xPath 或其他一些坐标并从 XML 中获取值。如果不存在,则返回空字符串。

我对如何实现它没有任何限制,xPath、DOM、SAX、XSLT...一旦编写了功能就应该很容易使用(比如 BeniBela 的解决方案)。

所以如果我要设置以下参数:

/configuration/param1/text()         -> 4.0
/configuration/param2/text()         -> "asdf"
/configuration/test/param3/text()    -> true

结果应该是起始 XML + 那些参数。如果它们已经存在于该 xPath 中,它们将被替换,否则它们将被插入到该点。

最佳答案

如果您想要一个没有依赖关系的解决方案,您可以只使用 DOM 而不需要 XPath/XSLT。

Node.getChildNodes|getNodeName/NodeList.* 可用于查找节点,Document.createElement|createTextNode、Node.appendChild 可用于创建新节点。

然后您可以编写自己的简单“XPath”解释器,它会像这样在路径中创建丢失的节点:

public static void update(Document doc, String path, String def){
  String p[] = path.split("/");
  //search nodes or create them if they do not exist
  Node n = doc;
  for (int i=0;i < p.length;i++){
    NodeList kids = n.getChildNodes();
    Node nfound = null;
    for (int j=0;j<kids.getLength();j++) 
      if (kids.item(j).getNodeName().equals(p[i])) {
    nfound = kids.item(j);
    break;
      }
    if (nfound == null) { 
      nfound = doc.createElement(p[i]);
      n.appendChild(nfound);
      n.appendChild(doc.createTextNode("\n")); //add whitespace, so the result looks nicer. Not really needed
    }
    n = nfound;
  }
  NodeList kids = n.getChildNodes();
  for (int i=0;i<kids.getLength();i++)
    if (kids.item(i).getNodeType() == Node.TEXT_NODE) {
      //text node exists
      kids.item(i).setNodeValue(def); //override
      return;
    }

  n.appendChild(doc.createTextNode(def));    
}

然后,如果您只想更新 text() 节点,您可以将其用作:

DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
Document doc = domFactory.newDocumentBuilder().parse(file.getAbsolutePath());

update(doc, "configuration/param1", "4.0");
update(doc, "configuration/param2", "asdf");
update(doc, "configuration/test/param3", "true");

关于java - 使用 xPath 修改 XML 文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12459712/

相关文章:

java - 编译 OpenGTS 失败

xml - 如何从 perl 中的 xml 中获取所需的元素?

ios - iOS平台如何监控文件变化?

java - JavaBean 和 POJO 有什么区别?

java - 如何在 Choco (CSP) 中定义产品

java - 无法将 CircularSeekBar 添加到我的项目中

Java XML 空节点

bash - 循环查找文件位置,直到文件存在于 bash 中

php 创建文本文件。换行符是错误的

java - 无法将包含所有内容的相对布局转换为图像