PHP SimpleXML получить innerXML - PullRequest
8 голосов
/ 21 декабря 2009

Мне нужно получить содержимое HTML answer в этом бите XML:

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

Итак, я хочу получить строку "Кто, кто, , кто, кто , , я ".

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

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

Ответы [ 10 ]

12 голосов
/ 20 августа 2011
function SimpleXMLElement_innerXML($xml)
  {
    $innerXML= '';
    foreach (dom_import_simplexml($xml)->childNodes as $child)
    {
        $innerXML .= $child->ownerDocument->saveXML( $child );
    }
    return $innerXML;
  };
6 голосов
/ 02 сентября 2010

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

echo (string)$qa->answer;
5 голосов
/ 21 декабря 2009

Насколько мне известно, нет встроенного способа получить это. Я бы порекомендовал попробовать 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 или Инструкции обработки.

4 голосов
/ 13 июня 2011

Самое простое решение - реализовать пользовательский get 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 (что вы ищете) и externalXML (что вы получаете сейчас). Библиотека Microsoft Dom предлагает это различие, но, к сожалению, PHP DOM этого не делает.

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

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

1 голос
/ 24 августа 2012

Я бы расширил класс 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 innerXML( $node )
{
    $name = $node->getName();
    return preg_replace( '/((<'.$name.'[^>]*>)|(<\/'.$name.'>))/UD', "", $node->asXML() );
}
0 голосов
/ 20 марта 2014

Если вы не хотите удалять раздел 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 голосов
/ 04 октября 2013
    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 голосов
/ 29 февраля 2012
<?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)
0 голосов
/ 21 декабря 2009

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

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