Вопрос

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

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

Итак, я хочу получить строку "Кто, кто, <strong>кто, кто</strong>, <em>я</em>".

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

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

Это было полезно?

Решение

Насколько мне известно, встроенного способа получить это не существует.Я бы рекомендовал попробовать Простой мир, который представляет собой класс 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 к a DOMNode затем зациклите его childNodes для создания XML-файла.Другим было бы позвонить asXML() затем используйте строковые функции для удаления корневого узла.Внимание, однако, asXML() иногда может возвращать разметку, которая на самом деле снаружи узла, с которого он был вызван, например, XML prolog или Инструкции по обработке.

Другие советы

function SimpleXMLElement_innerXML($xml)
  {
    $innerXML= '';
    foreach (dom_import_simplexml($xml)->childNodes as $child)
    {
        $innerXML .= $child->ownerDocument->saveXML( $child );
    }
    return $innerXML;
  };

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

echo (string)$qa->answer;

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

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

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

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

Если вы не хотите удалять раздел 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);
}

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

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

используя регулярное выражение, вы могли бы сделать это

preg_match(’/<answer(.*)?>(.*)?<\/answer>/’, $xml, $match);
$result=$match[0];
print_r($result);
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top