使用xPath修改XML文件 [英] Modify XML file with xPath

查看:54
本文介绍了使用xPath修改XML文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I want to modify an existing XML file using xPath. If the node doesn't exist, it should be created (along with it's parents if neccessary). An example:

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

这是我要插入/修改的几个xPath:

And here are a couple of xPaths I want to insert/modify:

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

此后XML文件应如下所示:

The XML file should look like this afterwards:

<?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为空(因此抛出了NullPointerException):

The node is changed in the file after running this code. Exactly what I wanted. But if I use one of the below paths, node is null (and therefore a NullPointerException is thrown):

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

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

How can I change this code so that the node (and non existing parent nodes as well) are created?

编辑:好的,请澄清一下:我有一组要保存为XML的参数.在开发过程中,此集合可以更改(某些参数被添加,某些参数被移动,某些参数被删除).因此,我基本上想拥有一个将当前参数集写入现有文件的功能.它应该覆盖文件中已经存在的参数,添加新参数,然后在其中保留旧参数.

EDIT: Ok, to clarify: I have a set of parameters that I want to save to XML. During development, this set can change (some parameters get added, some get moved, some get removed). So I basically want to have a function to write the current set of parameters to an already existing file. It should override the parameters that already exist in the file, add new parameters and leave old parameters in there.

阅读时也一样,我可以只使用xPath或其他一些坐标,然后从XML中获取值.如果不存在,则返回空字符串.

The same for reading, I could just have the xPath or some other coordinates and get the value from the XML. If it doesn't exist, it returns the empty string.

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

I don't have any constraints on how to implement it, xPath, DOM, SAX, XSLT... It should just be easy to use once the functionality is written (like BeniBela's solution).

因此,如果要设置以下参数:

So if I have the following parameters to set:

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

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

the result should be the starting XML + those parameters. If they already exist at that xPath, they get replaced, otherwise they get inserted at that point.

推荐答案

如果您想要一个没有依赖项的解决方案,则可以仅使用DOM而不使用XPath/XSLT.

If you want a solution without dependencies, you can do it with just DOM and without XPath/XSLT.

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

Node.getChildNodes|getNodeName / NodeList.* can be used to find the nodes, and Document.createElement|createTextNode, Node.appendChild to create new ones.

然后,您可以编写自己的简单"XPath"解释器,该解释器将在路径中创建丢失的节点,如下所示:

Then you can write your own, simple "XPath" interpreter, that creates missing nodes in the path like that:

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()节点,则可以将其用作:

Then, if you only want to update text() nodes, you can use it as:

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");

这篇关于使用xPath修改XML文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆