2011-02-27 7 views
5

Dado el código php:Conseguir la parte de texto de un nodo utilizando PHP XML simple

$xml = <<<EOF 
<articles> 
<article> 
This is a link 
<link>Title</link> 
with some text following it. 
</article> 
</articles> 
EOF; 

function traverse($xml) { 
    $result = ""; 
    foreach($xml->children() as $x) { 
     if ($x->count()) { 
      $result .= traverse($x); 
     } 
     else { 
      $result .= $x; 
     } 
    } 
    return $result; 
} 

$parser = new SimpleXMLElement($xml); 
traverse($parser); 

que esperaba el travesaño() para volver:

This is a link Title with some text following it. 

Sin embargo, se devuelve sólo:

Title 

¿Hay alguna manera de obtener el resultado esperado utilizando simpleXML (obviamente con el fin de consumir los datos en lugar de simplemente r eturning it como en este simple ejemplo)?

Gracias, N.

Respuesta

15

Puede haber maneras de lograr lo que desea utilizando sólo SimpleXML, pero en este caso, la forma más sencilla de hacerlo es usar DOM. La buena noticia es que si usted ya está usando SimpleXML, usted no tiene que cambiar nada como DOM y SimpleXML son basically interchangeable:

// either 
$articles = simplexml_load_string($xml); 
echo dom_import_simplexml($articles)->textContent; 

// or 
$dom = new DOMDocument; 
$dom->loadXML($xml); 
echo $dom->documentElement->textContent; 

Asumiendo que su tarea consiste en iterar sobre cada <article/> y obtener su contenido, su código se verá como

$articles = simplexml_load_string($xml); 
foreach ($articles->article as $article) 
{ 
    $articleText = dom_import_simplexml($article)->textContent; 
} 
+0

Esto realmente produce el resultado exacto que estaba esperando, sin resolver realmente el problema subyacente de atravesar el documento Xml. – Nikolaj

+1

No podrá "atravesar" o iterar sobre nodos de texto con SimpleXML. O al menos, será artificial/poco práctico si es posible. Use SimpleXML siempre que haga las cosas más fáciles, luego importe los nodos seleccionados a DOM para acceder a las funciones que no son parte de SimpleXML. –

+0

Sí, de hecho. Parece que tuve que aprenderlo de la manera difícil. – Nikolaj

1

Puede obtener el nodo de texto de un elemento DOM con simplexml simplemente tratándolo como una cadena:

foreach($xml->children() as $x) { 
    $result .= "$x" 

Sin embargo, esto imprime:

This is a link 

with some text following it. 
TitleTitle 

.. porque el nodo de texto se trata como un bloque y no hay forma de saber dónde encaja el elemento dentro del nodo de texto. El nodo hijo también se agrega dos veces debido a los demás {}, pero puedes eliminarlo.

Lo siento si no ayudé mucho, pero no creo que haya ninguna forma de averiguar dónde encaja el nodo secundario en el nodo de texto a menos que el xml sea coherente (pero entonces, ¿por qué no usar etiquetas?). Si sabe de qué elemento quiere quitar el texto, strip_tags() funcionará muy bien.

+0

Siempre es útil saber que lo que estamos tratando de lograr no sólo es posible. Desafortunadamente, no poseo el XML, entonces es lo que es. ¿Sabes si alguno de los otros analizadores en php son más adecuados para mi tarea? – Nikolaj

+0

No conozco ninguna existente ... ¡quizás podría escribir una! –

+0

Después de haber ladrado el árbol equivocado (¿analizador?) Durante bastante tiempo, parece que DOM es nuestro amigo necesitado a la hora de tratar con este tipo de XML. – Nikolaj

0

Como @tandu Dicho esto, no es posible, pero si se puede modificar el código XML, esto va a funcionar:

$xml = <<<EOF 
<articles> 
    <article> 
     This is a link 
    </article> 
    <link>Title</link> 
    <article> 
     with some text following it. 
    </article> 
</articles> 
3

Entonces, la respuesta simple a mi pregunta fue: Simplexml no puede procesar este tipo de XML. Use DomDocument en su lugar.

Este ejemplo muestra cómo recorrer todo el XML. Parece que DomDocument funcionará con cualquier XML, mientras que SimpleXML requiere que XML sea simple.

function attrs($list) { 
    $result = ""; 
    foreach ($list as $attr) { 
     $result .= " $attr->name='$attr->value'"; 
    } 
    return $result; 
} 

function parseTree($xml) { 
    $result = ""; 
    foreach ($xml->childNodes AS $item) { 
     if ($item->nodeType == 1) { 
      $result .= "<$item->nodeName" . attrs($item->attributes) . ">" . parseTree($item) . "</$item->nodeName>"; 
     } 
     else { 
      $result .= $item->nodeValue; 
     } 
    } 
    return $result; 
} 

$xmlDoc = new DOMDocument(); 
$xmlDoc->loadXML($xml); 

print parseTree($xmlDoc->documentElement); 

También puede cargar el código XML con SimpleXML y luego convertirlo a DOM utilizando dom_import_simplexml() como se dijo Josh. Esto sería útil si está utilizando simpleXml para filtrar nodos para el análisis sintáctico, p. usando XPath.

Sin embargo, en realidad no utilizo SimpleXML, por lo que para mí eso sería tomar el camino más largo.

$simpleXml = new SimpleXMLElement($xml); 
$xmlDom = dom_import_simplexml($simpleXml); 

print parseTree($xmlDom); 

¡Gracias por la ayuda!

4
node->asXML();// It's the simple solution i think !! 
+0

¿Has probado esto con los datos del OP? ¿realmente funciona? –

1

Esto ya ha sido contestada, pero conversión a String (es decir, $ sString = (cadena) oSimpleXMLNode-> TagName) siempre ha funcionado para mí.

+0

echo (cadena) $ xmlNode; –

0

Prueba esto:

$parser = new SimpleXMLElement($xml); 
echo strip_tags($parser->asXML()); 

Eso es más o menos equivalente a:

$parser = simplexml_load_string($xml); 
echo dom_import_simplexml($parser)->textContent; 
Cuestiones relacionadas