使用simpleXML从XML文件中提取HTML

时间:2011-01-20 18:08:00

标签: php html xml simplexml

我正在阅读由第三方应用程序生成的xml文件,其中包含以下内容:

<Cell>
    <Comment ss:Author="Mark Baker">
        <ss:Data xmlns="http://www.w3.org/TR/REC-html40"><B><Font html:Face="Tahoma" html:Size="8" html:Color="#000000">Mark Baker:</Font></B><Font html:Face="Tahoma" html:Size="8" html:Color="#000000">&#10;Comment 1 - No align</Font></ss:Data>
    </Comment>
</Cell>

我要做的是从Cell-&gt; Comment-&gt;数据元素中“原样”或作为(X)HTML标记的实际块(最好是后者)访问原始数据。 / p>

if (isset($cell->Comment)) {
    echo 'comment found<br />';
    $commentAttributes = $cell->Comment->attributes($namespaces['ss']);
    if (isset($commentAttributes->Author)) {
        echo 'Author: ',(string)$commentAttributes->Author,'<br />';
    }
    $commentData = $cell->Comment->children($namespaces['ss']);
    var_dump($commentData);
    echo '<br />';
}

给了我:

comment found
Author: Mark Baker
object(SimpleXMLElement)#130 (2) { ["@attributes"]=> array(1) { ["Author"]=> string(10) "Mark Baker" } ["Data"]=> object(SimpleXMLElement)#129 (0) { } } 

,而

if (isset($cell->Comment)) {
    echo 'comment found<br />';
    $commentAttributes = $cell->Comment->attributes($namespaces['ss']);
    if (isset($commentAttributes->Author)) {
        echo 'Author: ',(string)$commentAttributes->Author,'<br />';
    }
    $commentData = $cell->Comment->Data->children();
    var_dump($commentData);
    echo '<br />';
}

给了我:

comment found
Author: Mark Baker
object(SimpleXMLElement)#129 (2) { ["B"]=> object(SimpleXMLElement)#118 (1) { ["Font"]=> string(11) "Mark Baker:" } ["Font"]=> string(21) " Comment 1 - No align" } 

不幸的是,simpleXML似乎将整个元素视为一系列XML节点。我确信我应该能够在没有复杂循环的情况下获得原始数据,或者将元素提供给DOM Parser;也许使用xmlns =“http://www.w3.org/TR/REC-html40”命名空间来干净地提取它,但我无法弄清楚如何。

任何帮助表示感谢。

更复杂的XML数据示例:

<Cell>
    <Comment ss:Author="Mark Baker">
        <ss:Data xmlns="http://www.w3.org/TR/REC-html40">
            <B><Font html:Face="Tahoma" html:Size="8" html:Color="#000000">Mark Baker:</Font></B><Font html:Face="Tahoma" html:Size="8" html:Color="#000000">&#10;</Font><B><Font html:Face="Tahoma" x:Family="Swiss" html:Size="8" html:Color="#000000">Rich </Font><U><Font html:Face="Tahoma" x:Family="Swiss" html:Size="8" html:Color="#FF0000">Text </Font></U><Font html:Face="Tahoma" x:Family="Swiss" html:Size="8" html:Color="#000000">Comment</Font></B><Font html:Face="Tahoma" html:Size="8" html:Color="#000000"> Center Aligned</Font>
        </ss:Data>
    </Comment>
</Cell>

4 个答案:

答案 0 :(得分:2)

如果您的实施是使用DOM,我相信您可以执行以下操作:

//given $node is <ss:data>

$frag = $node->ownerDocument->createDocumentFragment();
foreach($node->childNodes as $child){
    $frag->appendChild($child->cloneNode(true));
}
$string = $node->ownerDocument->saveXML($frag);

答案 1 :(得分:1)

如果<ss:Data>元素中的HTML被视为字符串文字,则必须将其包含在CDATA section中,如评论中已经暗示的那样

$xml = <<< XML
<Cell>
    <Comment ss:Author="Mark Baker">
        <ss:Data xmlns="http://www.w3.org/TR/REC-html40">
            <![CDATA[
                <B><Font html:Face="Tahoma" … html:Color="#000000">
            ]]>
        </ss:Data>
    </Comment>
</Cell>
XML;
libxml_use_internal_errors(TRUE);
$cell = simplexml_load_string($xml);
echo $cell->Comment->Data;

如果它不在CDATA部分,它将被视为节点。然后你将寻找<ss:Data>的innerXml来将其作为原始XML。不幸的是,SimpleXml和DOM都没有本地方式直接获取它。您必须使用userland实现。

innerXml的Userland实现通常迭代所有子节点并连接其原始XML。或者他们转储整个树和字符串替换根节点。或者他们创建一个片段或将节点导入另一个文档。

我不知道有任何其他方法可以做到这一点。不确定XSLT是否可行。 XMLReader虽然有readInnerXML方法。

答案 2 :(得分:0)

我暂时用一个快速而肮脏的解决方案。从长远来看,我将切换到使用XMLReader(由于上述所有原因)......我现在没有时间重写所有现有的simpleXML代码。

我已经离开了:

$node = $cell->Comment->Data->asXML();
$comment = substr($node,49,-10);
$comment = strip_tags($comment);

虽然我更喜欢保留HTML标记,但这需要额外的工作,所以我只是剥离所有标记,留下纯文本(这是关键元素)。

虽然这是一个远非完美的解决方案,但它完成了我需要它做的事情(暂时),我可以转到我的“待办事项”列表中的下一个项目,已经添加了一个新项目“使用XMLReader重写”到该列表。

感谢您的帮助。当我进行重写时,我一定会重新访问这个帖子。

答案 3 :(得分:0)

所以我知道你的问题已经过去了,但我遇到了同样的问题,我不得不弄清楚我是如何处理它的。对于后代,我就是这样做的。

如果您只接受(x)HTML:

$data = str_replace('<?xml version="1.0"?>','',$xmlNode->asXML());

如果您认为有人会使用XML并且您可以使用它,那么您只需要删除第一个自动生成的XML标记:

$data = preg_replace('/^<\?xml version="1.0"\?\>\n/', '',$xmlNode->asXML());

所以你的代码看起来像这样:

if (isset($cell->Comment)) {
    echo 'comment found<br />';
    $commentAttributes = $cell->Comment->attributes($namespaces['ss']);
    if (isset($commentAttributes->Author)) {
        echo 'Author: ',(string)$commentAttributes->Author,'<br />';
    }
    $commentData = str_replace('<?xml version="1.0"?>','',$cell->Comment->Data->asXML());
    echo $commentData;
    echo '<br />';
}