解析HTML以修剪它

时间:2012-08-03 14:41:40

标签: php html parsing zend-framework

我们假设我有以下代码:

<div class="content">
    <h3>Test</h3>
    <img src="#" alt="" />
    <p>Lorem ipsum</p>
    <p>dolor sit</p>
    <p><!-- pagebreak --></p>
    <p>amet</p>
</div>

我想修剪我的代码并在分页后删除所有内容,但保留html逻辑(</div>):

<div class="content">
    <h3>Test</h3>
    <img src="#" alt="" />
    <p>Lorem ipsum</p>
    <p>dolor sit</p>
</div>

工具:Zend,常规PHP。

有什么想法吗?

2 个答案:

答案 0 :(得分:3)

您可以使用xpath来访问这些节点:

$doc = new DOMDocument;
$doc->loadHTML($html); // your content with a between '<html></html>' pair
$xpath = new DOMXpath($doc);
$elements = $xpath->query('//p[contains(comment(), "pagebreak")]/following-sibling::*|//p[contains(comment(), "pagebreak")]');
foreach ($elements as $elem) {
    $elem->parentNode->removeChild($elem);
}   

print $doc->saveHTML();

xpath的一点细分:

  • // p 每个P元素。
  • // p [] 过滤P的列表,就像它的数组一样。
  • // p [contains(comment(),“pagebreak”)] 过滤器是否其评论()值包含“pagebreak”字符串。
  • // p [contains(comment(),“pagebreak”)] / following-sibling :: * 选择了P的每个兄弟。
  • 另一部分只是一个没有|部分的相同模式的联合(following-sibling::*)。

编辑:

可能不那么多毛的xpath:

//p[contains(comment(), "pagebreak")]/preceding-sibling::*[1]/following-sibling::*

这可以通过退回兄弟列表中的一个(当时以<p>定位在带有注释的那个之前)并具有该节点的following-siblings::*

来实现这一目的。

答案 1 :(得分:0)

我做到了!我把它作为个人挑战,我终于用正则表达式做了! 这段代码可能没有优化,然后不要犹豫告诉我如何改进它(但使用正则表达式,而不是DOM),但仍然有效! :)

$str = '<div>
    <h3>Test</h3>
    <img/>
    <p>Lorem ipsum</p>
    <p>dolor sit</p>
    <p><-- pagebreak --></p>
    <p>amet</p>
    <blockquote>
        <p>
            lol
        <p>
    </blockquote>
</div>';


$pagebreak_str = '-- pagebreak --';
$weird_replacement = '§~@';

$parsed = array();
$is_below_break = false;

while (preg_match ("#<([^/]+)>#isU",$str)) {
    if ($is_below_break) {
        $str = preg_replace ("#<" .$pagebreak_str. ">#isU", "", $str);
        $str = preg_replace ("#<[^/>]+>(.+)</[^/>]+>#isU", "", $str);
        $str = preg_replace ("#<[^/>]+/>#isU", "", $str);
    }
    else {
        $get = preg_replace ("#^(.*)<([^/>]+)>(.*)$#isU","$2",$str,1);

        if ($get == $pagebreak_str)
            $is_below_break = true;
        if (!$is_below_break)
            $str = preg_replace ("#<([^/>]+)>#isU","$weird_replacement$1>",$str,1);
        if (preg_match ("#</([^/>]+)>(.+)(<$pagebreak_str>)#isU", $str))
            $str = preg_replace ("#</([^/>]+)>#isU", "$weird_replacement/$1>", $str, 1);
    }
}
$str = preg_replace ("#$weird_replacement#isU", "<", $str);

echo $str;

此代码假设您没有任何html编码错误,例如交叉标记(&lt; div&gt;&lt; a&gt;&lt; / div&gt;&lt; / a&gt;),但它确实使用了正确的编码风格。
试试看吧!