PHP SimpleXML获取innerXML

时间:2009-12-20 21:10:08

标签: php simplexml innerxml

我需要在这一段XML中获取answer的HTML内容:

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

所以我希望得到一个字符串“Who who,&lt; strong&gt; who who&lt; / strong&gt;,&lt; em&gt; me&lt; / em&gt;”。

如果我将answer作为SimpleXMLElement,我可以致电asXML()以获取“&lt; answer&gt;谁是谁,&lt; strong&gt;谁&lt; / strong&gt;,&lt; ; em&gt;我&lt; / em&gt;&lt; / answer&gt;“但是如何在没有元素本身的情况下获取元素的内部XML?

我更喜欢不涉及字符串函数的方法,但如果这是唯一的方法,那就这样吧。

11 个答案:

答案 0 :(得分:12)

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

答案 1 :(得分:6)

这有效(虽然看起来很蹩脚):

echo (string)$qa->answer;

答案 2 :(得分: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。

答案 3 :(得分: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,它可以区分innerXML(您正在寻找的内容)和outerXML(您现在获得的内容)。 Microsoft Dom libary提供了这种区别,但遗憾的是PHP DOM没有。

我发现PHP XMLReader API提供了这种区别。请参阅readInnerXML()。虽然这个API在处理XML方面有很多不同的方法。试试吧。

最后,我要强调的是,XML并不是要将数据提取为子树,而是将其作为值。这就是为什么你在找到合适的API时遇到麻烦的原因。将HTML子树存储为值(并转义所有标记)而不是XML子树将更“标准”。还要注意一些HTML synthax并不总是与XML兼容(即
vs,
)。无论如何,在实践中,你的方法对于编辑xml文件肯定更方便。

答案 4 :(得分: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();

答案 5 :(得分: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)

答案 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;
    }

答案 7 :(得分: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);
}

答案 8 :(得分:0)

您可以使用此功能:)

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

答案 9 :(得分:0)

这是我创建的一个非常快速的解决方案:

function InnerHTML($Text)
{   
    return SubStr($Text, ($PosStart = strpos($Text,'>')+1), strpos($Text,'<',-1)-1-$PosStart);
}

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

答案 10 :(得分:-2)

使用正则表达式,你可以这样做

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