PHP的SimpleXML获取innerXML

我需要得到这个XML位的answer的HTML内容:

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

所以我想得到一个string“谁,谁</ strong>,我的</ em>”。

如果我的answer是一个SimpleXMLElement ,那么我可以调用asXML()来获得<<谁>,<谁> </ strong>,<em> </ em> </ answer>获取元素的内部XML而不包含元素本身?

我宁愿不涉及string函数的方法,但如果这是唯一的方法,那就这样吧。

据我所知,没有内置的方法来获得。 我build议尝试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来构buildXML。 另一个将调用asXML()然后使用string函数来删除根节点。 注意, asXML()有时可能返回标记,它实际上是从它被调用的节点之外的,比如XML prolog或Processing Instructions。

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

这工作(虽然看起来真的很蹩脚):

 echo (string)$qa->answer; 

最直接的解决scheme是实现自定义获取简单的XML的innerXML:

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

在你的代码中,replace$body_content = $el->asXml(); with $body_content = simplexml_innerXML($el);

但是,您也可以切换到另一个API,它提供了innerXML(您正在查找的内容)和outerXML(您现在得到的内容)之间的区别。 微软Dom库提供了这种区别,但不幸的是PHP的DOM不。

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

最后,我要强调的是,XML并不意味着将数据作为子树提取,而是作为价值。 这就是为什么你遇到麻烦find正确的API。 将HTML子树存储为一个值(而不是所有的标签)而不是XML子树会更“标准化”。 另外请注意,一些HTML合成器并不总是与XML兼容(即
vs,
)。 无论如何,在实践中,你的做法绝对是更方便的编辑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>")); ?> 

我search一段时间后,我没有得到满意的解决scheme。 所以我写了自己的function。 这个函数将得到确切的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:)

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

使用正则expression式,你可以做到这一点

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