2009-12-20 33 views
8

que necesito para obtener el contenido HTML de answer en este poco de XML:PHP SimpleXML obtener InnerXml

<qa> 
<question>Who are you?</question> 
<answer>Who who, <strong>who who</strong>, <em>me</em></answer> 
</qa> 

por lo que quiero obtener la cadena "¿Quién que, <fuerte> que quien </strong >, <em> me </em > ".

Si tengo el answer como SimpleXMLElement, puedo llamar a asXML() para conseguir "<respuesta> Quién que, <fuerte> que quien </strong >, <em> me </em > </respuesta >", pero, ¿cómo obtener el XML interno de un elemento sin el elemento envuelto alrededor de él?

Preferiría formas que no impliquen funciones de cadena, pero si esa es la única manera, que así sea.

Respuesta

5

A lo mejor de mi conocimiento, no está incorporado manera de conseguir eso. Recomiendo probar SimpleDOM, que es una clase PHP que extiende SimpleXMLElement que ofrece métodos de conveniencia para la mayoría de los problemas comunes.

include 'SimpleDOM.php'; 

$qa = simpledom_load_string(
    '<qa> 
     <question>Who are you?</question> 
     <answer>Who who, <strong>who who</strong>, <em>me</em></answer> 
    </qa>' 
); 
echo $qa->answer->innerXML(); 

De lo contrario, veo dos maneras de hacerlo. La primera sería convertir su SimpleXMLElement en DOMNode y luego recorrer su childNodes para compilar el XML. El otro sería llamar al asXML() y luego usar las funciones de cadena para eliminar el nodo raíz. Sin embargo, a veces, el asXML() puede devolver el marcado que en realidad es fuera del del nodo desde el que se invocó, como el prólogo XML o las Instrucciones de procesamiento.

-2

usando expresiones regulares se podía hacer esto

preg_match(’/<answer(.*)?>(.*)?<\/answer>/’, $xml, $match); 
$result=$match[0]; 
print_r($result); 
+0

Este es sin duda el caso de uso incorrecto de expresiones regulares. Uno nunca debería usarlo para el análisis xml/dom. sin mencionar que $ match [0] siempre contiene el texto completo para buscar. Y $ xml es un objeto, no una cadena. –

5

Esto funciona (aunque parece muy escaso):

echo (string)$qa->answer; 
+0

¡No es cojo en absoluto! me salvó de hacer malabarismos con xml a varias variables. He visto lamer;) – rvdavid

4

solución más sencilla consiste en aplicar personalizado Descarga InnerXml con XML simple:

function simplexml_innerXML($node) 
{ 
    $content=""; 
    foreach($node->children() as $child) 
     $content .= $child->asXml(); 
    return $content; 
} 

En su código, reemplace $body_content = $el->asXml(); con $body_content = simplexml_innerXML($el);

Sin embargo, también podría cambiar a otra API que ofrezca distinción entre innerXML (lo que está buscando) y outerXML (lo que obtienes por ahora). Microsoft Dom Libary ofrece esta distinción, pero lamentablemente PHP DOM no.

Encontré que PHP XMLReader API ofrece esta distinción. Ver readInnerXML(). Aunque esta API tiene un enfoque bastante diferente al procesamiento XML. Intentalo.

Por último, quiero resaltar que XML no pretende extraer datos como subárboles sino más bien como valor. Es por eso que tiene problemas para encontrar la API correcta. Sería más "estándar" almacenar el subárbol HTML como un valor (y escapar de todas las etiquetas) en lugar del subárbol XML. También tenga en cuenta que algunos sintetizadores HTML no siempre son compatibles con XML (es decir,
vs,
). De todos modos, en la práctica, su enfoque es definitivamente más conveniente para editar el archivo xml.

+0

Gracias por esto, un problema, el ejemplo del código está ligeramente roto, $ nodo no está definido. –

12
function SimpleXMLElement_innerXML($xml) 
    { 
    $innerXML= ''; 
    foreach (dom_import_simplexml($xml)->childNodes as $child) 
    { 
     $innerXML .= $child->ownerDocument->saveXML($child); 
    } 
    return $innerXML; 
    }; 
0
<?php 
    function getInnerXml($xml_text) {   
     //strip the first element 
     //check if the strip tag is empty also 
     $xml_text = trim($xml_text); 
     $s1 = strpos($xml_text,">");   
     $s2 = trim(substr($xml_text,0,$s1)); //get the head with ">" and trim (note that string is indexed from 0) 

     if ($s2[strlen($s2)-1]=="/") //tag is empty 
      return ""; 

     $s3 = strrpos($xml_text,"<"); //get last closing "<"   
     return substr($xml_text,$s1+1,$s3-$s1-1); 
    } 

    var_dump(getInnerXml("<xml />")); 
    var_dump(getInnerXml("<xml/>faf </xml>")); 
    var_dump(getInnerXml("<xml  ></xml>"));  
    var_dump(getInnerXml("<xml>faf </xml>")); 
    var_dump(getInnerXml("<xml > faf </xml>"));  
?> 

Después de que busco por un tiempo, no tengo solución de la satisfacción. Entonces escribí mi propia función. Esta función obtendrá exactamente el contenido innerXml (incluido el espacio en blanco, por supuesto). Para usarlo, pase el resultado de la función asXML(), como este getInnerXml($e->asXML()). Esta función también funciona para elementos con muchos prefijos (como en mi caso, ya que no pude encontrar ningún método actual que realice la conversión en todos los nodos secundarios de prefijos diferentes).

Salida:

string '' (length=0)  
string '' (length=0)  
string '' (length=0)  
string 'faf ' (length=4)  
string ' faf ' (length=6) 
1

me habría extender la clase SimpleXMLElement:

class MyXmlElement extends SimpleXMLElement{ 

    final public function innerXML(){ 
     $tag = $this->getName(); 
     $value = $this->__toString(); 
     if('' === $value){ 
      return null; 
     } 
     return preg_replace('!<'. $tag .'(?:[^>]*)>(.*)</'. $tag .'>!Ums', '$1', $this->asXml()); 
    } 
} 

y luego usarlo como esto:

echo $qa->answer->innerXML(); 
0
function get_inner_xml(SimpleXMLElement $SimpleXMLElement) 
    { 
     $element_name = $SimpleXMLElement->getName(); 
     $inner_xml = $SimpleXMLElement->asXML(); 
     $inner_xml = str_replace('<'.$element_name.'>', '', $inner_xml); 
     $inner_xml = str_replace('</'.$element_name.'>', '', $inner_xml); 
     $inner_xml = trim($inner_xml); 
     return $inner_xml; 
    } 
0

Si no lo hace quiere quitar la sección CDATA, comentar las líneas 6-8.

function innerXML($i){ 
    $text=$i->asXML(); 
    $sp=strpos($text,">"); 
    $ep=strrpos($text,"<"); 
    $text=trim(($sp!==false && $sp<=$ep)?substr($text,$sp+1,$ep-$sp-1):''); 
    $sp=strpos($text,'<![CDATA['); 
    $ep=strrpos($text,"]]>"); 
    $text=trim(($sp==0 && $ep==strlen($text)-3)?substr($text,$sp+9,-3):$text); 
    return($text); 
} 
0

Sólo puede utilizar esta función :)

function innerXML($node) 
{ 
    $name = $node->getName(); 
    return preg_replace('/((<'.$name.'[^>]*>)|(<\/'.$name.'>))/UD', "", $node->asXML()); 
} 
Cuestiones relacionadas