Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/351.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用Java删除XML文档上重复的节点标记_Java_Xml_Algorithm_Xml Parsing - Fatal编程技术网

使用Java删除XML文档上重复的节点标记

使用Java删除XML文档上重复的节点标记,java,xml,algorithm,xml-parsing,Java,Xml,Algorithm,Xml Parsing,我有以下xml文档: <?xml version="1.0" ?> <tag>text<b><b>bold</b> bold again</b><b><br/>the end </tag> text再次加粗结束 我需要删除重复的标签,但保留其内容,因此结果是: <?xml version="1.0" ?> <tag>text<b>bold

我有以下xml文档:

<?xml version="1.0" ?>
<tag>text<b><b>bold</b> bold again</b><b><br/>the end </tag>

text再次加粗
结束
我需要删除重复的标签,但保留其内容,因此结果是:

<?xml version="1.0" ?>
    <tag>text<b>bold bold again</b>the end </tag> 

textbold再次出现在末尾
我有以下代码:

import java.io.*;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import org.w3c.dom.Document;
import org.w3c.dom.*;
import java.util.Arrays;

import javax.xml.transform.*;
import javax.xml.transform.dom.*;
import javax.xml.transform.stream.*;


import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;


public class TakeDuplicatesXml{

    public static void main(String[] args){

        try{
            DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
            Document doc = docBuilder.parse("/Users/youruser/code/Exercises/file.xml");

            //get node list
            List<String> aux = new ArrayList<String>();
            removeDuplicate(doc.getDocumentElement(), aux);

            //print the new document out
            printXmlDocument(doc);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public static void printXmlDocument(Document doc){
        try{
            DOMSource domSource = new DOMSource(doc);
            StringWriter writer = new StringWriter();
            StreamResult result = new StreamResult(writer);
            TransformerFactory tf = TransformerFactory.newInstance();
            Transformer transformer = tf.newTransformer();
            transformer.transform(domSource, result);
            System.out.println("XML IN String format is: \n" + writer.toString());
        }catch (Exception ex) {
            ex.printStackTrace();
        }

    }
  //with recursion
    public static void removeDuplicate(Node node, List<String>  aux){

        System.out.println(node.getNodeName());
        //check if that node exists already
        if(aux.contains(node.getNodeName())){
            node.getParentNode().removeChild(node);
        }else{
            //add node name to aux list
            aux.add(node.getNodeName());
        }

        NodeList nodeList = node.getChildNodes();

        for (int i = 0; i < nodeList.getLength(); i++) {
            Node currentNode = nodeList.item(i);
            if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
                //calls this method for all the children which is Element
                removeDuplicate(currentNode, aux);
            }
        }
    }
}
import java.io.*;
导入java.util.ArrayList;
导入java.util.LinkedList;
导入java.util.List;
导入org.w3c.dom.Document;
导入org.w3c.dom.*;
导入java.util.array;
导入javax.xml.transform.*;
导入javax.xml.transform.dom.*;
导入javax.xml.transform.stream.*;
导入javax.xml.parsers.DocumentBuilderFactory;
导入javax.xml.parsers.DocumentBuilder;
导入org.xml.sax.SAXException;
导入org.xml.sax.SAXParseException;
公共类XML{
公共静态void main(字符串[]args){
试一试{
DocumentBuilderFactory docFactory=DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder=docFactory.newDocumentBuilder();
documentdoc=docBuilder.parse(“/Users/youruser/code/Exercises/file.xml”);
//获取节点列表
List aux=新阵列列表();
移除副本(doc.getDocumentElement(),aux);
//打印新文档
打印文档(doc);
}捕获(例外情况除外){
例如printStackTrace();
}
}
公共静态无效printXmlDocument(文档文档){
试一试{
DOMSource DOMSource=新的DOMSource(doc);
StringWriter编写器=新的StringWriter();
StreamResult结果=新的StreamResult(writer);
TransformerFactory tf=TransformerFactory.newInstance();
变压器=tf.新变压器();
transformer.transform(domSource,result);
System.out.println(“字符串格式的XML是:\n”+writer.toString());
}捕获(例外情况除外){
例如printStackTrace();
}
}
//递归
移除的公共静态无效副本(节点,列表辅助){
System.out.println(node.getNodeName());
//检查该节点是否已经存在
if(aux.contains(node.getNodeName())){
node.getParentNode().removeChild(节点);
}否则{
//将节点名称添加到辅助列表
add(node.getNodeName());
}
NodeList NodeList=node.getChildNodes();
for(int i=0;i
但结果并不是我想要的,因为它将节点与其内容(粗体字不见了):

文本再次粗体显示
结束
我怎样才能修好它?如何使其性能更高?

bold
又是
bold的子项。
如果执行
node.getParentNode().removeChild(node)
,它就不存在了。将子对象的值添加到父对象的值,然后再将其删除

查询XML的另一种可能性是XPath。见:

  • :“子体轴包含上下文节点的子体;子体是子体或子体的子体,依此类推”
  • :“函数名()返回元素的名称”

不知道这是否更有效。但我想它是-支持自写递归。

所以我找到了解决方案。我仍然不确定这是否是最佳解决方案,但效果良好,并将内容按正确顺序排列:

//with recursion
    public static void removeDuplicate(Node node, List<String>  aux){


        //check if that node exists already
        if(aux.contains(node.getNodeName())){

            Node parentNode = node.getParentNode();
            String value = parentNode.getTextContent();

            parentNode.removeChild(node);
            parentNode.setTextContent(value);
        }else{
            //add node name to aux list
            aux.add(node.getNodeName());
        }

        NodeList nodeList = node.getChildNodes();

        for (int i = 0; i < nodeList.getLength(); i++) {
            Node currentNode = nodeList.item(i);
            if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
                //calls this method for all the children which is Element
                removeDuplicate(currentNode, aux);
            }
        }
//使用递归
移除的公共静态无效副本(节点,列表辅助){
//检查该节点是否已经存在
if(aux.contains(node.getNodeName())){
Node parentNode=Node.getParentNode();
字符串值=parentNode.getTextContent();
parentNode.removeChild(节点);
parentNode.setTextContent(值);
}否则{
//将节点名称添加到辅助列表
add(node.getNodeName());
}
NodeList NodeList=node.getChildNodes();
for(int i=0;i
这类问题最好使用简单的XSLT转换来解决。您需要一个具有两个规则的样式表:一个复制所有内容不变的标识规则

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

@GeroldBroser这是有道理的,但是如果节点在节点内其余内容之前还是之后,我现在怎么办呢?我不知道使用DOM解析器是否可以做到这一点。使用SAX解析器,您可以按顺序接收文档项的事件。请参阅,还有一个可以读取和写入的事件。
<xsl:template match="*">
  <xsl:copy>
    <xsl:copy-of select="@*"/>
    <xsl:apply-templates select="child::node()"/>
  </xsl:copy>
</xsl:template>
<xsl:template match="b/b">
  <xsl:apply-templates/>
</xsl:template>
<xsl:stylesheet version="1.0" xmlns:xsl="http:www.w3.org/1999/XSL/Transform">

.. template rules go here ...

</xsl:stylesheet>
public static void main(String[] args){

    try{
        TransformerFactory tFactory = TransformerFactory.newInstance();
        Templates t = tFactory.newTemplates(new File(... stylesheet file ....));
        Source doc = new StreamSource(
          new File("/Users/youruser/code/Exercises/file.xml"));
        t.newTransformer().transform(doc, new StreamResult(System.out));
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}