PHP DOMXPath正在剥离匹配文本中的标签

时间:2010-04-04 14:07:53

标签: php html domdocument domxpath

我昨天问过这个问题,当时这正是我所需要的,但在处理一些实时数据时,我发现这并不是我所期望的那样。 Parse HTML with PHP's HTML DOMDocument

它从HTML页面获取数据,但随后它也会删除捕获的文本块中的所有HTML标记,这不是我想要的。 (我可能不想拿出一些标签,但不是全部,这可以在以后完成)

2 个答案:

答案 0 :(得分:8)

这是DOM的一个常见问题:如果你想获取标签的内容及其所有孩子的内容,你必须做更多的工作。

基本上,您必须遍历与XPath查询匹配的子节点,以获取其内容。

用户在DOMElement class的手册页上注明了一个解决方案 - 请参阅this note


将此解决方案集成到您已有的代码中应该为HTML字符串的声明提供类似于此的内容,并带有子标记:

$html = <<<HTML
<div class="main">
    <div class="text">
        <p>
            Capture this <strong>text</strong> <em>1</em>
        </p>
        <p>
            And some other <strong>text</strong>
        </p>
    </div>
</div>
HTML;


并且,要从该HTML字符串中提取数据,您可以使用类似的内容:

$dom = new DOMDocument();
$dom->loadHTML($html);

$xpath = new DOMXPath($dom);

$tags = $xpath->query('//div[@class="main"]/div[@class="text"]');
foreach ($tags as $tag) {
    $innerHTML = '';

    // see http://fr.php.net/manual/en/class.domelement.php#86803
    $children = $tag->childNodes;
    foreach ($children as $child) {
        $tmp_doc = new DOMDocument();
        $tmp_doc->appendChild($tmp_doc->importNode($child,true));       
        $innerHTML .= $tmp_doc->saveHTML();
    }

    var_dump(trim($innerHTML));
}

唯一改变的是foreach循环的内容:您不必仅使用$tag->nodeValue,而是必须迭代子元素。


这给了我以下输出:

string '<p>
            Capture this <strong>text</strong> <em>1</em>
        </p>


<p>
            And some other <strong>text</strong>
        </p>' (length=150)

匹配的<div>标记及其所有子标记的完整内容包括标记。


注意:手册的用户注释中经常有有趣的想法和解决方案; - )

答案 1 :(得分:1)

Pascal MARTIN的答案很棒,但我发现它可以简化

$dom = new DOMDocument();
$dom->loadHTML($html);

$xpath = new DOMXPath($dom);

$tags = $xpath->query('//div[@class="main"]/div[@class="text"]');
foreach ($tags as $tag) {
    $innerHTML = '';

    $children = $tag->childNodes;
    foreach ($children as $child) {     
        $innerHTML .= $dom->saveHTML($child);
    }

    var_dump(trim($innerHTML));
}

这种方式似乎产生相同的结果,但不需要在DomDocument循环内创建新的foreach个对象。

编辑:

因此,经过进一步的实验,您实际上可以将上述内容简化为:

$dom = new DOMDocument();
$dom->loadHTML($html);

$xpath = new DOMXPath($dom);

$tags = $xpath->query('//div[@class="main"]/div[@class="text"]');
foreach ($tags as $tag) {
    var_dump(trim($dom->saveHTML($tag)));
}