2009-02-27 8 views
45

ho questo come xml:Parse XML con Namespace usando SimpleXML

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

come posso il ciclo di tutti della manifestazione: i nodi di eventi e di visualizzazione, per esempio, tutti della manifestazione: SessionKey di?

Questo non funziona:

$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

Questo potrebbe aiutare http://www.lornajane.net/posts/2010/Fetching-Namespaced-XML-Elements-With-SimpleXML –

+1

* non funziona * è e non è mai stato una descrizione d'errore.PHP ti dà il seguente errore: * "Avviso: SimpleXMLElement :: xpath(): prefisso spazio dei nomi non definito" *. Se sviluppi software, dovresti ascoltare gli avvertimenti di PHP. Vedi anche: [Come ottenere utili messaggi di errore in PHP?] (Http://stackoverflow.com/q/845021/367456) – hakre

risposta

-3

potrei sbagliarmi, ma non credo di XML con il simbolo del colon come il sapone può essere analizzato correttamente utilizzando SimpleXMLElement.

Sono sicuro che c'è un modo più elegante di fare questo, ma io di solito leggere il contenuto del file in una variabile utilizzando file_get_contents() quindi sostituire/rimuovere i due punti poi inviarlo a SimpleXMLElement.

+0

In realtà, c'è un po 'di supporto per il namespace: http://us.php.net/ manuale/it/function.simplexml-element-registerXPathNamespace.php E sono consapevole che i namespace possono essere rimossi in questo modo: $ namespaceFree = preg_replace ('/ ([<< \ /]) ([a-z0- 9] +):/i '' $ 1 $ 2 ', $ xml); Sto solo cercando una soluzione migliore. – user38968

+8

persone. Per favore. Non utilizzare espressioni regolari o altre manipolazioni di stringhe quando si lavora con dati XML. Le possibilità di rompere qualcosa (ad esempio, XML "X" (per "estensibile")) sono semplicemente troppo alte. – scy

24

lo fa lavoro senza registerXPathNamespace e il prefisso dello spazio dei nomi completo nelle query XPath:

$xml = new SimpleXMLElement($r); 

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

Sì, funziona come un fascino! –

+6

Sì e no, in realtà considero questo un bug. PHP registra automaticamente gli spazi dei nomi del contesto corrente. Questo sovrascrive anche gli spazi dei nomi che ti registri. Basi la tua fonte sui prefissi usati nel documento che stai caricando. Una fonte esterna su cui non hai controllo. Prefissi che sono opzionali, ambigui e possono cambiare in qualsiasi momento. I namespace sono definiti, unici e stabili - i prefissi/alias no. – ThW

20

È necessario registrarsi lo spazio dei nomi per ogni SimpleXMLElement oggetto che si usa.

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

Lo spazio dei nomi dovrebbe anche essere dichiarato da qualche parte nel file xml.

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

Anche l'ascia del metodo descritto funziona. Puoi saltare il registroXPathNamespace se sai che il file xml userà sempre lo stesso prefisso.

6

Un altro approccio è quello di utilizzare SimpleXML per parsing e DOMDocument per manipolazione/accesso, che ignora del tutto i problemi di namespacing:

$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; 
} 
11

qui alternativa che ha funzionato per me.

+0

Il trucco sta usando 'children()' con almeno il suo primo parametro. Se conosci in anticipo la struttura del documento, puoi anche digitare manualmente il nome dello spazio dei nomi (o il relativo URI) come alternativa a 'getNamespaces()'. –

2

Dopo aver lavorato molto con simplexml, questo è il modo in cui lo faccio.

Il trucco magico se si dispone già di un elemento e desidera ottenere è diverso bambini namespace, diciamo per una struttura come questa:

<entry> 
<title type="text">My test entry</title> 
<gd:when startTime="2017-02-26T02:00:00Z" endTime="2017-02-26T03:00:00Z"/> 
<gc:notes type="string">A type</gc:notes> 
</entry> 

è quello di inviare vero come secondo parametro alla funzione figli:

$title = (string) $entry->title; 
    $gd = $entry->children('gd', TRUE); 
    $attrs = $gd->when->attributes(); 
    $startTime = (string) $attrs->startTime; 
    $gc = $entry->children('gc', TRUE); 
    $notes = (string) $gc->notes(); 
+0

Per me la migliore risposta. Semplice ed efficace! – Grzegorz