2009-12-20 2 views
8

Мне нужно, чтобы получить HTML-содержимое answer в этом кусочке XML:PHP SimpleXML получить InnerXml

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

Так что я хочу, чтобы получить строку «Кто, кто, < сильный > кто, кто </сильный >, <em> me </em > ".

Если у меня есть answer как SimpleXMLElement, я могу назвать asXML(), чтобы получить "< ответ > Кто, кто, < сильный > кто, кто </сильный >, <EM> меня </эм > </ответ >", но как получить внутренний XML элемента без самого элемента, обернутого вокруг него?

Я бы предпочел способы, которые не включают строковые функции, но если это единственный способ, пусть будет так.

ответ

5

насколько мне известно, есть не встроенный способ, чтобы получить это. Я бы рекомендовал попробовать SimpleDOM, который является классом PHP, расширяющим SimpleXMLElement, который предлагает удобные методы для большинства распространенных проблем.

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

В противном случае я вижу два способа сделать это. Первым было бы преобразовать ваш SimpleXMLElement в DOMNode, а затем цикл над его childNodes для создания XML. Другим было бы позвонить asXML(), а затем использовать строковые функции для удаления корневого узла. Внимание, однако, asXML() может иногда возвращать разметку, которая на самом деле вне узла, из которого он был вызван, например, пролог XML или инструкции по обработке.

-2

с помощью регулярных выражений вы могли бы сделать это

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

Это, безусловно, неправильное использование случае регулярное выражение. Его нельзя использовать для анализа синтаксиса xml/dom. не говоря о том, что $ match [0] всегда содержит полный текст для поиска. И $ xml - это объект, а не строка. –

5

Это работает (хотя это, кажется, действительно хромает):

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

Не совсем хромой! спас меня от жонглирования xml до нескольких переменных. Я видел lamer;) – rvdavid

4

наиболее простым решением является реализация пользовательских получить InnerXml с простой XML:

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

В вашем коде замените $body_content = $el->asXml(); с $body_content = simplexml_innerXML($el);

Однако вы также можете переключиться на другой API, который предлагает различие между innerXML (то, что вы ищете) и outerXML (что вы получаете сейчас). Microsoft Dom libary предлагает это различие, но, к сожалению, PHP DOM этого не делает.

Я обнаружил, что PHP XMLReader API предлагает это задание. См. ReadInnerXML(). Хотя этот API имеет совершенно иной подход к обработке XML. Попробуй.

Наконец, я хотел бы подчеркнуть, что XML не предназначен для извлечения данных в виде поддеревьев, а скорее как значения. Вот почему вам сложно найти правильный API. Было бы более «стандартным» хранить HTML-поддерево как значение (и избегать всех тегов), а не поддерево XML. Также будьте осторожны, что некоторые синтаксисы HTML не всегда совместимы с XML (т. Е.
vs,
). Во всяком случае, на практике вы подходите, определенно, более удобно для редактирования xml-файла.

+0

Спасибо за это, один вопрос, хотя пример кода немного сломан, $ node не определен. –

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

После того как я искать какое-то время, я не получил никакого решения удовлетворять. Поэтому я написал свою собственную функцию. Эта функция получит точное содержимое innerXml (включая, конечно, пробелы). Чтобы использовать его, передайте результат функции asXML(), вот так getInnerXml($e->asXML()). Эта функция работает и для элементов со многими префиксами (как и в моем случае, поскольку я не мог найти какие-либо текущие методы, которые делают преобразование на всех дочерних узлах разных префиксов).

Выход:

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

Я бы расширить класс 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()); 
    } 
} 

, а затем использовать его как это:

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

Если вы не хотите снять секцию CDATA, прокомментировать строки 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

Вы можете просто использовать эту функцию :)

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