2009-11-06 58 views
5

從(任意)XML結構的Java刪除空的XML標記

<xml> 
    <field1>bla</field1> 
    <field2></field2> 
    <field3/> 
    <structure1> 
     <field4>bla</field4> 
     <field5></field5> 
    </structure1> 
</xml> 

應該變成刪除空標籤;

<xml> 
    <field1>bla</field1> 
    <structure1> 
     <field4>bla</field4> 
    </structure1> 
</xml> 
+1

目前您解析XML爲數據結構以任何特定的方式(JDOM等)?還是你從頭開始? –

+3

示例XML中的輸入錯誤:structure1未正確關閉 – Jonik

回答

8

我想知道是否很容易做到這一點與XOM圖書館,並試了一下。

原來是相當簡單:

import nu.xom.*; 

import java.io.File; 
import java.io.IOException; 

public class RemoveEmptyTags { 

    public static void main(String[] args) throws IOException, ParsingException { 
     Document document = new Builder().build(new File("original.xml")); 
     handleNode(document.getRootElement()); 
     System.out.println(document.toXML()); // empty elements now removed 
    } 

    private static void handleNode(Node node) { 
     if (node.getChildCount() == 0 && "".equals(node.getValue())) { 
      node.getParent().removeChild(node); 
      return; 
     } 
     // recurse the children 
     for (int i = 0; i < node.getChildCount(); i++) { 
      handleNode(node.getChild(i)); 
     } 
    } 
} 

這將可能無法正確處理所有角落的情況下,像一個完全空白的文檔。以及如何處理那些空的但有屬性的元素?

如果您想保存帶有屬性的XML標籤,我們可以在方法「handleNode」下面的檢查補充:

... && ((Element) node).getAttributeCount() == 0)) 

而且,如果XML有兩個或兩個以上的空標籤,此起彼伏;這種遞歸方法不會刪除所有空標籤!

(這個答案是我XOM的評價作爲潛在replacement to dom4j的一部分。)

+0

謝謝,我將使用此 – Raymond

0

使用XSLT,您可以轉換您的XML以忽略空標籤並重新編寫文檔。

8

這XSLT樣式表應該做你要找的內容:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:template match="@*|node()"> 
    <xsl:if test=". != '' or ./@* != ''"> 
     <xsl:copy> 
     <xsl:apply-templates select="@*|node()"/> 
     </xsl:copy> 
    </xsl:if> 
    </xsl:template> 
</xsl:stylesheet> 

應該保留它們是空的,但具有不屬性的元素。如果你不希望這種行爲再改:

<xsl:if test=". != '' or ./@* != ''">

要:<xsl:if test=". != ''">

如果你想知道如何在Java應用XSLT,應該有很多教程在那裏對Interwebs 。祝你好運!

+0

XSLT解決方案的輸入 –

3

作爲一個邊注:標記的不同狀態實際上有寓意:

  • 開放 - 關閉標籤:元素存在並且其值是空字符串
  • 單標籤:的元件存在,但該值nullnil
  • 缺少標籤:的元素不存在

因此,通過去除空開閉式標籤和單標籤,你跟團缺少的標籤把它們合併,從而丟失信息。

+0

非常好的一點 - 有些時候刪除空值或空值的標籤是有用的,但有同時這樣做可能會對應用程序造成不利影響。 –

+0

爲了我的目的,這是無關緊要的 – Raymond

1

如果xml以字符串形式提供;正則表達式可以用來過濾掉空的元素:

<(\\w+)></\\1>|<\\w+/> 

這會找到空的元素。

data.replaceAll(re, "") 

數據在這種情況下是一個變量,用於存放您的xml字符串。
並不是說這是最好的解決方案,但它是可能的...

1

我需要添加帶空間和縮進元素克里斯的r答案,否則封裝塊,新空的,不會被刪除:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:strip-space elements="*"/> 
    <xsl:output indent="yes" /> 
    <xsl:template match="@*|node()"> 
    <xsl:if test=". != '' or ./@* != ''"> 
     <xsl:copy> 
     <xsl:apply-templates select="@*|node()"/> 
     </xsl:copy> 
    </xsl:if> 
    </xsl:template> 
</xsl:stylesheet> 
0

要刪除所有空標籤,即使他們是一個接一個,一個不可能性的解決方案是:

private void removeEmptyTags(Document document) { 
    List<Node> listNode = new ArrayList<Node>(); 
    findListEmptyTags(document.getRootElement(), listNode); 
    if (listNode.size() == 0) 
     return; 

    for (Node node : listNode) { 
     node.getParent().removeChild(node); 
    } 
    removeEmptyTags(document); 
} 

private void findListEmptyTags(Node node, List<Node> listNode) { 

    if (node != null && node.getChildCount() == 0 && "".equals(node.getValue()) && ((Element) node).getAttributeCount() == 0) { 
     listNode.add(node); 
     return; 
    } 
    // recurse the children 
    for (int i = 0; i < node.getChildCount(); i++) { 
     findListEmptyTags(node.getChild(i), listNode); 
    } 
} 
2

我測試Jonik的和Marco的示例代碼。但那些不是我想要的。所以我修改了他們的源代碼和下面的代碼,對我來說很好。我已經在我的項目中調整了這些代碼。如果你願意,請測試它。

public String removeEmptyNode(String xml){ 
    String cleanedXml = null; 
    try{ 
     xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" + xml; 
     InputStream input = new ByteArrayInputStream(xml.getBytes("UTF-8")); 
     Document document = new Builder().build(input); 
     removeEmptyNode(document.getRootElement()); 
     cleanedXml = document.toXML(); 
    }catch(Exception e){ 
     e.printStackTrace(); 
    } 
    return cleanedXml; 
} 

private static void removeEmptyNode(Node node) { 
    if(node.getChildCount()!=0){ 
     int count = node.getChildCount(); 
     for (int i = count-1; i >= 0 ; i--) { 
      removeEmptyNode(node.getChild(i)); 
     } 
    } 

    doCheck(node); 
} 

private static void doCheck(Node node){ 
    if(node.getChildCount() == 0 && "".equals(node.getValue().trim())) { 
     try{node.getParent().removeChild(node);}catch(Exception e){} 
    }  
} 
0
public static void main(String[] args) { 

    final String regex1 = "<([a-zA-Z0-9-\\_]*)[^>]*/>"; 
    final String regex2 = "<([a-zA-Z0-9-\\_]*)[^>]*>\\s*</\\1>"; 

    String xmlString = "<xml><field1>bla</field1><field2></field2><field3/><structure1><field4><field50><field50/></field50></field4><field5></field5></structure1></xml>"; 
    System.out.println(xmlString); 

    final Pattern pattern1 = Pattern.compile(regex1); 
    final Pattern pattern2 = Pattern.compile(regex2); 

    Matcher matcher1; 
    Matcher matcher2; 
    do { 
     xmlString = xmlString.replaceAll(regex1, "").replaceAll(regex2, ""); 
     matcher1 = pattern1.matcher(xmlString); 
     matcher2 = pattern2.matcher(xmlString); 
    } while (matcher1.find() || matcher2.find()); 

    System.out.println(xmlString); 
} 

控制檯:

<xml> 
    <field1>bla</field1> 
    <field2></field2> 
    <field3/> 
    <structure1> 
     <field4> 
      <field50> 
       <field60/> 
      </field50> 
     </field4> 
     <field5></field5> 
    </structure1> 
</xml> 

<xml> 
    <field1>bla</field1> 
</xml> 

Online demo here