56 votes

Analyser XML avec espace de nom en utilisant SimpleXML

J'ai ceci en tant que xml :

<root xmlns:event="http://www.webex.com/schemas/2002/06/service/event">
    <event:event>
        <event:sessionKey></event:sessionKey>
        <event:sessionName>Learn QB in Minutes</event:sessionName>
        <event:sessionType>9</event:sessionType>
        <event:hostWebExID></event:hostWebExID>
        <event:startDate>02/12/2009</event:startDate>
        <event:endDate>02/12/2009</event:endDate>
        <event:timeZoneID>11</event:timeZoneID>
        <event:duration>30</event:duration>
        <event:description></event:description>
        <event:status>NOT_INPROGRESS</event:status>
        <event:panelists></event:panelists>
        <event:listStatus>PUBLIC</event:listStatus>
    </event:event>
    ...
</root>

Comment puis-je parcourir en boucle tous les nœuds event:event et afficher, par exemple, tous les event:SessionKey ?

Cela ne fonctionne pas :

$xml = new SimpleXMLElement($r);
$xml->registerXPathNamespace('e', 'http://www.webex.com/schemas/2002/06/service/event');

foreach($xml->xpath('//e:event') as $event) {
 var_export($event->xpath('//e:sessionKey'));
}

3 votes

Cela pourrait aider lornajane.net/posts/2010/

1 votes

ne fonctionne pas n'est et n'a jamais été une description correcte d'une erreur. PHP vous donne l'erreur suivante : "Avertissement : SimpleXMLElement::xpath() : Undefined namespace prefix" . Si vous développez des logiciels, vous devriez écouter les avertissements de PHP. Voir aussi : Comment obtenir des messages d'erreur utiles en PHP ?

32voto

ax. Points 22269

Il fonctionne sans registerXPathNamespace et le préfixe complet de l'espace de nom dans les requêtes xpath :

$xml = new SimpleXMLElement($r);

foreach($xml->xpath('//event:event') as $event) {
 var_export($event->xpath('event:sessionKey'));
}

10 votes

Oui et non, en fait je considère cela comme un bug. PHP enregistre automatiquement les espaces de noms du contexte actuel. Cela remplace même les espaces de noms que vous enregistrez vous-même. Vous basez votre source sur les préfixes utilisés dans le document que vous chargez. Une source externe sur laquelle vous n'avez aucun contrôle. Des préfixes qui sont optionnels, ambigus et qui peuvent changer à tout moment. Les espaces de noms sont définis, uniques et stables - les préfixes/aliases ne le sont pas.

23voto

mcrumley Points 3551

Vous devez enregistrer l'espace de nom pour chaque objet simpleXMLElement que vous utilisez.

$xml = new SimpleXMLElement($r);
$xml->registerXPathNamespace('e', 'http://www.webex.com/schemas/2002/06/service/event');

foreach($xml->xpath('//e:event') as $event) {
    $event->registerXPathNamespace('e', 'http://www.webex.com/schemas/2002/06/service/event');
    var_export($event->xpath('//e:sessionKey'));
}

L'espace de nom doit également être déclaré quelque part dans le fichier xml.

<event:event xmlns:event="http://www.webex.com/schemas/2002/06/service/event">
...

La méthode décrite par Ax fonctionne également. Vous pouvez sauter le registerXPathNamespace si vous savez que le fichier xml utilisera toujours le même préfixe.

18voto

ewwink Points 424

Voici une alternative qui a fonctionné pour moi.

$xml = simplexml_load_string($r);
$ns = $xml->getNamespaces(true);

foreach ($xml->children($ns['event'])->event as $skey) {
    $sessionKey = $skey->children($ns['event'])->sessionKey;
    echo $sessionKey;
}

0 votes

L'astuce consiste à utiliser children() avec au moins son premier paramètre. Si vous connaissez la structure du document à l'avance, vous pouvez même taper manuellement le nom de l'espace de noms (ou son URI) comme alternative à l'option getNamespaces() .

0 votes

Pour une saisie plus facile, l'astuce consiste à convertir en objet, c'est-à-dire $ns = (object) $xml->getNamespaces(true); alors vous pourriez utiliser ceci comme $sessionKey = $skey->children($ns->event)->sessionKey;

8voto

Asad Points 22968

Une autre approche consiste à utiliser SimpleXML pour l'analyse syntaxique et DOMDocument pour la manipulation/l'accès, ce qui permet de contourner complètement les problèmes d'espacement des noms :

$xml = new SimpleXMLElement($r);
$xml = dom_import_simplexml($xml);
$nodelist= $xml->getElementsByTagName('event');  
for($i = 0; $i < $nodelist->length; $i++) {
    $sessions = $nodelist->item($i)->getElementsByTagName('sessionKey');
    echo $sessions->item(0)->nodeValue;
}

5voto

Raf Points 359

Utilisation de registerXPathNamespace et ensuite appeler xpath n'a pas vraiment fonctionné pour moi. J'ai dû opter pour la solution proposée dans cet excellent article : http://blog.preinheimer.com/index.php?/archives/172-SimpleXML,-Namespaces-Hair-loss.html

Donc dans votre cas, ceci :

echo $xml->children('http://www.webex.com/schemas/2002/06/service/event')->sessionName;

La sortie est prévue :

Apprenez QB en quelques minutes

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X