Simplexml:解析 HTML 遗漏了带有文本节点的元素内的嵌套元素

Simplexml: parsing HTML leaves out nested elements inside an element with a text node

我正在尝试解析特定的 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 我尝试用谷歌搜索它,但唯一承认这个问题的地方是这个博客: https://hakre.wordpress.com/2013/07/09/simplexml-and-json-encode-in-php-part-i/ 但不提供任何解决方案。

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

有没有简单的方法来处理这个问题? 或者,我应该改变策略吗?

您的观察是正确的: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[=32= 的子节点完成的] 对象。

输出:

 - 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 );
}