IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Bibliothèques et frameworks PHP Discussion :

[DOM XML] Suppression d'éléments enfants


Sujet :

Bibliothèques et frameworks PHP

  1. #1
    Membre à l'essai Avatar de jean-c
    Homme Profil pro
    Développeur, documentaliste, gestionnaire d'information
    Inscrit en
    Décembre 2014
    Messages
    24
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur, documentaliste, gestionnaire d'information

    Informations forums :
    Inscription : Décembre 2014
    Messages : 24
    Points : 14
    Points
    14
    Par défaut [DOM XML] Suppression d'éléments enfants
    Bonsoir !

    J'ai un arbre XML comme suit :

    Code xml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
     
    <utilisateurs>
    <user id="1">Jean-michel</user>
    <user id="2">Pascal</user>
    <user id="3">Hubert</user>
    <user id="4">Emilie</user>
    <user id="5">Samia</user>
    </utilisateurs>

    Ce que je veux, c'est enlever les noeuds enfants. Pour cela j'utilise PHP DOM XML et sa méthode removeChild().

    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
     
     
    <?php
     
    $document = new DOMDocument("1.0", "UTF-8");
    $document -> load("cheminVersMonFichier.xml");
    $document -> xmlStandalone = true;
    $document -> preserveWhiteSpace = "false";
    $document -> formatOutput = "true";
    $unPath = new DOMXPath($document);
     
    $cpteUsers = $unPath -> evaluate("count(/utilisateurs/user[@id=' . $idAretirer . '])");
     
    for($i = 0; $i < $cpteUsers; $i++) {
     
    $monPath = $unPath -> query("/utilisateurs/user[@id=' . $idAretirer . ']") -> item(0);
    $getNoeudParent = $monPath -> parentNode;
    $retraitNoeud = $getNoeudParent -> removeChild();
     
    }
     
    $sauvegarde = $document -> save("cheminVersMonFichier.xml");
    ?>

    Ce code devrait me permettre de retirer tous les enfants du noeud <utilisateurs></utilisateurs>.

    Mon problème c'est qu'avec DOM, lors de la suppression, il laisse des tags vides et on ne peut plus appendChild() de nouveaux éléments enfants à l'intérieur sans bug. J'ai fait des recherches, et je suis tombé sur les extentions LIBXML mais je ne sais pas laquelle pourrait, lors d'une suppression, passer le tag de : <utilisateurs></utilisateurs> à <utilisateurs />, le condenser.

    Quelle méthode me conseillez vous ? Vous avez des exemples de code ? Vous connaissez cette problématique vous aussi ? Vous avez déjà travaillé avec les LIBXML ?

    Je suis preneur de conseils !

  2. #2
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 858
    Points : 6 556
    Points
    6 556
    Par défaut
    Dans l'ordre du code:

    Concernant le constructeur DOMDocument::__contruct, il est inutile de lui passer les paramètres de version xml et d'encodage, car ceux seront systématiquement écrasés dés lors que tu charges un document avec DOMDocument::load ou DOMDocument::loadXML par ceux trouvés dans la directive xml <?xml version="1.0" encoding="UTF-8" standalone="yes"?> ou à défaut de directive par des valeurs par défaut. (En fait les paramètres du constructeur ne sont utiles que quand tu veux créer un document de toute pièce sans charger quoi que ce soit.)

    Il est également inutile de préciser l'attribut DOMDocument::xmlStandalone.

    Les attributs DOMDocument::preserveWhiteSpace et DOMDocument::formatOutput sont de type booléen, pas de type string.

    La suite du code est assez mystérieuse:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    $cpteUsers = $unPath -> evaluate("count(/utilisateurs/user[@id=' . $idAretirer . '])");
     
    for($i = 0; $i < $cpteUsers; $i++) { 
    $monPath = $unPath -> query("/utilisateurs/user[@id=' . $idAretirer . ']") -> item(0);
    $getNoeudParent = $monPath -> parentNode;
    $retraitNoeud = $getNoeudParent -> removeChild();
    }
    Pourquoi veux-tu compter le nombre de nœuds user qui ont pour attribut id une certaine valeur contenue dans $idAretirer? La valeur d'un attribut id est censée être unique. D'ailleurs pas besoin de faire appel à XPath pour obtenir le nœud avec une id précise, il suffit d'utiliser la méthode DOMDocument::getElementById.
    D'autre part, pour boucler sur un objet DOMNodeList (ce que renvoie par exemple DOMXPath::query ou DOMDocument::childNodes), inutile de faire une première requête avec DOMXPath::evaluate('count(bidule)') pour compter puis de faire une boucle for pour parcourir les différents nœuds. Il suffit d'utiliser directement la méthode DOMXPath::query puis foreach:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    $nodeList = $xp->query('bidule'); // $nodeList est une instance de DOMNodeList
    foreach ($nodeList as $node) {
        //...
    }
    Ce n'est pas ainsi que DOMDocument::removeChild s'utilise (si tu ne lui précise pas ce que tu veux enlever, il ne peut pas le deviner), voir le manuel PHP.

    Je trouve étrange que tu dises vouloir retirer tous les nœuds enfant du nœud "utilisateurs" (qui dans ton exemple est par ailleurs le nœud racine) et que le code que tu postes semble avoir pour but d'enlever seulement un nœud enfant bien précis. Il faudrait clarifier ta demande.

    Quoi qu'il en soit, tu devrais activer l'affichage des erreurs en commençant ton code par ini_set('display_errors', 'On');, ne plus utiliser de franglais pour les noms de variables (l'idéal à mon avis, c'est tout en anglais (plus court, plus direct, sans accents)), et te reporter systématiquement au manuel PHP.


    Pas besoin de faire quoi que ce soit en ce qui concerne les nœuds vides, quand un nœud est vide, il est automatiquement représenté par une balise auto-fermante, si ce n'est pas le cas, c'est qu'il n'est pas vide.
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  3. #3
    Membre à l'essai Avatar de jean-c
    Homme Profil pro
    Développeur, documentaliste, gestionnaire d'information
    Inscrit en
    Décembre 2014
    Messages
    24
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur, documentaliste, gestionnaire d'information

    Informations forums :
    Inscription : Décembre 2014
    Messages : 24
    Points : 14
    Points
    14
    Par défaut
    Bonsoir,

    Merci pour ces conseils concernant DOM XML, notamment en ce qui concerne le constructeur de DOMDocument. Cela me permettra d'alléger un peu mon code.
    Je vais appliquer aussi le conseil du ini_set("display_errors", "on"); .

    Initialement j'ai ça :

    Code xml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
     
    <utilisateurs>
    <user id="1">Jean-michel</user>
    <user id="2">Pascal</user>
    <user id="3">Hubert</user>
    <user id="4">Emilie</user>
    <user id="5">Samia</user>
    </utilisateurs>

    Dans ce que j'ai codé, je parviens, à l'aide de removeChild() à retirer les enfants d'un noeud, ça c'est c'est OK.

    Cela fait je souhaiterais donc me retrouver avec :

    Code xml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    <?xml version="1.0" encoding="UTF-8"?>
    <utilisateurs />

    Mais moi, je me retrouve avec :

    Code xml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    <?xml version="1.0" encoding="UTF-8"?>
    <utilisateurs> </utilisateurs>

    Ainsi donc, selon vos explications, mon noeud parent ne serait pas vraiment vide ? De quoi cela peut-il venir ? C'est pour ça qu'initialement, je m'intéresse aux constantes LIBXML, je pense qu'elles pourraient m'aider à résoudre ce problème.

    Merci pour votre réponse.

  4. #4
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 858
    Points : 6 556
    Points
    6 556
    Par défaut
    Et non, il n'est pas vide, il contient un nœud texte (voire plusieurs) avec un espace ou des espaces. Car visiblement avec ton code tu ne cherches qu'à retirer les nœuds user mais pas les nœuds texte entre ces éléments qui sont composés sauts de ligne.

    Avec l'exemple xml que tu as donné, si je devais entièrement vider le nœud "utilisateurs", je ferai:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    $dom = new DOMDocument;
    $dom->load("cheminVersMonFichier.xml");
    $dom->preserveWhiteSpace = false;
    $dom->formatOutput = true;
     
    $target = $dom->getElementsByTagName('utilisateurs')->item(0);
    // ou plus simplement puisqu'il s'agit de l'élément racine
    // $target = $dom->documentElement;
     
    while ($target->childNodes->length) {
        $target->removeChild($target->lastChild);
    }
    En utilisant l'attribut DOMDocument::childNodes tu cibles tous les nœuds enfants quelque soit leur nature (élément, texte ou autre) sans distinction. En faisant ça tu es sûr qu'il sera entièrement vide.

    En ce qui concerne les constantes LIBXML_..., la seule chose que tu puisses faire est justement le contraire de ce que tu souhaites, c'est à dire de produire <utilisateurs></utilisateurs> à la place de <utilisateurs/> en utilisant l'option LIBXML_NOEMPTYTAG en deuxième paramètre de la méthode DOMDocument::save.
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  5. #5
    Membre à l'essai Avatar de jean-c
    Homme Profil pro
    Développeur, documentaliste, gestionnaire d'information
    Inscrit en
    Décembre 2014
    Messages
    24
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur, documentaliste, gestionnaire d'information

    Informations forums :
    Inscription : Décembre 2014
    Messages : 24
    Points : 14
    Points
    14
    Par défaut
    Bonsoir,

    Ok, merci, je cais tenter quelque chose dans ce goût là, ça pourrait marcher.

    Par contre, tu m'as mal compris, je souhaite obtenir :

    Code xml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
     
    <?xml version="1.0" encoding="UTF-8"?>
    <utilisateurs />

    Et non pas :

    Code xml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
     
    <?xml version="1.0" encoding="UTF-8"?>
    <utilisateurs>  </utilisateurs>

    Ayant déjà fait une ou deux recherches, je doute donc que la constante LIBXML_NOEMPTYTAG, me soit d'un grand secours puisqu'elle étend les tags. Est-ce qu'il n'y en a pas une qui permette de faire le contraire ?

    Merci par avance.

  6. #6
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 858
    Points : 6 556
    Points
    6 556
    Par défaut
    Relis calmement la fin des mes deux précédent messages, j'ai bien compris ce que tu souhaites faire, et le code en question fait exactement ça.
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  7. #7
    Membre à l'essai Avatar de jean-c
    Homme Profil pro
    Développeur, documentaliste, gestionnaire d'information
    Inscrit en
    Décembre 2014
    Messages
    24
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur, documentaliste, gestionnaire d'information

    Informations forums :
    Inscription : Décembre 2014
    Messages : 24
    Points : 14
    Points
    14
    Par défaut
    Re-bonsoir !

    Tu avais RAISON !

    Il semble que lorqu'on fait un removeChild(), le noeud parent conserve des noeuds texte, donc, merci à toi et merci à Firebug !

    Nom : contenuNoeud.png
Affichages : 718
Taille : 53,1 Ko

    C'est quoi ces noeuds texte moisis ? Je tiens à préciser que je n'y suis pour rien dans leur présence.

    Je te remercie.

    Je retente sous peu et je mettrai sûrement ce sujet en résolu si tout se déroule selon LE PLAN !

    !

  8. #8
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 858
    Points : 6 556
    Points
    6 556
    Par défaut
    Citation Envoyé par jean-c Voir le message
    C'est quoi ces noeuds texte moisis ? Je tiens à préciser que je n'y suis pour rien dans leur présence.
    Il n'y a rien d'étonnant en fait, ton xml est:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
     
    <utilisateurs>
    <user id="1">Jean-michel</user>
    <user id="2">Pascal</user>
    <user id="3">Hubert</user>
    <user id="4">Emilie</user>
    <user id="5">Samia</user>
    </utilisateurs>
    et pas:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <utilisateurs><user id="1">Jean-michel</user><user id="2">Pascal</user><user id="3">Hubert</user><user id="4">Emilie</user><user id="5">Samia</user></utilisateurs>
    Il y a bien des nœuds texte entre chaque élément user.
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  9. #9
    Membre à l'essai Avatar de jean-c
    Homme Profil pro
    Développeur, documentaliste, gestionnaire d'information
    Inscrit en
    Décembre 2014
    Messages
    24
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur, documentaliste, gestionnaire d'information

    Informations forums :
    Inscription : Décembre 2014
    Messages : 24
    Points : 14
    Points
    14
    Par défaut
    Bonjour,

    Mais alors, le problème vient de l'indentation du XML par les propriétés :

    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    <?php 
     
    $document = new DOMDocument();
    $document -> formatOutput = true; 
    $document -> preserveWhiteSpace = true;
     
    ?>

    ... c'est ça ? Si je veux résoudre le problème détecté dans l'onglet DOM de Firebug, il faut que je génère mon XML sans vouloir d'indentation ?

  10. #10
    Membre à l'essai Avatar de jean-c
    Homme Profil pro
    Développeur, documentaliste, gestionnaire d'information
    Inscrit en
    Décembre 2014
    Messages
    24
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur, documentaliste, gestionnaire d'information

    Informations forums :
    Inscription : Décembre 2014
    Messages : 24
    Points : 14
    Points
    14
    Par défaut Un plan qui se déroule sans accrocs !
    Re !

    J'ai compris ce qui foire : lorsque je vire tous les enfants d'un noeud parent, je me retrouve avec :

    Code xml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    <?xml version="1.0" encoding="UTF-8"?>
    <utilisateurs>  </utilisateurs>

    parce que la balise XML est un objet DOMNode, si je ne me trompe, et que cet objet comporte une propriété textContent = " ". Elle est non vide, pas à la valeur null et génère donc un noeud enfant "implicite" à mon noeud parent. Pour résoudre ce problème, après l'élimination des noeuds enfants "visibles" par la méthode removeChild() , il faut écrire :

    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    <?php
    $racine = $document -> getElementsByTagName("utilisateurs") -> item(0);
    //var_dump($racine);
    $racine -> textContent = null;
    ?>

    ensuite tu sauvegardes ton document XML, et là, ça fonctionne, la propriété textContent étant à la valeur null, le tag fermant disparaît et on se retrouve avec :

    Code xml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    <?xml version="1.0" encoding="UTF-8"?>
    <utilisateurs />

    Ca marche !

  11. #11
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 858
    Points : 6 556
    Points
    6 556
    Par défaut
    Citation Envoyé par jean-c Voir le message
    J'ai compris ce qui foire : lorsque je vire tous les enfants d'un noeud parent, je me retrouve avec :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    <?xml version="1.0" encoding="UTF-8"?>
    <utilisateurs>  </utilisateurs>
    Encore une fois, si tu obtiens ça, c'est que tu n'as pas enlevé tous les nœuds enfant. (pour rappel, ce qu'on appelle "nœud" n'est pas forcément une balise mais peut être du texte). Pour visualiser de quoi est fait ton XML, essaie quelque chose comme ça:
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    <?php
    $xml = <<<'EOD'
    <?xml version="1.0" encoding="UTF-8"?>
    <root>
        <tag>toto</tag>
        <tag class="tutu">titi</tag>text text text
        <!--commentaire-->
        <![CDATA[cdata section]]>
        <?php echo 'php code'; ?>
    </root>
    EOD;
     
    $nodeType = [ 'NONE', 'ELEMENT', 'ATTRIBUTE', 'TEXT', 'CDATA', 'ENTITY_REF',
        'ENTITY', 'PI', 'COMMENT', 'DOC', 'DOC_TYPE', 'DOC_FRAGMENT', 'NOTATION',
        'WHITESPACE', 'SIGNIFICANT_WHITESPACE', 'END_ELEMENT', 'END_ENTITY',
        'XML_DECLARATION' ];
     
    $reader = new XMLReader;
    $reader->XML($xml); // ou $reader->open('tonfichier');
     
    while($reader->read()) {
        printf("%-30s\t%-20s\t`%s`%s", $nodeType[$reader->nodeType], $reader->name, $reader->value, PHP_EOL);
    }

    Il n'y a pas de "génération de nœud implicite", il a des nœuds texte contenant des espaces et des sauts de ligne que tu n'as pas retiré.
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  12. #12
    Membre à l'essai Avatar de jean-c
    Homme Profil pro
    Développeur, documentaliste, gestionnaire d'information
    Inscrit en
    Décembre 2014
    Messages
    24
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur, documentaliste, gestionnaire d'information

    Informations forums :
    Inscription : Décembre 2014
    Messages : 24
    Points : 14
    Points
    14
    Par défaut
    Bonsoir,

    Justement, j'ai réussi !

    Je n'obtiens plus :

    Code xml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    <?xml version="1.0" encoding="UTF-8"?>
    <utilisateurs>  </utilisateurs>

    Mais bel et bien :

    Code xml : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    <?xml version="1.0" encoding="UTF-8"?>
    <utilisateurs />

    J'ai tenu compte du fait que ce qui maintenait la balise fermante présente n'était peut-être que du texte. C'était le textContent qui m'ennuyait.

    Mais je retiens cette technique de parcours de document XML donnée dans ton post. EOD c'est pour End Of Data ? EOL pour EndOfLine ? et le <<< , c'est pour demander à voir tout ce qui est avant EOD c'est ça ?

    "%-30s\t%-20s\t`%s`%s" c'est de la mise en forme ?

    Merci.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 2
    Dernier message: 29/11/2012, 13h47
  2. Fichier XML avec éléments enfants de profondeur varaible
    Par tetsu no tama dans le forum Développement de jobs
    Réponses: 2
    Dernier message: 11/07/2011, 17h06
  3. Réponses: 2
    Dernier message: 24/01/2009, 10h21
  4. [XML] [DOM(XML?)] Suppression d'un noeud XML en php
    Par ribrok dans le forum Bibliothèques et frameworks
    Réponses: 1
    Dernier message: 30/01/2007, 15h11

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo