在Java中更改XML文件中的一个值,最好的方法是什么?

12

我有一个XML文件,我知道需要更改值的节点名称。

节点名称是ipAddress。

我可以使用JDOM获取文档、获取节点并更改值然后写入,或者我可以编写一个XSLT文件。

代码更改值来自Java,所以我的问题是哪个选项更好?XML文件的大小可能不同。

另一个与XSLT相关的问题:是否可以编写一个XSLT文件,使得我不必列出XML中的所有节点,而只需指定像if node == ipAddress这样的条件,然后采用新值,如何从Java应用XSLT转换?

谢谢。


1
好问题,+1。请查看我的答案,其中包含完整的XSLT解决方案以及一个最佳的基于Java的XSLT处理器文档链接。 - Dimitre Novatchev
“最好”是什么意思?最方便(最简单),最高性能,适用于大文件?XSLT和树模型(DOM)可能很方便,但也会使用大量内存并且相对较慢(例如)。 - StaxMan
Saxon几乎是最好的。它具有比DOM更小的内存模型,支持处理大文件的流式传输,具有出色的优化器,并支持XSLT 1、XSLT 2、XQuery、XML Schema,并支持一些新的草案标准。 - lavinio
你好,StaxMan。感谢你的问题。我认为处理这种情况最方便和最简单的方法是什么? - yart
@Dimitre Novatchev:感谢您的提醒。我接受了第一个答案,因为它清楚地说明了如何实现。我也喜欢您的答案,但我记得我花了一些时间阅读有关Saxonica的内容,仍然有疑问,但这已经是不同的话题了。谢谢您,Dimitre。我还会查看所有未被接受的答案。 - yart
2个回答

6
您可以使用标准的org.w3c.dom API获取DOM。然后使用标准的javax.xml.xpath API获取节点。最后使用javax.xml.transform API将其写回。类似于:
import java.io.File;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.xpath.*;
import org.w3c.dom.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        Document document = dbf.newDocumentBuilder().parse(new File("input.xml"));

        XPathFactory xpf = XPathFactory.newInstance();
        XPath xpath = xpf.newXPath();
        XPathExpression expression = xpath.compile("//A/B[C/E/text()=13]");

        Node b13Node = (Node) expression.evaluate(document, XPathConstants.NODE);
        b13Node.getParentNode().removeChild(b13Node);

        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer t = tf.newTransformer();
        t.transform(new DOMSource(document), new StreamResult(System.out));
    }
}

4

XSLT解决方案:

<xsl:stylesheet version="1.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output omit-xml-declaration="yes" indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:param name="pNewIpAddress" select="'192.68.0.1'"/>

  <xsl:template match="node()|@*">
    <xsl:copy>
       <xsl:apply-templates select="node()|@*"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="ipAddress/text()">
  <xsl:value-of select="$pNewIpAddress"/>
  </xsl:template>
</xsl:stylesheet>

当应用此转换于任何文档时,文档的所有节点都会被“原样”复制,除了任何ipAddress元素的文本节点子节点(无论此元素在文档中的位置如何)。后者将被替换为外部提供的参数$pNewIpAddress的值。

例如,如果对这个XML文档应用转换

<t>
    <a>
        <b>
          <ipAddress>127.0.0.1</ipAddress>
        </b>
        <c/>
    </a>
    <d/>
</t>
期望的、正确的结果已经生成:
<t>
   <a>
      <b>
         <ipAddress>192.68.0.1</ipAddress>
      </b>
      <c/>
   </a>
   <d/>
</t>

有许多基于Java的XSLT处理器,了解如何从Java中调用它们的正确方法是查看它们的文档。其中最好的XSLT处理器之一是Saxon,其文档可以在以下网址找到:

http://www.saxonica.com/documentation/documentation.xml


非常感谢您的回答。您知道我是否可以通过变量从Java代码传递新IP地址的值,例如transformer.transform(xml, xslt, variable),这样我就不需要直接在XSLT文件中指定它,因为该值是动态计算的? - yart
@yart:是的。请参阅此处的Saxon文档:http://www.saxonica.com/documentation/using-xsl/embedding.xml - Dimitre Novatchev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接