2009-12-20 19 views
8

ho bisogno di ottenere il contenuto HTML di answer in questo po 'di XML:PHP SimpleXML ottenere InnerXml

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

quindi voglio ottenere la stringa "Chi chi, <forte> che chi </strong >, <em> me </em > ".

Se ho la answer come SimpleXMLElement, posso chiamare asXML() per ottenere "<risposta> Chi che, <forte> che chi </strong >, <em> me </em > </risposta >", ma come ottenere l'XML interno di un elemento senza l'elemento stesso avvolto attorno ad esso?

Preferirei modi che non implichino funzioni di stringa, ma se questo è l'unico modo, così sia.

risposta

5

Al meglio della mia conoscenza, non v'è built-in modo per ottenere questo. Ti consigliamo di provare SimpleDOM, che è una classe PHP che estende SimpleXMLElement che offre metodi di convenienza per la maggior parte dei problemi comuni.

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(); 

Altrimenti, vedo due modi per farlo. Il primo sarebbe quello di convertire il tuo SimpleXMLElement in un DOMNode quindi passare il suo childNodes per creare l'XML. L'altro sarebbe chiamare asXML() quindi utilizzare le funzioni di stringa per rimuovere il nodo principale. Attenzione, tuttavia, asXML() potrebbe talvolta restituire markup che è in realtà all'esterno del del nodo da cui è stato chiamato, ad esempio XML prolog o Istruzioni di elaborazione.

-2

usando espressioni regolari si potrebbe fare questo

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

Questo è sicuramente il caso d'uso sbagliato per regex. Non si dovrebbe mai usarlo per l'analisi xml/dom. non parlare di quella $ match [0] contiene sempre il testo completo da cercare. E $ xml è un oggetto, non una stringa. –

5

Questo funziona (anche se sembra davvero zoppo):

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

Non per niente! mi ha salvato da giocoleria xml a diverse variabili. Ho visto lamer;) – rvdavid

4

soluzione più semplice è quella di implementare personalizzato ottenere InnerXml con semplice XML:

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

Nel codice, sostituire $body_content = $el->asXml(); con $body_content = simplexml_innerXML($el);

Tuttavia, è anche possibile passare a un'altra API che offre una distinzione tra innerXML (quello che stai cercando) e outerXML (cosa si ottiene per ora). La libreria Microsoft Dom offre questa distinzione ma sfortunatamente il DOM PHP non lo fa.

Ho trovato che PHP XMLReader API offre questa distinzione. Vedi readInnerXML(). Sebbene questa API abbia un approccio abbastanza diverso all'elaborazione di XML. Provalo.

Infine, vorrei sottolineare che XML non è inteso per estrarre i dati come sottoalberi ma piuttosto come valore. Ecco perché ti imbatti in problemi nella ricerca dell'API corretta. Sarebbe più "standard" memorizzare la sottostruttura HTML come valore (e sfuggire a tutti i tag) piuttosto che sottostruttura XML. Inoltre, fai attenzione che alcuni synthax HTML non sono sempre compatibili con XML (ad esempio
vs,
). Ad ogni modo, in pratica, l'approccio è decisamente più conveniente per la modifica del file xml.

+0

Grazie per questo, un problema però, l'esempio di codice è leggermente rotto, $ nodo non è definito. –

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>"));  
?> 

Dopo la ricerca di un po ', ho avuto alcuna soluzione di soddisfazione. Così ho scritto la mia funzione. Questa funzione otterrà esattamente il contenuto di innerXml (incluso lo spazio bianco, ovviamente). Per utilizzarlo, passa il risultato della funzione asXML(), come questo getInnerXml($e->asXML()). Questa funzione funziona anche per gli elementi con molti prefissi (come nel mio caso, poiché non sono riuscito a trovare alcun metodo corrente che faccia la conversione su tutti i nodi figlio di prefissi diversi).

uscita:

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

mi avrebbe estendere la classe 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()); 
    } 
} 

e quindi utilizzarlo in questo modo:

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

Se non lo fai desidera rimuovere la sezione CDATA, commentare le righe 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

Si può semplicemente utilizzare questa funzione :)

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