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

Langage PHP Discussion :

getElementsByTagNameNS : Récupérer les balises w:Sdt d'un fichier Word au format html


Sujet :

Langage PHP

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Ingénieur commercial
    Inscrit en
    Avril 2017
    Messages
    46
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Ingénieur commercial

    Informations forums :
    Inscription : Avril 2017
    Messages : 46
    Points : 36
    Points
    36
    Par défaut getElementsByTagNameNS : Récupérer les balises w:Sdt d'un fichier Word au format html
    Bonjour à tous,

    Je débute le PHP depuis quelques jours et dans le cadre de mon projet, je dois lire un fichier word enregistré au format html (TemplateDemo.html) puis récupérer le contenu des balises de "w:Sdt" présente dans ce fichier.

    Extrait du fichier TemplateDemo.html:

    Code : 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
    <html xmlns:v="urn:schemas-microsoft-com:vml"
    xmlns:o="urn:schemas-microsoft-com:office:office"
    xmlns:w="urn:schemas-microsoft-com:office:word"
    xmlns:m="http://schemas.microsoft.com/office/2004/12/omml"
    xmlns="http://www.w3.org/TR/REC-html40">
     
    </head>
     
    <body lang=FR style='tab-interval:35.4pt'>
     
    <div class=WordSection1>
     
    <p class=MsoNormal>Bonjour <w:Sdt DocPart="06F41A9E3F1AD443B6220BEA9C32380D"
     Title="NOM" SdtTag="VAR" ID="950663817">NOM1</w:Sdt>,</p>
     
    <p class=MsoNormal><o:p>&nbsp;</o:p></p>
    Voici mon code PhP pour lire le contenue du fichier TemplateDemo.html et récupérer le contenu des balises <w:Sdt>:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    //Extract data from TemplateDemo.html
    $content = file_get_contents( dirname( __FILE__ ) . '/TemplateDemo.html' );
      if ($content === false) echo "ERROR CANNOT READ TEMPLATEDEMO file";
    //Extraction of <w:Std> tags included in Word Template
    $dom = new DOMDocument();
    $dom->loadHTML($content);
    		foreach ($dom->getElementsByTagNameNS('*', 'w:std') as $element) {
        echo 'local name: ', $element->localName, ', prefix: ', $element->prefix, "\n";
    }
    Le echo ne me renvoi rien. J'ai essayé de suivre à la lettre la documentation PhP:

    https://www.php.net/manual/fr/domdoc...ytagnamens.php

    Est ce que quelqu'un peut m'aiguiller svp ?

    AG

  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
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    foreach ($dom->getElementsByTagNameNS('*', 'w:std') as $element) {
    Le deuxième paramètre de getElementsByTagNameNS() doit être le nom local de l'élément donc il faut enlever le préfixe. En plus ta balise de s'appelle pas std mais Sdt et il faut respecter la casse.

    Dernière chose tu devrais plutôt tenter ta chance avec loadXML plutôt qu'avec loadHTML.
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  3. #3
    Nouveau membre du Club
    Homme Profil pro
    Ingénieur commercial
    Inscrit en
    Avril 2017
    Messages
    46
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Ingénieur commercial

    Informations forums :
    Inscription : Avril 2017
    Messages : 46
    Points : 36
    Points
    36
    Par défaut
    Bonjour CosmoKnacki,

    Merci beaucoup de me donner des pistes. Je débute et j'ai l'impression de pas m'attaquer à du super facile...

    J'ai modifié le code comme ci dessous mais le Echo affiche toujours rien. Peux être à cause du NameSpace qui est sur "*"? J'ai essayer de mettre 'urn:schemas-microsoft-com:office:word' mais ça ne change rien non plus.

    Je comprends à ta dernière phrase que ce serait peut être plus simple si j'enregistre le document Word en .xml et que je fasse loadXML. Je vais essayer demain et je vous informe du résultat.

    Encore merci.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    //Extract data from TemplateDemo.html
    $content = file_get_contents( dirname( __FILE__ ) . '/TemplateDemo.html' );
      if ($content === false) echo "ERROR CANNOT READ TEMPLATEDEMO file";
    //Extraction of <w:Std> tags included in Word Template
    $dom = new DOMDocument();
    $dom->loadHTML($content);
    		foreach ($dom->getElementsByTagNameNS('*', 'Std') as $element) {
        echo 'local name: ', $element->localName, ', prefix: ', $element->prefix, "\n";
    }

  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
    En fait, avec le peu que tu as montré de ton document, le problème est double:
    • Si tu charges ton document avec DOMDocument::loadHTML, celui-ci va sucrer tous les préfixes d'espaces de noms inconnues des éléments (car en html DOMDocument applique des corrections automatiques).
    • Si tu charges ton document avec DOMDocument::loadXML, le parser va tiquer à la moindre incartade (comme une balise non-fermée, un attribut dont la valeur n'est pas entre quotes simples ou doubles, une entité inconnue comme &nbsp;) et tu ne pourras pas exploiter le document car l'arbre DOM ne sera même pas construit (ce coup ci, pas de corrections automatique, un document est du XML ou il ne l'est pas).


    Pour prendre la mesure de tout ça, tu peux faire ce test qui va t'afficher les erreurs rencontrées:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    libxml_use_internal_errors(true);
    $dom = new DOMDocument;
    $dom->loadXML($content); 
    print_r(libxml_get_errors());
    Puis remplace loadXML par loadHTML et tu verras que les erreurs relevées ne sont pas toutes les mêmes.

    Bref, pour t'en tirer facilement, ce que tu peux faire c'est de charger ton document en html, mais tu devras dire adieu aux préfixes d'espaces de noms pour l'exploiter, donc:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    libxml_use_internal_errors(true);
    $dom = new DOMDocument;
    $dom->loadHTML($content); 
     
    foreach ($dom->getElementsByTagName('sdt') as $element) { 
        //...
    }
    L'autre solution serait de "réparer" le document pour en faire du XML (en exploitant les informations données par libxml_get_errors()), mais c'est fastidieux et pas toujours possible.
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  5. #5
    Nouveau membre du Club
    Homme Profil pro
    Ingénieur commercial
    Inscrit en
    Avril 2017
    Messages
    46
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Ingénieur commercial

    Informations forums :
    Inscription : Avril 2017
    Messages : 46
    Points : 36
    Points
    36
    Par défaut
    Hello CosmoKnacki,

    Merci pour ces conseils. Je suis partie sur la piste de l'utilisation d'un .XML au lieu du .HTML.
    Pour cela j'ai ce fichier modèle Word dans lequel j'ai mis un champs conditonnel pour reconnaitre la variable NOM dans les balises du fichier XML:

    Nom : Capture d’écran 2019-07-11 à 09.58.29.png
Affichages : 503
Taille : 170,3 Ko
    Nom : Capture d’écran 2019-07-11 à 09.59.36.png
Affichages : 585
Taille : 294,0 Ko

    Dans le fichier XML, je retrouve bien mon texte "NOM" dans une balise de type "std". A ce stade je suis partie de du principe que les milliers d'heures passées à developper Word par les ingénieurs de Microsoft me garantissent que le fichier XML généré par Word est forcement sans erreur de format XML. Je suis peut être trop optimiste

    Nom : Capture d’écran 2019-07-11 à 10.02.15.png
Affichages : 517
Taille : 257,9 Ko

    Voici à quoi ressemble mon code maintenant:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //Extract data from Bonjour.xml
    $content = file_get_contents( dirname( __FILE__ ) . '/Bonjour.xml' );
      if ($content === false) echo "ERROR CANNOT READ file";
    //Extraction of <w:sdt> tags included in Word Template
    libxml_use_internal_errors(true);
    $dom = new DOMDocument();
    $dom->loadXML($content);
    		foreach ($dom->getElementsByTagNameNS('http://schemas.openxmlformats.org/wordprocessingml/2006/main', 'sdt') as $element) {
        echo 'local name: ', $element->localName, ', prefix: ', $element->prefix, value: ', $element->nodeValue, "\n";
    }

    et ça fonctione voici ce que m'affiche la page web:

    Nom : Capture d’écran 2019-07-11 à 11.08.26.png
Affichages : 456
Taille : 28,8 Ko

    Encore merci beaucoup !

    Un dernier point, je remarque la fonction ne récupére pas tous les paramétres de la balise. En effet voici ce qui est contenu dans $element:

    Nom : Capture d’écran 2019-07-11 à 11.32.43.png
Affichages : 437
Taille : 178,6 Ko

    Voici le contenu du XML:
    Nom : Capture d’écran 2019-07-11 à 11.33.05.png
Affichages : 452
Taille : 91,1 Ko

    J'aimerai récupérer l'ID:
    <w:id w:val="950663817"/>

    Afin d'identifier de façon univoque la variable car 2 balises "sdt" pourraient avoir le même nom. Une idée pour cela ?

  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
    Ah bah si tu peux réenregistrer le fichier sous forme XML, c'est effectivement l'idéal, donc fonce.

    Ne soit pas étonné de ne voir ni les attributs ni les nœuds enfants en faisant var_dump($element);, celui-ci ne donnera que les caractéristiques de l'objet DOMElement et pas la description détaillée de ses attributs XML ni de ses nœuds enfants quels qu'ils soient.

    Pour parvenir plus facilement à tes fins, tu peux t'intéresser au langage XPath (tutoriel nécessaire) via la class DOMXPath qui permet de faire des recherches ciblées dans l'arbre DOM, exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    $xp = new DOMXPath($dom);
    $xp->registerNameSpace('w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'); // permet de définir les préfixes utilisés dans les requêtes XPath
     
    $result = $xp->evaluate('string(//w:sdt/w:sdtPr/w:id/@val)');
     
    echo $result;
    (XPath n'est pas indispensable, on peut très bien s'en passer, mais dés lors qu'il s'agit de vérifier des relations de parenté, les fonctions classiques du DOM deviennent très lourdes à exploiter et nécessitent des boucles à n'en plus finir sur les enfants des enfants des enfants... de l'élément.)
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  7. #7
    Nouveau membre du Club
    Homme Profil pro
    Ingénieur commercial
    Inscrit en
    Avril 2017
    Messages
    46
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Ingénieur commercial

    Informations forums :
    Inscription : Avril 2017
    Messages : 46
    Points : 36
    Points
    36
    Par défaut
    Citation Envoyé par CosmoKnacki Voir le message
    Ah bah si tu peux réenregistrer le fichier sous forme XML, c'est effectivement l'idéal, donc fonce.

    Ne soit pas étonné de ne voir ni les attributs ni les nœuds enfants en faisant var_dump($element);, celui-ci ne donnera que les caractéristiques de l'objet DOMElement et pas la description détaillée de ses attributs XML ni de ses nœuds enfants quels qu'ils soient.

    Pour parvenir plus facilement à tes fins, tu peux t'intéresser au langage XPath (tutoriel nécessaire) via la class DOMXPath qui permet de faire des recherches ciblées dans l'arbre DOM, exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    $xp = new DOMXPath($dom);
    $xp->registerNameSpace('w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'); // permet de définir les préfixes utilisés dans les requêtes XPath
     
    $result = $xp->evaluate('string(//w:sdt/w:sdtPr/w:id/@val)');
     
    echo $result;
    (XPath n'est pas indispensable, on peut très bien s'en passer, mais dés lors qu'il s'agit de vérifier des relations de parenté, les fonctions classiques du DOM deviennent très lourdes à exploiter et nécessitent des boucles à n'en plus finir sur les enfants des enfants des enfants... de l'élément.)
    Pour le document je n'ai pas de contrainte entre le XML ou le HTML. Je continue donc en XML.

    Je comprends que le code ci dessus avec la classe DomXPath devrait me permettre de récupérer la valeur de la balise ID. J'ai lancé ton bout de code mais le echo sur $result ne me renvoi rien. Je vais lire attentivement la documentation de la classe DomXPath pour essayer de la faire fonctionner.

    Je suis également tomber sur le la classe:XMLReader. Je vais voir si cela peut m'aider.
    https://www.php.net/manual/fr/class.xmlreader.php

    Merci beaucoup.

  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
    ...le echo sur $result ne me renvoi rien...
    C'est peut-être l'url du namespace qui n'est pas bonne, regarde dans ton fichier XML quelle est l'url correcte (xmlns:w="...").

    XMLReader, c'est bien parce que très rapide (car il ne construit pas d'arbre DOM) et parce que le parsing se fait au fur et à mesure (donc on peut l'arrêter lorsqu'on a trouvé ce qu'on voulait), mais ça n'est absolument pas souple et ça devient très vite limité lorsqu'on veut faire des choses complexes (on retombe dans un problème des boucles et de conditions imbriquées) ou lorsqu'on a plusieurs recherches différentes dans le document (ce qui alourdi la boucle principale).

    En fait ce qui manque à cette extension c'est une sorte de gestionnaire d'événements (eventlistener) comme en javascript pour éviter la tartine de boucles et de tests. Il est possible de faire une programmation dans ce sens mais du coup on perd l'aspect légèrté de l'extension.
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  9. #9
    Nouveau membre du Club
    Homme Profil pro
    Ingénieur commercial
    Inscrit en
    Avril 2017
    Messages
    46
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Ingénieur commercial

    Informations forums :
    Inscription : Avril 2017
    Messages : 46
    Points : 36
    Points
    36
    Par défaut
    Merci CosmoKnacki,

    Pour le moment je vais rester sur DOMDocument. Je suis parvenu à récupérer la valeur de l'attribut ID comme cela:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    //Get item element
    $sdt = $dom->getElementsByTagNameNS('http://schemas.openxmlformats.org/wordprocessingml/2006/main', 'sdt')->item(0);
    $id = $sdt->getElementsByTagNameNS('http://schemas.openxmlformats.org/wordprocessingml/2006/main', 'id')->item(0);
    $idvalue = $id -> attributes -> getNamedItem( 'val' ) -> value;
    Mon but est uniquement de pouvoir venir remplacer dans le fichier .xml la valeur textContent des balises sdt en les identifiant par l'ID contenue dans leur balise enfant... Je pense maintenant avoir tous les outils pour réussir... j'espère...

    Est ce que tu sais comment à la fin je peux créer un nouveau fichier .xml qui sera le fichier d'origine chargé mais avec les modification ?
    J'ai essayé cela mais je pense être à coté de la plaque:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $dom->saveXML('exemple.xml');

  10. #10
    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
    Je sais ce qui n'allait pas dans la requête XPath, il manquait le préfixe w:devant l'attribut val, il suffit de le rajouter.

    Citation Envoyé par Alex101283 Voir le message
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    //Get item element
    $sdt = $dom->getElementsByTagNameNS('http://schemas.openxmlformats.org/wordprocessingml/2006/main', 'sdt')->item(0);
    $id = $sdt->getElementsByTagNameNS('http://schemas.openxmlformats.org/wordprocessingml/2006/main', 'id')->item(0);
    $idvalue = $id -> attributes -> getNamedItem( 'val' ) -> value;
    Plus direct:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    $nsp = ['w' => 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'];
     
    $sdt = $dom->getElementsByTagNameNS($nsp['w'], 'sdt')->item(0);
    $id = $sdt->getElementsByTagNameNS($nsp['w'], 'id')->item(0);
    $idvalue = $id->getAttributeNS($nsp['w'], 'val');
    Mon but est uniquement de pouvoir venir remplacer dans le fichier .xml la valeur textContent des balises sdt en les identifiant par l'ID contenue dans leur balise enfant.
    Oui et c'est là qu'on voit à quel point XPath est redoutable car en une seule requête tu peux vérifier des conditions et cibler le nœud qui t'intéresse:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    $xp = new DOMXPath($dom);
    $xp->registerNameSpace('w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'); 
    $textNL = $xp->query('//w:sdt[.//w:id/@w:val="950663817"]/w:sdtContent//w:t/text()');
     
    if ($textNL->length) { // tu peux même te payer le luxe de ce type de vérification qu'il faudrait faire pratiquement à chaque ligne avec les fonctions de bases.
        $text = $textNL->item(0);
        $text->parentNode->replaceChild($dom->createTextNode('Toto'), $text);
    }

    Est ce que tu sais comment à la fin je peux créer un nouveau fichier .xml qui sera le fichier d'origine chargé mais avec les modification ?
    DOMDocument::save()
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  11. #11
    Nouveau membre du Club
    Homme Profil pro
    Ingénieur commercial
    Inscrit en
    Avril 2017
    Messages
    46
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Ingénieur commercial

    Informations forums :
    Inscription : Avril 2017
    Messages : 46
    Points : 36
    Points
    36
    Par défaut
    Excellent, merci beaucoup.

    Effectivement avec Xpath ça à l'air très puissant. Je recode demain en utilisant toutes tes préconisations . J'enverrai ma copie finale

    J'ai juste un peu de mal avec l'opérateur "->". Je le fait par automatisme et par tâtonnement, je comprends qu'il permet de passer d'un niveau à l'autre de la structure mais aussi de d'appeler une fonction ? Comme ici ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $textNL = $xp->query('//w:sdt[.//w:id/@w:val="950663817"]/w:sdtContent//w:t/text()');
    Je déduis que cette ligne enregistre dans $textNL la balise text correspondant à la balise sdt qui à l'ID 950663817 dans son child w:id mais je maitrise pas vraiment la syntaxe.

    idem pour

    ça va paraitre nul mais je comprends pas ce que fait ce contrôle. J'ai commencé le PHP depuis lundi... j'ai appris les variables, les opérateurs, les tableaux, les commandes de base mais j'ai l'impression que ce qu'on manipule avec les fonctions DOMDocument c'est encore autre chose que je ne maitrise pas.

    et ici:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $text->parentNode->replaceChild($dom->createTextNode('Toto'), $text);
    Je devine à peut près ce que ça fait mais avec 3 fonction dans la même ligne je suis pas sur de moi.
    $text contient la balise text à mettre à jour et le code lui dit remonte un niveau dessus (le parent) puis remplace l'enfant $text par la valeur 'Toto'. C'est bien un remplacement malgré que la fonction s'appelle createTextNode ? Je comprends qu'on remonte au parent car on peut uniquement agir des Childs ? C'est bien cela ?

    Merci pour les explications

  12. #12
    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
    L'opérateur -> n'a rien à voir avec le DOM en particulier, il permet d'accéder à une méthode ou à une propriété d'un objet (=une instance de classe):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class Toto {
        public maProp=3.14;
     
        public function maMethode() { echo "pouet"; }
    }
     
    $a = new Toto();
     
    echo $a->maProp;
     
    echo PHP_EOL;
     
    $a->maMethode();
    query comme evaluate sont des méthodes de la classe DOMXPath. Donc $xp qui est une instance de cette classe en dispose. Ces méthodes prennent en premier paramètre une requête XPath. De base, la syntaxe d'XPath n'est pas différente de celle du chemin d'un fichier rep1/rep2/rep3/fichier sauf que là on se fait un chemin avec les balises. Mais XPath ne se cantonne pas à ça, il est également capable de vérifier des conditions au passage (ces conditions sont appelées "prédicats"), c'est ce que tu trouves entre crochets.

    Si on la décompose:
    Code xpath : 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
    // # descendant de la racine du site
    w:sdt # un élément (balise) sdt avec le namespace dont le préfixe est w
    [ # prédicat
        . # élément courant (donc w:sdt)
        // # descendant de cet élément
        w:id # l'élément w:id
        / # descendant direct de w:id
       @w:val # l'attribut w:val
        ="950663817" # qui vaut "950663817"
    ] # fin du prédicat
    / # descendant direct de w:sdt
    w:sdtContent
    // # descendant de w:sdtContent
    w:t
    / # descendant direct de w:t
    text() # un nœud texte

    Mais XPath ne se limite pas à cela, loin de là. Tu dois passer absolument par la case tutoriel.

    La méthode DOMXPath::query() renvoie un objet DOMNodeList (le résultat d'une requête peut être plusieurs nœuds) qui dispose d'une propriété length (=nombre d'éléments qu'il y a dans la liste). Donc si la requête XPath ne renvoie aucun résultat, $textNL->length vaut 0 (ou null, je ne sais plus), c'est pour ça que je fais le test car dans ce cas précis $textNL->item(0) n'existerait pas et provoquerait une erreur.

    Pour ce qui est de replaceChild, c'est bien l'idée: on appelle cette méthode depuis le parent du nœud qu'on veut remplacer. Pour ce qui est de la création du remplaçant, on aurait très bien pu écrire une ligne de plus:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    $newTextNode = $dom->createTextNode('Toto');
    $text->parentNode->replaceChild($newTextNode, $text);
    Ne t'inquiète pas le DOM c'est un gros morceau qu'on apprend pas du jour au lendemain, arme toi de var_dump(), du manuel PHP et de tutoriels. L'avantage, c'est qu'une fois qu'on en a tâté, on le retrouve dans tous les langages.
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  13. #13
    Nouveau membre du Club
    Homme Profil pro
    Ingénieur commercial
    Inscrit en
    Avril 2017
    Messages
    46
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Ingénieur commercial

    Informations forums :
    Inscription : Avril 2017
    Messages : 46
    Points : 36
    Points
    36
    Par défaut
    Merci beaucoup pour tous ces excellents conseils.
    Je comprends que ce qu'on manipule ce sont des objets qui ont des fonctions et des caractéristiques. Les objets c'est un chapitre que je n'avais pas encore vu. Je vais suivre le cours pour me mettre à niveau.

    Je ne parviens pas à sauvegarder le XML mis à jour. J'ai essayé de m'inspirer de la doc ici mais visiblement une subtilité m'échape.

    https://www.php.net/manual/fr/domdocument.save.php

    Comme je ne parviens pas à faire marcher l'enregistrement du document xml, j'ai suivi ton conseil et j'utilise var_dump();

    lorsque je fais var_dump($textNL); avant de faire le replace_child

    Je m'attends à retrouver la valeur "NOM1" or le système m'affiche cela:

    object(DOMNodeList)#1344 (1) { ["length"]=> int(1) }

    J'ai pensé que c'était peut être lié à la query() car je remarque qu'on passe de la balise w:sdt directement à la balise w:id or il y a la balise w:sdtPr entre les deux. J'ai donc essayé de mettre à jour la query() comme ceci mais cela ne change rien:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    $textNL = $xp->query('//w:sdt[.//w:sdtPr//w:id/@w:val="950663817"]/w:sdtContent//w:t/text()');
    Le xml:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    w:sdt>
    <w:sdtPr>
    <w:alias w:val="NOM"/>
    <w:tag w:val="VAR"/>
    <w:id w:val="950663817"/>
    <w:placeholder>...</w:placeholder>
    </w:sdtPr>
    <w:sdtContent>
    <w:r>
    <w:t>NOM1</w:t>
    </w:r>
    </w:sdtContent>
    </w:sdt>
    et voici mon code complet à ce stade:

    Code : 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
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    //Start of specific code
     
    //Extract data from Bonjour.xml
    $content = file_get_contents( dirname( __FILE__ ) . '/Bonjour.xml' );
      if ($content === false) echo "ERROR CANNOT READ file";
    //Extraction of <w:std> tags included in Word XML Template
    $dom = new DOMDocument();
    $dom->loadXML($content);
     
    //Enregistrement du NameSpace Microsoft Word
    $nsp = ['w' => 'http://schemas.openxmlformats.org/wordprocessingml/2006/main'];
     
    //Get item elements <w:sdt> with linked id's in XML document
    		foreach ($dom->getElementsByTagNameNS($nsp['w'], 'sdt') as $sdt)
    		{
    			$id = $sdt->getElementsByTagNameNS($nsp['w'], 'id')->item(0);
    			$idvalue = $id -> attributes -> getNamedItem( 'val' );
    			//$idvalue = $id->getAttributeNS($nsp['w'], 'val'); //Je n'arrive pas à faire fonctionner la fonction getAttributeNS
    			$ids[]=$idvalue->value;
    			echo 'local name: ', $sdt->localName, ', prefix: ', $sdt->prefix, ' ID:',$idvalue->value, "\n",'<br/>';
    			echo '</pre>';
    		}
     
    // Update text value for a balise sdt with ID 950663817 with XPath
    $target_id = array_search('950663817', $ids);
    $xp = new DOMXPath($dom);
    $xp->registerNameSpace('w', 'http://schemas.openxmlformats.org/wordprocessingml/2006/main');
    $textNL = $xp->query('//w:sdt[.//w:id/@w:val='.$ids[$target_id].']/w:sdtContent//w:t/text()');
    if ($textNL->length)
    	{ 
        $text = $textNL->item(0);
        $text->parentNode->replaceChild($dom->createTextNode('Toto'), $text);
      }
    //Check update of textnode
    var_dump($textNL);
     
    //Save updated xml in test.xml file
    $dom->save("test.xml"); // Ici rien ne se passe. Je m'attends à avoir un doc test.xml créé mais je me plante à un endroit que je n'identifie pas
     
    //End of specific code

  14. #14
    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
    Non, ce que t'affiche var_dump($textNL) est tout à fait correct de même que la requête XPath: DOMXPath::query renvoie bien un objet DOMNodeList (qui comme son nom l'indique est une liste d'objets DOMNode).

    var_dump($textNL); t'indique simplement la valeur de son unique attribut (Length) qui vaut 1 (Il n'y a donc qu'1 objet dans la liste), et il n'est pas censé t'indiquer autre chose et encore moins les attributs des objets contenus dans cette liste.

    Si tu veux voir les attributs du seul objet contenu dans cette liste: var_dump($textNL->item(0))
    J'ai pensé que c'était peut être lié à la query() car je remarque qu'on passe de la balise w:sdt directement à la balise w:id or il y a la balise w:sdtPr entre les deux. J'ai donc essayé de mettre à jour la query()...
    Merci de passer par la case tutoriel sur XPath pour éviter tout futur délire.

    En ce qui concerne le problème d'enregistrement, le var_dump que tu peux faire est celui de ta commande d'enregistrement (comme précisé dans le manuel, DOMDocument::save() renvoie le nombre d'octets enregistrés ou false lorsque l'enregistrement échoue). Il y a fort à parier qu'il te renverra false: la plupart du temps c'est ce qui se produit quand on essaie d'enregistrer quelque chose dans un répertoire où on a pas les droits en écriture. C'est plutôt de ce coté là qu'il faut chercher.
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  15. #15
    Nouveau membre du Club
    Homme Profil pro
    Ingénieur commercial
    Inscrit en
    Avril 2017
    Messages
    46
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Hauts de Seine (Île de France)

    Informations professionnelles :
    Activité : Ingénieur commercial

    Informations forums :
    Inscription : Avril 2017
    Messages : 46
    Points : 36
    Points
    36
    Par défaut
    Pour le DOMDocument::save() j'avais bien mis le répertoire en CHMOD777, en fait c'était juste le chemin à indiquer.
    Comme ceci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    //Save updated xml in test.xml file
    $path = '../www/wp-content/themes/softing-child/';
    $dom->save($path . '/test.xml');
    Encore merci beaucoup pour toute cette aide qui m'a permis de grandement progresser. J'espère que ces échanges profiterons à d'autres également.

    Cdlt,

    AG

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

Discussions similaires

  1. Récupérer les balises headings de la page html
    Par MisterLSC dans le forum Général JavaScript
    Réponses: 12
    Dernier message: 06/04/2018, 12h24
  2. Réponses: 25
    Dernier message: 10/12/2011, 23h21
  3. Réponses: 2
    Dernier message: 09/12/2010, 21h03
  4. Comment récupérer les balises enfant ?
    Par souffle56 dans le forum XSL/XSLT/XPATH
    Réponses: 2
    Dernier message: 12/08/2010, 22h21
  5. [XML] HTML dns XML -> Récupérer les balises intérprétées comme du XML
    Par dacid dans le forum Bibliothèques et frameworks
    Réponses: 0
    Dernier message: 16/04/2010, 17h59

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