web-dev-qa-db-fra.com

Comment supprimer des lignes vides supplémentaires d'un fichier XML?

En bref; J'ai beaucoup de lignes vides générées dans un fichier XML, et je cherche un moyen de les supprimer comme moyen d’appuyer le fichier. Comment puis je faire ça ?

Pour une explication détaillée J'ai actuellement ce fichier XML:

<recent>
  <paths>
    <path>path1</path>
    <path>path2</path>
    <path>path3</path>
    <path>path4</path>
  </paths>
</recent>

Et j'utilise ce code Java pour supprimer toutes les balises et en ajouter de nouvelles:

public void savePaths( String recentFilePath ) {
    ArrayList<String> newPaths = getNewRecentPaths();
    Document recentDomObject = getXMLFile( recentFilePath );  // Get the <recent> element.
    NodeList pathNodes = recentDomObject.getElementsByTagName( "path" );   // Get all <path> nodes.

    //1. Remove all old path nodes :
        for ( int i = pathNodes.getLength() - 1; i >= 0; i-- ) { 
            Element pathNode = (Element)pathNodes.item( i );
            pathNode.getParentNode().removeChild( pathNode );
        }

    //2. Save all new paths :
        Element pathsElement = (Element)recentDomObject.getElementsByTagName( "paths" ).item( 0 );   // Get the first <paths> node.

        for( String newPath: newPaths ) {
            Element newPathElement = recentDomObject.createElement( "path" );
            newPathElement.setTextContent( newPath );
            pathsElement.appendChild( newPathElement );
        }

    //3. Save the XML changes :
        saveXMLFile( recentFilePath, recentDomObject ); 
}

Après avoir exécuté cette méthode un certain nombre de fois, j'obtiens un fichier XML avec les bons résultats, mais avec beaucoup de lignes vides après la balise "path" et avant la première balise "path", comme ceci:

<recent>
  <paths>





    <path>path5</path>
    <path>path6</path>
    <path>path7</path>
  </paths>
</recent>

Quelqu'un sait comment résoudre ce problème?

------------------------------------------- Edit: Ajouter le getXMLFile (...), saveXMLFile (...) code.

public Document getXMLFile( String filePath ) { 
    File xmlFile = new File( filePath );

    try {
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = dbf.newDocumentBuilder();
        Document domObject = db.parse( xmlFile );
        domObject.getDocumentElement().normalize();

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

    return null;
}

public void saveXMLFile( String filePath, Document domObject ) {
    File xmlOutputFile = null;
    FileOutputStream fos = null;

    try {
        xmlOutputFile = new File( filePath );
        fos = new FileOutputStream( xmlOutputFile );
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        transformer.setOutputProperty( OutputKeys.INDENT, "yes" );
        transformer.setOutputProperty( "{http://xml.Apache.org/xslt}indent-amount", "2" );
        DOMSource xmlSource = new DOMSource( domObject );
        StreamResult xmlResult = new StreamResult( fos );
        transformer.transform( xmlSource, xmlResult );  // Save the XML file.
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (TransformerConfigurationException e) {
        e.printStackTrace();
    } catch (TransformerException e) {
        e.printStackTrace();
    } finally {
        if (fos != null)
            try {
                fos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
    }
}
11
Brad

J'ai pu résoudre ce problème en utilisant ce code après avoir supprimé tous les anciens noeuds "path":

while( pathsElement.hasChildNodes() )
    pathsElement.removeChild( pathsElement.getFirstChild() );

Cela supprimera tous les espaces vides générés dans le fichier XML.

Un merci spécial à MadProgrammer pour les commentaires sur le lien utile mentionné ci-dessus.

3
Brad

Tout d'abord, expliquez pourquoi cela se produit - ce qui est peut-être un peu compliqué, car vous n'avez pas inclus le code utilisé pour charger le fichier XML dans un objet DOM.

Lorsque vous lisez un document XML à partir d'un fichier, les espaces entre les balises constituent en réalité des nœuds DOM valides, conformément à la spécification DOM. Par conséquent, l'analyseur XML traite chaque séquence d'espaces blancs comme des noeuds DOM (de type TEXT);

Pour m'en débarrasser, il y a trois approches auxquelles je peux penser:

  • Associez le XML à un schéma, puis utilisez setValidating(true) avec setIgnoringElementContentWhitespace(true) sur DocumentBuilderFactory.

    (Remarque: setIgnoringElementContentWhitespace ne fonctionnera que si l'analyseur est en mode de validation, c'est pourquoi vous devez utiliser setValidating(true))

  • Ecrivez un fichier XSL pour traiter tous les nœuds, en filtrant les nœuds TEXT d'espaces blancs uniquement.
  • Utilisez le code Java pour ce faire: utilisez XPath pour rechercher tous les nœuds TEXT d'espaces blancs, parcourez-les et supprimez-les de leur parent (à l'aide de getParentNode().removeChild()). Quelque chose comme ceci ferait (doc serait votre objet de document DOM):

    XPath xp = XPathFactory.newInstance().newXPath();
    NodeList nl = (NodeList) xp.evaluate("//text()[normalize-space(.)='']", doc, XPathConstants.NODESET);
    
    for (int i=0; i < nl.getLength(); ++i) {
        Node node = nl.item(i);
        node.getParentNode().removeChild(node);
    }
    
16
Isaac

Vous pouvez regarder quelque chose comme ceci si vous avez seulement besoin de "nettoyer" rapidement votre code XML. Vous pourriez alors avoir une méthode comme:

public static String cleanUp(String xml) {
    final StringReader reader = new StringReader(xml.trim());
    final StringWriter writer = new StringWriter();
    try {
        XmlUtil.prettyFormat(reader, writer);
        return writer.toString();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return xml.trim();
}

En outre, pour comparer les différences de vérification des accès, si vous en avez besoin: XMLUnit

1
mdm

J'utilise le code ci-dessous:

System.out.println("Start remove textnode");
        i=0;
        while (parentNode.getChildNodes().item(i)!=null) {
            System.out.println(parentNode.getChildNodes().item(i).getNodeName());
            if (parentNode.getChildNodes().item(i).getNodeName().equalsIgnoreCase("#text")) {
                parentNode.removeChild(parentNode.getChildNodes().item(i));
                System.out.println("text node removed");
            }
            i=i+1;

        }
1
Jlearner

Je faisais face au même problème et je n’avais aucune idée de cela pendant longtemps, mais maintenant, après la question de Brad et sa propre réponse à sa propre question, je me suis rendu compte du problème.

Je dois ajouter ma propre réponse, parce que celle de Brad n'est pas vraiment parfaite, comment Isaac a dit: 

Je ne serais pas un grand fan de supprimer aveuglément les nœuds enfants sans savoir ce qu'ils sont

Donc, une meilleure "solution" (citée parce que c'est une solution plus probable) est:

pathsElement.setTextContent("");

Cela supprime complètement les lignes vides inutiles. C'est certainement mieux que de supprimer tous les nœuds enfants. Brad, ça devrait marcher pour toi aussi.

Mais c’est un effet, pas la cause, et nous avons appris comment supprimer cet effet, pas la cause.

La cause en est: lorsque nous appelons removeChild(), il supprime cet enfant, mais il laisse un retrait de l'enfant supprimé et le saut de ligne également. Et cet indent_and_like_break est traité comme un contenu textuel.

Donc, pour éliminer la cause, nous devrions comprendre comment supprimer un enfant et son retrait . Bienvenue sur ma question à ce sujet .

1
Dmitry Frank

Quelques remarques: 1) Lorsque vous manipulez XML (supprimer des éléments/en ajouter de nouveaux), je vous conseille vivement d’utiliser XSLT (et non DOM) 2) Lorsque vous transformez un document XML en XSLT (comme dans votre méthode de sauvegarde), définissez OutputKeys.INDENT sur "non" 3) Pour un post-traitement simple de votre xml (suppression des espaces, commentaires, etc.), vous pouvez utiliser un simple SAX2. filtre

0
rmuller

Il existe un moyen très simple de supprimer les lignes vides si vous utilisez une API de traitement DOM (par exemple, DOM4J):

  • placez le texte que vous souhaitez conserver dans une variable (par exemple,text)
  • définissez le texte du nœud sur "" à l'aide de node.setText("")
  • définissez le texte du nœud surtextusing node.setText(text)

et voilà! il n'y a plus de lignes vides. Les autres réponses décrivent très bien comment les lignes vides supplémentaires de la sortie xml sont en réalité des noeuds supplémentaires de type text. 

Cette technique peut être utilisée avec n’importe quel système d’analyse DOM, à condition que le nom de la fonction de paramétrage du texte soit modifié pour correspondre à celui de votre API, d’où la possibilité de le représenter légèrement de manière plus abstraite.

J'espère que cela t'aides:) 

0
GMasucci
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setIgnoringElementContentWhitespace(true);
0
Tai Le