【问题标题】:Java: how to wrap all elements with <sometag> in org.w3c.dom?Java:如何在 org.w3c.dom 中用 <sometag> 包装所有元素?
【发布时间】:2011-07-21 00:59:32
【问题描述】:

我的目标是用标签&lt;something style="background-color:red"&gt;&lt;/something&gt; 包装当前org.w3c.dom.Document 上的每一个dom 元素(Node.ELEMENT_NODE)。

public static void main(String[] args){
    org.w3c.dom.DOMDocument doc;
    paintAllNodes(doc, 0);
}

public static void paintAllNodes(Node node, int level) {
    // Process node

    // If there are any children, visit each one
    NodeList list = node.getChildNodes();
    for (int i=0; i<list.getLength(); i++) {
        // Get child node
        Node childNode = list.item(i);        

        // Visit child node
        paintAllNodes(childNode, level+1);
    }
}

【问题讨论】:

  • 抱歉,您是要将属性style 添加到所有元素还是更改元素的名称?
  • 我想将&lt;something style="background-color:red'"&gt;&lt;/something&gt; 包裹在所有元素周围。
  • 好问题,+1。有关此问题的最短和最简单的解决方案,请参阅我的答案。请记住将 XSLT 作为任何 XML 转换的 工具添加到您的工具集中。 :)
  • 为什么不将您的赏金奖励给您最喜欢的答案?有什么理由吗? :-)

标签: java xml xslt dom xpath


【解决方案1】:

对于任何给定的节点“节点”,它来自类似这样的文档“文档”应该可以工作。

Node parent = node.getParent();
Node nextSibling = node.getNextSibling();

parent.removeChild(node);

Element something = document.createElement("something");
NamedNodeMap atts = something.getAttributes();
Attr att = document.createAttribute("style");
att.setNodeValue("background-color:red;");
atts.setNamedItem(att);
something.addChild(node);
parent.insertBefore(something, nextSibling);

【讨论】:

    【解决方案2】:

    这会将每个Node.ELEMENT_NODE 包装在带有&lt;something&gt; 标签的org.w3c.dom.Document 中:

    public static void paintAllNodes(Document doc) {
        // build list of Node.ELEMENT_NODE to process
        List<Node> nodes = new ArrayList<Node>();
        NodeList list = doc.getElementsByTagName("*");
        for (int i = 0; i < list.getLength(); i++) {
            Node node = list.item(i);
            if (node.getNodeType() == Node.ELEMENT_NODE) {
                nodes.add(node);
            }
        }
    
        // iterate through each node and wrap with <something> tag
        for (Node node : nodes) {
            // remember the next sibling for inserting at end
            Node nextSibling = node.getNextSibling();
    
            // remember the parent and remove this node from it
            Node parent = node.getParentNode();
            parent.removeChild(node);
    
            // create <something> element and attach node
            Element element = doc.createElement("something");
            NamedNodeMap attributes = element.getAttributes();
            Attr attr = doc.createAttribute("style");
            attr.setNodeValue("background-color:red");
            attributes.setNamedItem(attr);
            element.appendChild(node);
    
            // insert new element where the node was 
            parent.insertBefore(element, nextSibling);
        }
    }
    

    如果您想排除任何节点,只需在第一个 for 循环中将它们过滤掉即可。

    【讨论】:

    • 这只是返回一个空白文档。它会清除加载的 DOM 文档。
    • 你能举一个你正在处理的文件的例子吗?我对此进行了测试,上面的代码工作正常:&lt;html&gt;&lt;body&gt;&lt;h1&gt;Test Header&lt;/h1&gt;&lt;p&gt;Test body&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;
    • +1 用于使用doc.getElementsByTagName("*"); 以避免递归。
    • 我已经测试过了,它有效!我还使用替代解决方案添加了我的答案。
    【解决方案3】:

    我想给你一个递归解决方案,它利用Node#replaceChild 方法将节点替换为新标签:

    public static void paintAllNodes(Node node) {
        if (node.getNodeType() == Node.ELEMENT_NODE) {
            Element somethingElement = node.getOwnerDocument().createElement("something");
            somethingElement.setAttribute("style", "background-color:red");
            node.getParentNode().replaceChild(somethingElement, node);
            somethingElement.appendChild(node);
            NodeList nodeList = node.getChildNodes();
            for (int i = 0; i < nodeList.getLength(); i++) {
                paintAllNodes(nodeList.item(i));
            }
        }
    }
    

    这是我的主要内容:

    public static void main(String[] args) throws SAXException, IOException,
            ParserConfigurationException, TransformerException {
    
        DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
        DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
        Document document = docBuilder.parse(new File("document.xml"));
        paintAllNodes(document.getDocumentElement());
    
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        DOMSource source = new DOMSource(document);
        StreamResult result = new StreamResult(System.out);
        transformer.transform(source, result);
    }
    

    我已经用这个 xml 对其进行了测试:

    <html>
        <head>
            <title>title</title>
        </head>
        <body>
        <h1>title</h1>
        <div>test</div>
        </body>
    </html>
    

    我的 main 已经打印出这个新的 xml,这似乎是你想要的:

    <?xml version="1.0" encoding="UTF-8"?><something style="background-color:red"><html>
        <something style="background-color:red"><head>
            <something style="background-color:red"><title>title</title></something>
        </head></something>
        <something style="background-color:red"><body>
        <something style="background-color:red"><h1>title</h1></something>
        <something style="background-color:red"><div>test</div></something>
        </body></something>
    </html></something>
    

    希望这会有所帮助。

    【讨论】:

    • 我在`Element somethingElement = node.getOwnerDocument().createElement("something");`得到nullexception;`
    • 你用过我的主要方法吗?第一次你必须传递给paintAllNodesdocument.getDocumentElement()paintAllNodes(document.getDocumentElement());。你做到了吗?
    • 我已经更新了这个问题。我用过你的代码。
    • 我已经编辑了我的答案,我已经更改了几行代码以使其更可靠。如果节点是 Document 或 DocumentType,getOwnerDocument() 方法将返回 null。现在您还可以将整个Document 传递给paintAllNodes 方法。可以试试吗?
    • 是的,我已经运行了新代码,但它似乎不起作用。我尝试在 for 括号内打印出一些文本,但没有打印出来。
    【解决方案4】:

    解决此类问题(对于任何 XML 转换)的最简单方法之一是使用 XSLT

    这个 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:template match="*">
     <something style="background-color:red">
       <xsl:copy>
        <xsl:copy-of select="@*"/>
        <xsl:apply-templates select="node()"/>
       </xsl:copy>
      </something>
     </xsl:template>
    </xsl:stylesheet>
    

    应用于任何 XML 文档时,例如这个:

    <nums>
      <num>01</num>
      <num>02</num>
      <num>03</num>
      <num>04</num>
      <num>05</num>
      <num>06</num>
      <num>07</num>
      <num>08</num>
      <num>09</num>
      <num>10</num>
    </nums>
    

    产生想要的正确结果

    <something style="background-color:red">
       <nums>
          <something style="background-color:red">
             <num>01</num>
          </something>
          <something style="background-color:red">
             <num>02</num>
          </something>
          <something style="background-color:red">
             <num>03</num>
          </something>
          <something style="background-color:red">
             <num>04</num>
          </something>
          <something style="background-color:red">
             <num>05</num>
          </something>
          <something style="background-color:red">
             <num>06</num>
          </something>
          <something style="background-color:red">
             <num>07</num>
          </something>
          <something style="background-color:red">
             <num>08</num>
          </something>
          <something style="background-color:red">
             <num>09</num>
          </something>
          <something style="background-color:red">
             <num>10</num>
          </something>
       </nums>
    </something>
    

    注意:留给读者作为练习如何在 Java 代码中启动 XSLT 转换 :)

    【讨论】:

    • @Alejandro:谢谢,如果 XSLT 答案能得到这个问题的赏金,那就太好了——有些人需要了解哪个是用于转换 XML 的最佳工具 :)
    【解决方案5】:

    作为非回答 ;-) 我建议使用 CSS...something {background:red} 显然,这只有在您仍然使用 CSS 时才有意义。

    【讨论】:

      猜你喜欢
      • 2012-04-29
      • 2011-07-13
      • 2011-05-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-16
      • 2011-06-19
      • 1970-01-01
      相关资源
      最近更新 更多