2009-11-06 21 views
5

Sto cercando un semplice frammento di Java per rimuovere i tag vuoti da una (qualsiasi) struttura XMLJava Rimuovere vuoti tag XML

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

dovrebbe trasformarsi in;

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

Sono attualmente l'analisi del codice XML in strutture di dati in qualche modo particolare (JDOM, ecc)? O stai partendo da zero? –

+3

Typo in XML XML: structure1 non è chiuso correttamente – Jonik

risposta

8

Mi chiedevo se sarebbe stato facile farlo con la libreria XOM e provarlo.

si è rivelato essere abbastanza facile:

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)); 
     } 
    } 
} 

Questo probabilmente non in grado di gestire tutti i casi d'angolo correttamente, come un documento completamente vuoto. E cosa fare degli elementi che sono altrimenti vuoti ma hanno attributi?

Se si desidera salvare i tag XML con attributi, possiamo aggiungere nel metodo 'handleNode' il seguente controllo:

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

Inoltre, se l'XML ha due o più tag vuoti, uno dopo l'altro; questo metodo ricorsivo non rimuove tutti i tag vuoti!

(Questa risposta è parte della mia valutazione di XOM come un potenziale replacement to dom4j.)

+0

Grazie, userò questo – Raymond

0

Con XSLT è possibile trasformare il codice XML per ignorare i tag vuoti e riscrivere il documento.

8

Questo foglio di stile XSLT dovrebbe fare quello che stai cercando:

<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> 

Dovrebbe anche conservare elementi che sono vuoti, ma hanno gli attributi che non sono. Se non si desidera che questo comportamento poi cambiare:

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

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

Se volete sapere come applicare XSLT in Java, ci dovrebbe essere un sacco di tutorial là fuori sull'interwebs . In bocca al lupo!

+0

+1 per soluzione XSLT –

3

Come nota a margine: i diversi stati di un tag in realtà hanno un significato: Tag

  • aperto-chiuso : l'elemento esiste e il suo valore è una stringa vuota
  • singolo-Tag: l'elemento esiste, ma il valore è null o nil
  • mancante Tag: L'elemento non esiste

Quindi, rimuovendo i tag aperto-chiuso vuoti e single-tag, il gioco è loro fusione con il gruppo di tag mancanti e quindi perdere le informazioni.

+0

Ottimo punto: ci sono momenti in cui è utile rimuovere tag il cui valore è vuoto o nullo, ma ci sono anche i tempi in cui ciò potrebbe potenzialmente essere dannoso per l'applicazione. –

+0

Per il mio scopo, questo è irrilevante – Raymond

1

Se xml viene inviato come stringa; regex può essere utilizzato per filtrare gli elementi vuoti:

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

Ciò troverà elementi vuoti.

data.replaceAll(re, "") 

dati in questo caso una variabile contenente la stringa xml.
Non dicendo che questo sarebbe la migliore delle soluzioni, ma è possibile ...

1

avevo bisogno di aggiungere strip-spazio e gli elementi di rientro per la risposta di Chris R, altrimenti allegando blocchi, di recente vuoto, non vengono rimossi:

<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

Per rimuovere tutti i tag vuoti, anche se sono uno dopo l'altro, una soluzione possibile è:

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

ho provato codici di esempio di Jonik e Marco di. Ma quelli non sono esattamente quello che voglio. Così ho modificato la loro fonte e sotto il codice funziona bene per me. Ho già modificato questo codice nel mio progetto. per favore testalo, se vuoi

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); 
} 

Console:

<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

Problemi correlati