2012-02-01 94 views
1

我有一個輸出XML,其中包含空元素和空元素,但具有屬性。刪除Java中的空XML元素

我檢查了一些舊帖子,這些帖子幫助我解決了一部分問題。

我用下面的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> 

但問題是,同時刪除與像

<CurrencyList> 
<Currency code="EURO"/> 
<Currency code="USD"/> 
</CurrencyList> 

任何屬性的子元素有一個想法如何解決這個問題的要素是什麼?

非常感謝

+0

解析xml並驗證子元素和屬性的每個元素不是您的選項嗎? – tartak 2012-02-01 14:33:32

+0

@CatalinCiobanu是的,它可能是 – achraf 2012-02-01 14:47:25

+0

以及你可以得到列表中的元素列表並要求大小......但我們的同胞Joop Eggen建議更好的(更好的)解決方案 - >遞歸! – tartak 2012-02-01 14:54:27

回答

1

這就像刪除空目錄:你必須做一個深度優先遞歸步行:如果所有子目錄被刪除,那麼可以考慮刪除當前目錄。

因此,刪除最好在Java中用遞歸完成。好處是,那個不需要副本。


代碼

根據要求,與XML API的工作是相當零碎,一些未經測試的代碼:

import java.io.*; 
import java.util.*; 
import javax.xml.parsers.*; 
import javax.xml.transform.*; 
import javax.xml.transform.dom.DOMSource; 
import javax.xml.transform.stream.StreamResult; 
import org.w3c.dom.*; 
import org.xml.sax.SAXException; 

public class XmlCleanup { 

    public static void main(String[] args) { 
     if (args.length == 0) { 
      args = new String[] { "/home/joop/Labortablo/test1.xml" }; 
     } 
     new XmlCleanup().process(args[0]); 
    } 

    public void process(String xmlPath) { 
     try { 
      // Read XML document: 
      DocumentBuilder builder = 
        DocumentBuilderFactory.newInstance().newDocumentBuilder(); 
      Document doc = builder.parse(new File(xmlPath)); 

      removeEmptyChildElements(doc.getDocumentElement()); 

      // Write XML document back: 
      TransformerFactory transformerFactory = TransformerFactory.newInstance(); 
      Transformer transformer = transformerFactory.newTransformer(); 
      DOMSource source = new DOMSource(doc); 
      StreamResult result = new StreamResult(new File(xmlPath 
        .replaceFirst("\\.xml$", "") + "-clean.xml")); 
      transformer.transform(source, result); 
     } catch (TransformerException ex) { 
      Logger.getLogger(XmlCleanup.class.getName()).log(Level.SEVERE, null, ex); 
     } catch (SAXException ex) { 
      Logger.getLogger(XmlCleanup.class.getName()).log(Level.SEVERE, null, ex); 
     } catch (IOException ex) { 
      Logger.getLogger(XmlCleanup.class.getName()).log(Level.SEVERE, null, ex); 
     } catch (ParserConfigurationException ex) { 
      Logger.getLogger(XmlCleanup.class.getName()).log(Level.SEVERE, null, ex); 
     } 
    } 

    private void removeEmptyChildElements(Element parentElement) { 
     List<Element> toRemove = new LinkedList<Element>(); 

     NodeList children = parentElement.getChildNodes(); 
     int childrenCount = children.getLength(); 
     for (int i = 0; i < childrenCount; ++i) { 
      Node child = children.item(i); 
      if (child.getNodeType() == Node.ELEMENT_NODE) { 
       Element childElement = (Element) child; 
       removeEmptyChildElements(childElement); 
       if (elementIsRedundant(childElement)) { 
        toRemove.add(childElement); 
       } 
      } 
     } 

     for (Element childElement: toRemove) { 
      parentElement.removeChild(childElement); 
     } 
     parentElement.normalize(); 
    } 

    private boolean elementIsRedundant(Element element) { 
     if (element.hasAttributes()) 
      return false; 
     if (!element.hasChildNodes()) 
      return true; 
     NodeList children = element.getChildNodes(); 
     int childrenCount = children.getLength(); 
     for (int i = 0; i < childrenCount; ++i) { 
      Node child = children.item(i); 
      String value = child.getNodeValue(); 
      if (value != null && !value.matches("\\s*")) { 
       return false; // Found non-whitespace text 
      } 
     } 
     return true; 
    } 
} 

它採用java.xml.transform所以你可以使用XSLT轉換太;更簡單一點就是使用javax.xml.stream.XMLOutputFactory

+0

對不起,我是JAVA XML處理的新手,我們該如何處理? – achraf 2012-02-01 14:59:55

+0

看看這裏,它可能是你的起點http://stackoverflow.com/questions/47026/recursive-function-for-an-xml-file-hierarchial-data – tartak 2012-02-01 15:04:28

0

我認爲你從身份轉換開始走在正確的軌道上。我建議保持身份模板不變,然後添加一個忽略空元素的更具體的模板。

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

對'normalize-space`的調用使該模板摺疊所有連續的空格,通常只用於縮進。比賽的第二部分然後排除所有具有屬性本身或具有屬性後代的元素。爲了進行調試,我讓模板在輸出中刪除元素時在輸出中創建註釋。

<xsl:template match="*[normalize-space(.) = '' and not(descendant-or-self::*/@*)]"> 
    <xsl:comment><xsl:value-of select="name(.)" /></xsl:comment> 
</xsl:template>