2009-02-27 24 views
45

Tengo esto como xml:analizar XML con espacio de nombres utilizando 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> 

¿Cómo puedo recorrer todos de la prueba: los nodos de eventos y la pantalla, por ejemplo, todo el evento: SessionKey de?

Esto no funciona:

$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

Esto podría ayudar http://www.lornajane.net/posts/2010/Fetching-Namespaced-XML-Elements-With-SimpleXML –

+1

* no funciona * es y nunca fue una descripción de error adecuado.PHP le da el siguiente error: * "Advertencia: SimpleXMLElement :: xpath(): prefijo de espacio de nombre no definido" *. Si desarrolla software, debería escuchar las advertencias de PHP. Ver también: [¿Cómo obtener mensajes de error útiles en PHP?] (Http://stackoverflow.com/q/845021/367456) – hakre

Respuesta

-3

puedo estar equivocado, pero no creo XML con el símbolo de colon, como el jabón se puede analizar adecuadamente usando SimpleXMLElement.

Estoy seguro de que hay una forma más elegante de hacerlo, pero normalmente leo los contenidos del archivo en una variable usando file_get_contents() y luego sustituyo/quito los dos puntos y luego lo envío al SimpleXMLElement.

+0

En realidad, hay algo de apoyo para el espaciado de nombres: http://us.php.net/ manual/es/function.simplexml-element-registerXPathNamespace.php Y soy consciente de que los espacios de nombres se pueden eliminar así: $ namespaceFree = preg_replace ('/ ([<< \ /]) ([a-z0- 9] +):/i ',' $ 1 $ 2 ', $ xml); Estoy buscando una solución mejor. – user38968

+8

Gente. Por favor. No use expresiones regulares u otras manipulaciones de cadenas cuando trabaje con datos XML. Las posibilidades de romper algo (por ejemplo, la "X" de XML (para "extensible")) son simplemente demasiado altas. – scy

24

que funciona sin registerXPathNamespace y el prefijo de espacio de nombres completo en las consultas XPath:

$xml = new SimpleXMLElement($r); 

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

Sí, funciona como un encanto! –

+6

Sí y no, en realidad considero esto un error. PHP registra automáticamente los espacios de nombres del contexto actual. Esto incluso anula espacios de nombres que usted mismo registra. Basas tu fuente en los prefijos utilizados en el documento que cargaste. Una fuente externa sobre la que no tienes control. Prefijos que son opcionales, ambiguos y pueden cambiar en cualquier momento. Los espacios de nombres están definidos, únicos y estables, los prefijos/alias no lo son. – ThW

20

tiene que registrar el espacio de nombres para cada objeto, se utiliza SimpleXMLElement.

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

El espacio de nombre también debe declararse en algún lugar del archivo xml.

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

El método ax descrito también funciona. Puede omitir el registerXPathNamespace si sabe que el archivo xml siempre usará el mismo prefijo.

6

Otro enfoque es utilizar SimpleXML de análisis y DOMDocument para manipulación/acceso, que omite por completo los problemas de espacio de nombres:

$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

aquí alternativa que funcionó para mí.

$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

El truco es usar 'children()' con al menos su primer parámetro. Si conoce la estructura del documento de antemano, incluso puede escribir el nombre del espacio de nombres (o su URI) manualmente como una alternativa a 'getNamespaces()'. –

2

Habiendo trabajado mucho con simplexml, así es como lo hago.

El truco de magia si ya tiene un elemento y sólo quiere obtener sus diferentes hijos de espacios de nombres, digamos por una estructura como esta:

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

es enviar verdadero como el segundo parámetro a la función de los niños:

$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

Para mí la mejor respuesta. Simple y efectivo! – Grzegorz

Cuestiones relacionadas