2009-12-20 24 views
8

Potrzebuję uzyskać zawartość HTML z answer w tym kawałku XML:PHP SimpleXML dostać innerXML

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

Więc chcę uzyskać ciąg „Kto, kto, <silny> kto kto </strong >, <em> mi </em > ".

Jeśli mam answer jako SimpleXMLElement, mogę zadzwonić asXML() dostać "< odpowiedź > Kto którzy <silny> kto kto </strong >, < opinię > mi </em > </odpowiedź >" ale jak uzyskać wewnętrzny XML elementu bez samego owiniętego wokół niego elementu?

Wolałbym sposoby, które nie obejmują funkcji łańcuchowych, ale jeśli to jedyny sposób, niech tak będzie.

Odpowiedz

5

do mojej najlepszej wiedzy, nie jest wbudowana w sposób, aby ta. Polecam wypróbowanie SimpleDOM, która jest klasą PHP rozszerzającą SimpleXMLElement, która oferuje wygodę dla większości typowych problemów.

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

W przeciwnym razie widzę dwa sposoby na zrobienie tego. Pierwszym z nich byłoby przekonwertowanie twojej SimpleXMLElement na DOMNode, a następnie na jej childNodes, aby zbudować XML. Drugim byłoby wywołanie asXML(), a następnie użycie funkcji łańcuchowych do usunięcia węzła głównego. Uwaga jednak, asXML() może czasem zwracać znacznik, który w rzeczywistości jest poza węzła, z którego został wywołany, na przykład prolog XML lub instrukcje przetwarzania.

-2

użyciu regex można zrobić to

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

To jest zdecydowanie błędne użycie przypadku regex. Nigdy nie należy go używać do parsowania xml/dom. nie mówiąc o tym, że $ match [0] zawsze zawiera pełny tekst do przeszukania. A $ xml to obiekt, a nie ciąg znaków. –

5

To działa (choć wydaje się naprawdę lame):

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

W ogóle nie jest kulawy! uratował mnie od żonglowania xml do kilku zmiennych. Widziałem lamer;) – rvdavid

4

rozwiązaniem najprostszym jest wdrożenie niestandardowych dostać innerXML z prostego XML:

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

w kodzie, wymienić $body_content = $el->asXml(); z $body_content = simplexml_innerXML($el);

Można jednak przełączyć się na inny interfejs API oferujący rozróżnienie między innerXML (czego szukasz) i outerXML (co otrzymasz na razie). Microsoft Dom libary oferuje to rozróżnienie, ale niestety PHP DOM tego nie robi.

Znalazłem, że PHP XMLReader API oferuje tę dziedzinę. Zobacz readInnerXML(). Chociaż ten interfejs API ma całkiem inne podejście do przetwarzania XML. Spróbuj.

Na koniec chciałbym podkreślić, że XML nie ma na celu wyodrębniania danych jako poddrzewa, ale raczej jako wartość. Właśnie dlatego masz problem ze znalezieniem odpowiedniego API. Byłoby bardziej "standardowe" przechowywanie poddrzewa HTML jako wartości (i uniknięcia wszystkich znaczników), a nie podtekstu XML. Należy również pamiętać, że niektóre syntaktypy HTML nie zawsze są kompatybilne z XML (tj.
vs,
). W każdym razie w praktyce podejście jest zdecydowanie wygodniejsze przy edycji pliku xml.

+0

Dzięki temu, jeden problem, chociaż przykład kodu jest lekko uszkodzony, węzeł $ nie jest zdefiniowany. –

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

Po szukać jakiś czas, mam żadnego rozwiązania zadowolić. Więc napisałem swoją własną funkcję. Ta funkcja sprawi, że zawartość będzie dokładnie zgodna z innerXml (w tym z białą spacją). Aby z niego skorzystać, należy podać wynik funkcji asXML(), taki jak ten getInnerXml($e->asXML()). Ta funkcja działa również dla elementów z wieloma prefiksami (jak w moim przypadku, ponieważ nie mogłem znaleźć żadnych aktualnych metod, które dokonują konwersji we wszystkich węzłach potomnych różnych prefiksów).

wyjściowa:

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

musiałbym rozszerzyć klasę 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()); 
    } 
} 

a następnie używać go tak:

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

Jeśli nie chcesz usunąć sekcję CDATA, skomentować linie 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

można po prostu użyć tej funkcji :)

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