2009-12-20 5 views
8

je dois obtenir le contenu HTML de answer dans ce bit XML:PHP SimpleXML obtenir InnerXml

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

Je veux obtenir la chaîne « Qui qui, <fort> qui qui </strong >, <em> moi </em > ".

Si je le answer comme SimpleXMLElement, je peux appeler asXML() pour obtenir "< réponse > Qui qui, <fort> qui qui </strong >, <em> me </em > </réponse >", mais comment obtenir le XML interne d'un élément sans que l'élément lui-même ne l'entoure?

Je préférerais des manières qui n'impliquent pas des fonctions de chaîne, mais si c'est la seule manière, ainsi soit-il.

Répondre

5

Au meilleur de ma connaissance, il n'y a pas intégré de manière à obtenir. Je recommande d'essayer SimpleDOM, qui est une classe PHP qui étend SimpleXMLElement qui offre des méthodes de commodité pour la plupart des problèmes courants.

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

Sinon, je vois deux façons de le faire. Le premier serait de convertir votre SimpleXMLElement en un DOMNode puis de boucler sur son childNodes pour générer le XML. L'autre serait d'appeler asXML() puis d'utiliser des fonctions de chaîne pour supprimer le nœud racine. Attention cependant, asXML() peut parfois renvoyer un balisage qui est réellement en dehors de du nœud à partir duquel il a été appelé, tel que le prologue XML ou les instructions de traitement.

-2

utilisant l'expression rationnelle, vous pouvez le faire

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

C'est certainement le mauvais cas d'utilisation pour regex. On ne devrait jamais l'utiliser pour l'analyse xml/dom. ne pas parler de ce $ match [0] contient toujours le texte complet à rechercher. Et $ xml est un objet, pas une chaîne. –

5

Cela fonctionne (bien qu'il semble vraiment boiteux):

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

Pas boiteux du tout! m'a sauvé de jongler xml à plusieurs variables. J'ai vu lamer;) – rvdavid

4

solution consiste à mettre en œuvre se mesure InnerXml XML simple, la plus simple:

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

Dans votre code, remplacez $body_content = $el->asXml(); avec $body_content = simplexml_innerXML($el);

Cependant, vous pouvez également passer à une autre API qui offre une distinction entre innerXML (ce que vous cherchez) et outerXML (ce que vous obtenez pour l'instant). Microsoft Dom libary offre cette distinction, mais PHP DOM ne le fait malheureusement pas.

J'ai trouvé que PHP XMLReader API offre cette distintion. Voir readInnerXML(). Bien que cette API a une approche assez différente pour le traitement XML. Essayez-le.

Enfin, je voudrais souligner que XML n'est pas destiné à extraire des données en tant que sous-arbres mais plutôt en tant que valeur. C'est pourquoi vous avez des problèmes pour trouver la bonne API. Il serait plus «standard» de stocker sous-arbre HTML comme une valeur (et échapper toutes les balises) plutôt que sous-arborescence XML. Gardez également à l'esprit que certains synthax HTML ne sont pas toujours compatibles avec XML (c'est-à-dire
vs,
). Quoi qu'il en soit, en pratique, vous approchez certainement plus pratique pour éditer le fichier xml.

+0

Merci pour cela, un problème cependant, l'exemple de code est légèrement brisé, $ noeud n'est pas défini. –

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

Après je recherche pendant un certain temps, je me suis pas de solution satisfaire. J'ai donc écrit ma propre fonction. Cette fonction obtiendra exactement le contenu innerXml (y compris les espaces blancs, bien sûr). Pour l'utiliser, transmettez le résultat de la fonction asXML(), comme ceci getInnerXml($e->asXML()). Cette fonction fonctionne aussi bien pour les éléments avec beaucoup de préfixes (comme mon cas, car je n'ai pas trouvé de méthodes courantes qui effectuent la conversion sur tous les nœuds fils de préfixes différents).

Sortie:

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

j'aurais étendre 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()); 
    } 
} 

puis l'utiliser comme ceci:

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 vous n'êtes pas vouloir enlever la section CDATA, commenter les lignes 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

Vous pouvez simplement utiliser cette fonction :)

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