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 );
}
我正在尝试解析特定的 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 );
}