使用xPath修改XML文件

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

  true 1.0  

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

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

之后XML文件应如下所示:

   true 4.0 asdf  true   

我试过这个:

 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 ……一旦编写了function(比如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 

然后,如果您只想更新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"); 

这是一个简单的XSLT解决方案

         4.0    asdf true    

在提供的XML文档上应用此转换时:

  true 1.0  

产生了想要的正确结果:

  true 4.0 asdf true  

请注意

XSLT转换永远不会“就地更新”。 它总是创建一个新的结果树。 因此,如果想要修改同一文件,通常将转换结果保存在另一个名称下,则删除原始文件并将结果重命名为原始名称。

我创建了一个使用XPATH创建/更新XML的小项目: https : //github.com/shenghai/xmodifier更改xml的代码如下:

 DocumentBuilderFactory builderFactory = DocumentBuilderFactory.newInstance(); builderFactory.setNamespaceAware(true); DocumentBuilder documentBuilder = builderFactory.newDocumentBuilder(); Document document = documentBuilder.parse(xmlfile); XModifier modifier = new XModifier(document); modifier.addModify("/configuration/param1", "asdf"); modifier.addModify("/configuration/param2", "asdf"); modifier.addModify("/configuration/test/param3", "true"); modifier.modify(); 

我会指出一种新的/新颖的方式来做你所描述的,使用VTD-XML …有很多原因可以解释为什么VTD-XML比为这个问题提供的所有其他解决方案要好得多……这里有一些链接……

  • 使用vtd-xml简化XML处理
  • 使用Ximple方式处理XML
  • 使用Java处理XML – 性能基准

DFS

  import com.ximpleware.*; import java.io.*; public class modifyXML { public static void main(String[] s) throws VTDException, IOException{ VTDGen vg = new VTDGen(); if (!vg.parseFile("input.xml", false)) return; VTDNav vn = vg.getNav(); AutoPilot ap = new AutoPilot(vn); ap.selectXPath("/configuration/param1/text()"); XMLModifier xm = new XMLModifier(vn); // using XPath int i=ap.evalXPath(); if(i!=-1){ xm.updateToken(i, "4.0"); } String s1 ="asdf/n/ntrue/n"; xm.insertAfterElement(s1); xm.output("output.xml"); } }