Simplexml:解析HTML会在带有文本节点的元素中留下嵌套元素

时间:2015-03-08 15:08:41

标签: php xml parsing html-parsing simplexml

我试图解析一个特定的html文档,某种字典,大约有10000个单词和描述。 它一直很顺利,直到我注意到特定格式的条目没有得到很好的解析。

以下是一个例子:

    <?php
    $html = '
        <p>
            <b>
                <span>zot; zotz </span>
            </b>
            <span>Nista; nula. Isto
                <b>zilch; zip.</b>
            </span>
        </p>
        ';

    $xml = simplexml_load_string($html);

    var_dump($xml);
    ?>

var_dump()的结果是:

    object(SimpleXMLElement)#1 (2) {
      ["b"]=>
      object(SimpleXMLElement)#2 (1) {
        ["span"]=>
        string(10) "zot; zotz "
      }
      ["span"]=>
      string(39) "Nista; nula. Isto

            "
    }

正如您所看到的 - Simplexml将文本节点保留在标记内,但遗漏了子节点和文本。

我也尝试过:

    $doc = new DOMDocument();
    $doc->loadHTML($html);
    $xml = simplexml_import_dom($doc);

具有相同的结果。

因为在我看来,这是解析html的一个常见问题,我尝试用Google搜索,但只有承认这个问题的地方是这个博客: https://hakre.wordpress.com/2013/07/09/simplexml-and-json-encode-in-php-part-i/ 但是没有提供任何解决方案。

关于在SO中解析HTML,过于笼统的帖子和答案。

有没有一种简单的方法可以解决这个问题? 或者,我应该改变策略吗?

1 个答案:

答案 0 :(得分:0)

您的观察是正确的:SimpleXML仅提供子元素节点,而不是子文本节点。解决方案是切换到DOMDocument,因为它可以访问那里的所有节点,文本和元素子节点。

// first span element
$span = dom_import_simplexml($xml->span);

foreach ($span->childNodes as $child) {
    printf(" - %s : %s\n", get_class($child), $child->nodeValue );
}

此示例显示dom_import_simplexml用于更具体的<span>元素节点,遍历是根据 DOMElement 对象的子节点完成的。

输出:

 - DOMText : Nista; nula. Isto

 - DOMElement : zilch; zip.
 - DOMText : 

第一个条目是<span>元素中的第一个文本节点。接下来是<b>元素(它再次包含一些文本),然后是另一个仅包含空格的文本节点。

SimpleXMLElement 过于简单,无法在XML文档中进行更多差异化的数据访问时,dom_import_simplexml函数特别有用。就像你在这里遇到的情况一样。

完整示例:

$html = <<<HTML
<p>
    <b>
        <span>zot; zotz </span>
    </b>
    <span>Nista; nula. Isto
        <b>zilch; zip.</b>
    </span>
</p>
HTML;

$xml = simplexml_load_string($html);

// first span element
$span = dom_import_simplexml($xml->span);

foreach ($span->childNodes as $child) {
    printf(" - %s : %s\n", get_class($child), $child->nodeValue );
}