使用Java递归地转换dom节点

时间:2012-01-26 01:02:59

标签: java dom dom-traversal

说我有一个像这样的dom节点:

org.w3c.dom.Element node:

<node id="101">
  <node id="102">
    <node id="103" />
  </node>
  <node id="104">
    <node id="103" />
  </node>
</node>

要转换id属性,我将在我的Java代码中执行以下操作:

String nodeId = node.getAttribute("id");
String newNodeId = "prefix/" + nodeId;
node.getAttributeNode("id").setValue(newNodeId);

然后将上述节点转换为:

<node id="prefix/101">
  <node id="102">
    <node id="103" />
  </node>
  <node id="104">
    <node id="103" />
  </node>
</node>

但是,我想以递归方式修改所有子节点。预期的转换节点是:

<node id="prefix/101">
  <node id="prefix/102">
    <node id="prefix'103" />
  </node>
  <node id="prefix/104">
    <node id="prefix/103" />
  </node>
</node>

我可以遍历子节点,但是节点可能有多个级别的子节点。在这种情况下,根有两个子级别。但是,如果有更多的子级别,那么循环通过每个级别的子节点似乎有点尴尬。是否有更直接的方法来完成这项任务?

谢谢, 索尼

2 个答案:

答案 0 :(得分:2)

您可以使用XPath获取要修改的所有节点的列表:

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

...

final String xml = "<node id=\"101\"><node id=\"102\"><node id=\"103\" /></node><node id=\"104\"><node id=\"103\" /></node></node>";
final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
final DocumentBuilder db = dbf.newDocumentBuilder();
final Document doc = db.parse(new InputSource(new StringReader(xml)));
final XPathFactory xpathFactory = XPathFactory.newInstance();
final XPath xpath = xpathFactory.newXPath();
final NodeList nodes = (NodeList) xpath.compile("//node[@id]").evaluate(doc, XPathConstants.NODESET);
for (int nodeNumber = 0; nodeNumber < nodes.getLength(); ++nodeNumber) {
    final Element node = (Element) nodes.item(nodeNumber);
    final String nodeId = node.getAttribute("id");
    final String newNodeId = "prefix/" + nodeId;
    node.getAttributeNode("id").setValue(newNodeId);
}

该文件现在包括:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<node id="prefix/101">
    <node id="prefix/102">
        <node id="prefix/103" />
    </node>
    <node id="prefix/104">
        <node id="prefix/103" />
    </node>
</node>

答案 1 :(得分:0)

如果附加到id属性的前缀值是常量,则可以使用XSLT。 (这不是你需要的确切代码......只是我头顶的一个例子)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="node">
    <xsl:element name="node">
      <xsl:attribute name="id">
       <xsl:value-of select="concat('prefix/', @id)" />
      </xsl:attribute>

      <xsl:apply-templates/>
    <xsl:element>
  </xsl:template>
</xsl:stylesheet>

这将导致更简单的代码,但您必须加载XSLT解释器(如xalan)才能执行转换。如果您还没有使用XSLT,这可能是也可能不是最佳方法,但是使用Java代码直接操作DOM结构的另一种方法。