使用Java删除XML文档上重复的节点标记
我有以下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 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();
}
}