Supongamos que tengo esto en un archivo llamado data.xml:
<?xml version="1.0"?> <stats> <data1>lorem</data1> <data2>ipsum</data2> <source mount="/mno"> <thing>1.0</thing> <somethingelse>10</somethingelse> <important>12345</important> <more>word</more> </source> <source mount="/pqr"> <thing>1.0</thing> <somethingelse>10</somethingelse> <important>23456</important> <more>word</more> </source> <source mount="/stu"> <thing>1.0</thing> <somethingelse>10</somethingelse> <important>34567</important> <more>word</more> </source> <source mount="/vwx"> <thing>1.0</thing> <somethingelse>10</somethingelse> <important>45678</important> <more>word</more> </source> </stats> Ahora necesito extraer el contenido específicamente del elemento <important> que está debajo de <source mount="/stu"> y mostrarlo en una página web. Descubrí que puedo hacer eso así:
<?php $xml=simplexml_load_file("data.xml") or die("Error: Cannot create object"); echo $xml->source[3]->important; ?> Esto realmente funciona. Lo que hago aquí es ir a la tercera <source> que resulta ser la que necesito. Sin embargo... El contenido del XML puede (y lo hará) cambiar, y cuando eso suceda, <source mount="/stu"> puede que ya no sea el tercero, lo que significa que la salida ya no será la del específico elemento que necesito aquí.
¿Cómo lo hago para que siempre muestre el contenido de <important> de específicamente <source mount="/stu"> , incluso si cambia la cantidad de elementos en el XML?
Me dijeron que XPATH podría ser el camino a seguir, pero la codificación no es mi profesión, y me resulta difícil entenderlo... También he estudiado algunas otras preguntas relacionadas con XML aquí en StackOverflow, pero mi novato el cerebro no entiende cómo aplicarlos a mi situación. Así que cualquier consejo sería bienvenido aquí. ¿Es XPATH realmente una buena idea? Si es así, ¿cómo implemento/uso eso aquí? ¿O hay otras/mejores formas de hacer esto?
Muchas gracias.
Una forma es que puede recorrer todo $xml->source y salir del ciclo cuando el valor es important , como usar un ciclo foreach:
<?php $xml=simplexml_load_file("data.xml") or die("Error: Cannot create object"); foreach($xml->source as $source){ if($source['mount'] == '/stu'){ echo $source->important; break; } } ?>El uso de DOMDocument y DOMXPath hace que la tarea de recuperar nodos particulares desde un archivo XML simple como este sea bastante sencilla.
El XML publicado contenía errores con las etiquetas de data como se mencionó; estos fueron detectados por libxml ya que tiene sus propias rutinas de manejo de errores.
$xml='<stats> <data1>lorem</data1> <data2>ipsum</data2> <source mount="/mno"> <thing>1.0</thing> <somethingelse>10</somethingelse> <important>12345</important> <more>word</more> </source> <source mount="/pqr"> <thing>1.0</thing> <somethingelse>10</somethingelse> <important>23456</important> <more>word</more> </source> <source mount="/stu"> <thing>1.0</thing> <somethingelse>10</somethingelse> <important>34567</important> <more>word</more> </source> <source mount="/vwx"> <thing>1.0</thing> <somethingelse>10</somethingelse> <important>45678</important> <more>word</more> </source> </stats>'; libxml_use_internal_errors( true ) ; $dom=new DOMDocument(); $dom->validateOnParse=false; $dom->recover=true; $dom->strictErrorChecking=false; $dom->loadXML( $xml ); $errors=libxml_get_errors(); $xp=new DOMXPath( $dom ); if( $xp ){ $expr='//source[@mount="/stu"]/important'; $col=$xp->query( $expr ); if( $col && $col->length > 0 )echo $col->item(0)->nodeValue; } La expresión XPath $expr='//source[@mount="/stu"]/important'; dice que busque cualquier nodo de source que tenga un mount de atributo que sea exactamente igual a la cadena deseada /stu ; se puede hacer una combinación de nodos y atributos considerablemente más compleja que esto.
Esto da como resultado:
34567Con XPath, describe lo que desea seleccionar. Comenzando desde la parte superior del documento en el "nodo raíz" con / y luego "camine" hacia abajo por los niveles del árbol con cada "paso".
Si está buscando todos los elementos important que son hijos de elementos de source , que son hijos de stats :
/stats/source/important O puede buscar elementos important en cualquier lugar, en cualquier nivel dentro del documento con:
//important Y si solo desea el elemento important que es un elemento secundario de la source con el atributo mount="/stu" :
/stats/source[@mount="/stu"]/importantAplicado:
$result = $xml->xpath('/stats/source[@mount="/stu"]/important'); foreach ($result as $important){ echo '/stats/source[@mount="/stu"]/important: ', $important, "\n"; }