рекурсивно преобразовать узел dom с помощью Java

Скажем, у меня есть такой узел dom:

Узел org.w3c.dom.Element:

<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>

Я мог бы перебирать дочерние узлы, но тогда узел может иметь несколько уровней дочерних элементов. В этом случае корень имеет два подуровня. Но если подуровней больше, то цикл по дочерним узлам каждого уровня кажется немного неудобным. Есть ли более прямой подход к решению этой задачи?

Спасибо, Сони


person sony    schedule 26.01.2012    source источник


Ответы (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>
person laz    schedule 26.01.2012
comment
Я работаю над узлами dom. Извините за неясность ранее. Будет ли ваш подход работать и для узлов dom? - person sony; 26.01.2012
comment
В этом примере используется W3C DOM, объекты взяты из пакета org.w3c.dom. Я добавил импорт. - person laz; 26.01.2012
comment
Трансформация работает. Благодарю вас! Но когда я пытаюсь сделать следующее: public void transform (родительский элемент, дочерний элемент) { Document parent_doc = parent.getOwnerDocument(); дочерний = (Элемент)parent_doc.importNode(дочерний, правда); /* преобразовать дочерний элемент, как было предложено */ parent.appendChild(child);} Я получаю сообщение об ошибке в последней строке - 0: Неожиданное исключение: org.w3c.dom.DOMException: WRONG_DOCUMENT_ERR: Узел используется в документе, отличном от тот, кто его создал. org.w3c.dom.DOMException: WRONG_DOCUMENT_ERR: узел используется в документе, отличном от того, который его создал. - person sony; 27.01.2012
comment
Поскольку это другой вопрос, я создал новую тему. См.: stackoverflow.com/questions/9027230 /. Я надеялся, что ты поможешь. Спасибо - person sony; 27.01.2012

Если значение префикса, которое вы добавляете к атрибуту 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, это может быть или не быть лучшим подходом, но это еще одна альтернатива непосредственному управлению структурой DOM с помощью кода Java.

person Michael    schedule 26.01.2012