Java 递归地从XML中删除空节点

Java 递归地从XML中删除空节点,java,xml,xmlnode,Java,Xml,Xmlnode,我想从XML元素中删除空节点。 这个xml是由供应商生成的,我无法控制xml的生成。但是由于XML几乎没有空节点,我需要递归地删除这些空节点 这个xml是从OmeElement获取的,我使用[XMLUtils][1]从这个对象获取一个元素 示例XML <A> <B> <C> <C1> <C11>something</C11> <C12>something&l

我想从XML元素中删除空节点。 这个xml是由供应商生成的,我无法控制xml的生成。但是由于XML几乎没有空节点,我需要递归地删除这些空节点

这个xml是从OmeElement获取的,我使用[XMLUtils][1]从这个对象获取一个元素 示例XML

<A>
  <B>
    <C>
      <C1>
        <C11>something</C11>
        <C12>something</C12>
      </C1>
    </C>
    <D>
      <D1>
        <D11>
          <D111 operation="create">
            <Node>something else</Node>
          </D11>
        </D11>
      </D1>
      <D2>
        <D21>

        </D21>
      </D2>
    </D>
  </B>
</A> 
问候
Dheeraj Joshi

在DOM的顶级元素上使用
getTextContent()
。若方法返回空字符串或null,则可以删除此节点,因为此节点和所有子节点均为空。如果方法
getTextContent()
返回非空字符串,则对当前节点的每个子节点调用
getTextContent
,依此类推。

请参阅。

这是可行的,只需先创建一个“深入”的递归函数,然后在“备份树”的过程中删除空节点,这将产生删除D21和D2的效果

public static void main(String[] args) throws Exception {

    DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
    String input = "<A><B><C><C1><C11>something</C11><C12>something</C12></C1></C><D><D1><D11><D111 operation=\"create\"><Node>something else</Node></D111></D11></D1><D2><D21></D21></D2></D></B></A>";

    Document document = builder.parse(new InputSource(new StringReader(
            input)));

    removeNodes(document);

    Transformer transformer = TransformerFactory.newInstance()
            .newTransformer();
    transformer.setOutputProperty(OutputKeys.INDENT, "yes");
    StreamResult result = new StreamResult(new StringWriter());
    transformer.transform(new DOMSource(document), result);
    System.out.println(result.getWriter().toString());
}

public static void removeNodes(Node node) {
    NodeList list = node.getChildNodes();
    for (int i = 0; i < list.getLength(); i++) {
        removeNodes(list.item(i));
    }
    boolean emptyElement = node.getNodeType() == Node.ELEMENT_NODE
            && node.getChildNodes().getLength() == 0;
    boolean emptyText = node.getNodeType() == Node.TEXT_NODE
            && node.getNodeValue().trim().isEmpty();
    if (emptyElement || emptyText) {
        node.getParentNode().removeChild(node);
    }
}
publicstaticvoidmain(字符串[]args)引发异常{
DocumentBuilder=DocumentBuilderFactory.newInstance().newDocumentBuilder();
String input=“somethingsomethingsomethingsother”;
Document Document=builder.parse(新的InputSource(新的StringReader(
输入),;
移除节点(文件);
Transformer Transformer=TransformerFactory.newInstance()
.新变压器();
transformer.setOutputProperty(OutputKeys.INDENT,“是”);
StreamResult=新的StreamResult(新的StringWriter());
transform(新的DOMSource(文档)、result);
System.out.println(result.getWriter().toString());
}
公共静态void removeNodes(节点){
NodeList list=node.getChildNodes();
对于(int i=0;i
输出

<A>
<B>
<C>
<C1>
<C11>something</C11>
<C12>something</C12>
</C1>
</C>
<D>
<D1>
<D11>
<D111 operation="create">
<Node>something else</Node>
</D111>
</D11>
</D1>
</D>
</B>
</A>

某物
某物
别的

我没有足够的代表对@Adam的解决方案发表评论,但我遇到了一个问题,在删除节点后,该节点的最后一个同级节点被移动到索引零,导致它无法完全删除空元素。修复方法是使用一个列表来保存我们要递归调用以删除的所有节点

此外,还有一个bug删除了具有属性的空元素

这两个问题的解决办法:

public static void removeEmptyNodes(Node node) {

    NodeList list = node.getChildNodes();
    List<Node> nodesToRecursivelyCall = new LinkedList();

    for (int i = 0; i < list.getLength(); i++) {
        nodesToRecursivelyCall.add(list.item(i));
    }

    for(Node tempNode : nodesToRecursivelyCall) {
        removeEmptyNodes(tempNode);
    }

    boolean emptyElement = node.getNodeType() == Node.ELEMENT_NODE 
          && node.getChildNodes().getLength() == 0;
    boolean emptyText = node.getNodeType() == Node.TEXT_NODE 
          && node.getNodeValue().trim().isEmpty();

    if (emptyElement || emptyText) {
        if(!node.hasAttributes()) {
            node.getParentNode().removeChild(node);
        }
    }

}
公共静态void removemptynodes(节点){
NodeList list=node.getChildNodes();
List nodesToRecursivelyCall=新建LinkedList();
对于(int i=0;i
公共类RemoveEmptElement{
公共静态void main(字符串[]args){
ReadFile ReadFile=新的ReadFile();
字符串strXml=readFile.readFileFromPath(新文件(“sampleXml4.xml”);
removeMpRTElement元素empRTElement=新的removeMpRTElement();
DocumentBuilder dBuilder=null;
单据单据=空;
试一试{
dBuilder=DocumentBuilderFactory.newInstance().newDocumentBuilder();
doc=dBuilder.parse(新的ByteArrayInputStream(strXml.getBytes());
elementemptelement.getEmptyNodes(doc);
TransformerFactory tf=TransformerFactory.newInstance();
变压器变压器=tf.新变压器();
StreamResult=新的StreamResult(新的StringWriter());
转换(新的DOMSource(doc),结果);
System.out.println(result.getWriter().toString());
}捕获(例外e){
e、 printStackTrace();
}
}
私有无效getEmptyNodes(文档文档){
试一试{
XPathFactory=XPathFactory.newInstance();
XPath=factory.newXPath();
XPathExpression expr=xpath.compile(“//*[非(*)]”;
Object resultNS=expr.evaluate(doc,XPathConstants.NODESET);
节点列表节点=(节点列表)结果;
对于(int i=0;i<A>
<B>
<C>
<C1>
<C11>something</C11>
<C12>something</C12>
</C1>
</C>
<D>
<D1>
<D11>
<D111 operation="create">
<Node>something else</Node>
</D111>
</D11>
</D1>
</D>
</B>
</A>
public static void removeEmptyNodes(Node node) {

    NodeList list = node.getChildNodes();
    List<Node> nodesToRecursivelyCall = new LinkedList();

    for (int i = 0; i < list.getLength(); i++) {
        nodesToRecursivelyCall.add(list.item(i));
    }

    for(Node tempNode : nodesToRecursivelyCall) {
        removeEmptyNodes(tempNode);
    }

    boolean emptyElement = node.getNodeType() == Node.ELEMENT_NODE 
          && node.getChildNodes().getLength() == 0;
    boolean emptyText = node.getNodeType() == Node.TEXT_NODE 
          && node.getNodeValue().trim().isEmpty();

    if (emptyElement || emptyText) {
        if(!node.hasAttributes()) {
            node.getParentNode().removeChild(node);
        }
    }

}
public class RemoveEmprtElement {

public static void main(String[] args) {
    ReadFile readFile =new ReadFile();
    String strXml=readFile.readFileFromPath(new File("sampleXml4.xml"));
    RemoveEmprtElement elementEmprtElement=new RemoveEmprtElement();
    DocumentBuilder dBuilder = null;
    Document doc = null;
    try {
        dBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
        doc = dBuilder.parse(new ByteArrayInputStream(strXml.getBytes()));

        elementEmprtElement.getEmptyNodes(doc);
        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer trans = tf.newTransformer();
        StreamResult result = new StreamResult(new StringWriter());
        trans.transform(new DOMSource(doc), result);
        System.out.println(result.getWriter().toString());

    }catch(Exception e) {
        e.printStackTrace();
    }
}

private void getEmptyNodes(Document doc){

    try {
        XPathFactory factory = XPathFactory.newInstance();
        XPath xpath = factory.newXPath();
        XPathExpression expr = xpath.compile("//*[not(*)]");
        Object resultNS = expr.evaluate(doc, XPathConstants.NODESET);
        NodeList nodes = (NodeList) resultNS;
        for(int i =0 ; i < nodes.getLength() ; i++){
            Node node = nodes.item(i);
            boolean emptyElement = node.getNodeType() == Node.ELEMENT_NODE
                    && node.getChildNodes().getLength() == 0;
            boolean emptyText = node.getNodeType() == Node.TEXT_NODE
                    && node.getNodeValue().trim().isEmpty();

            if (emptyElement || emptyText) {
                xmlNodeRemove(doc,findPath(node));
                getEmptyNodes(doc);
            }
        } 
    }catch(Exception e) {
        e.printStackTrace();
    }

}

private void xmlNodeRemove(Document doc,String xmlNodeLocation){

    try {
        XPathFactory factory = XPathFactory.newInstance();
        XPath xpath = factory.newXPath();
        XPathExpression expr = xpath.compile(xmlNodeLocation);
        Object resultNS = expr.evaluate(doc, XPathConstants.NODESET);
        NodeList nodes = (NodeList) resultNS;
        Node node =nodes.item(0);
        if(node!=null && node.getParentNode()!=null && node.getParentNode().hasChildNodes()){
        node.getParentNode().removeChild(node);
        }
    }catch(Exception e) {
        e.printStackTrace();
    }
}

private String findPath(Node n) {
    String path="";
    if(n==null){
        return path;
    }else if(n.getNodeName().equals("#document")){
        return "";
    }
        else{
            path=n.getNodeName();
            path=findPath(n.getParentNode())+"/"+path;
        }
        return path;
    }

}
    Pattern emptyValueTag = Pattern.compile("\\s*<\\w+/>");
    Pattern emptyTagMultiLine = Pattern.compile("\\s*<\\w+>\n*\\s*</\\w+>");

    xml = emptyValueTag.matcher(xml).replaceAll("");

    while (xml.length() != (xml = emptyTagMultiLine.matcher(xml).replaceAll("")).length()) {
    }

    return xml;