2012-01-26 5 views
1

Скажем, у меня есть дом узел так:преобразование узла дом рекурсивно с помощью Java

org.w3c.dom.Element узла:

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

Чтобы преобразовать идентификатор атрибута Я хотел бы сделать следующее в моем 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> 

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

Спасибо, Sony

ответ

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

Я работаю на Dóm узлах. Извините, что раньше не было ясно. Будет ли ваша оценка работать и на dom-узлах? – sony

+0

В этом примере используется W3C DOM, объекты из пакета 'org.w3c.dom'. Я добавил импорт. – laz

+0

Преобразование работает. Спасибо! Но, когда я пытаюсь сделать следующее: public void transform (Element parent, Element child) { Документ parent_doc = parent.getOwnerDocument(); child = (Element) parent_doc.importNode (child, true); /* преобразовать ребенка как предложено */ parent.appendChild (child);} Я получаю сообщение об ошибке в последней строке - 0: Неожиданное исключение: org.w3c.dom.DOMException: WRONG_DOCUMENT_ERR: Узел используется в другом документе чем тот, который его создал. org.w3c.dom.DOMException: WRONG_DOCUMENT_ERR: Узел используется в другом документе, кроме того, который его создал. – sony

0

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