PHP SimpleXML获取内部XML

11

我需要获取此 XML 片段中 answer 的 HTML 内容:

<qa>
 <question>Who are you?</question>
 <answer>Who who, <strong>who who</strong>, <em>me</em></answer>
</qa>
所以我想获得字符串"Who who, who who, me"。
如果我有一个SimpleXMLElement的答案,我可以调用asXML()来获取"Who who, who who, me",但如何获取一个元素内部没有元素标记包裹的XML内容呢?
我更喜欢不涉及字符串函数的方法,但如果那是唯一的方法,那就这样吧。
11个回答

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

太棒了,简单的解决方案! - Wes

6
这个方法虽然很简单,但确实可行:

echo (string)$qa->answer;

一点也不糟糕!它让我免去了将 XML 转换为多个变量的麻烦。 我见过更差的 ;) - Aries

5
据我所知,没有内置的方法可以获取那个。我建议尝试使用SimpleDOM,它是一个扩展了SimpleXMLElement的PHP类,提供了大多数常见问题的便利方法。
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 prolog或Processing Instructions。

4
最直接的解决方案是使用简单的XML实现自定义get innerXML:
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,该API提供了内部XML(您正在寻找的内容)和外部XML(您现在获得的内容)之间的区别。Microsoft Dom库提供了这种区别,但不幸的是PHP DOM没有。
我发现PHP XMLReader API提供了这种区分。请查看readInnerXML()。虽然这个API对处理XML有相当不同的方法。尝试一下。
最后,我要强调XML不是用来提取子树数据的,而是作为值。这就是为什么你遇到了找到正确API的麻烦。将HTML子树存储为值(并转义所有标记)而不是XML子树会更“标准”。此外,请注意,某些HTML语法并不总是与XML兼容(即
vs
)。但在实践中,你的方法肯定更方便编辑xml文件。

谢谢,不过有一个问题,代码示例有点问题,$node未定义。 - Brian Wigginton

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
<?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
    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
你可以直接使用这个函数 :)
function innerXML( $node )
{
    $name = $node->getName();
    return preg_replace( '/((<'.$name.'[^>]*>)|(<\/'.$name.'>))/UD', "", $node->asXML() );
}

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 InnerHTML($Text)
{   
    return SubStr($Text, ($PosStart = strpos($Text,'>')+1), strpos($Text,'<',-1)-1-$PosStart);
}

echo InnerHTML($yourXML->qa->answer->asXML());

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接