使用 DOMXPath 在 <p> 标记内保留换行符?

Posted

技术标签:

【中文标题】使用 DOMXPath 在 <p> 标记内保留换行符?【英文标题】:Preserve line breaks inside <p> tags using DOMXPath? 【发布时间】:2011-06-12 00:17:57 【问题描述】:

我目前正在使用 phpDOMXPath 来获取网页的所有 &lt;p&gt; 元素的内容:

<?php
...    
$doc = new DOMDocument();
$doc->loadhtml($html);

$xpath = new DOMXPath($doc);
$paragraphs = $xpath->evaluate("/html/body//p");

foreach ($paragraphs as $paragraph)
echo $paragraph->textContent . "<br />";

我的问题是textContent 产生的字符串不尊重存在于&lt;p&gt; 元素中的&lt;br /&gt; 标签。相反,它删除了换行符并将通常位于不同行的单词放在一起。例如:

示例 HTML:

<p>
Some happy talk goes here talking about our great product.<br />
We would love for you to buy it!
</p>

<p>
Random information and what not<br />
Isn't that cool?
</p>

上面 PHP 的当前输出:

Some happy talk about our great product.We would love for you to buy it!

Random information and what notIsn't that cool?

我也试过$paragraphs = $doc-&gt;getElementsByTagName("p");,它给了我同样的东西。

有没有办法让 DOMXPath/DOMDocument 保留换行符?我需要能够分隔段落中的每个单词,而当前的输出不允许这样做。

如果有另一种方法可以检索&lt;p&gt; 元素中的字符串,同时保留&lt;br /&gt;'\n',那也很好。

编辑


经过进一步调查,有问题的 HTML 实际上是一个由&lt;br&gt; 标签分隔的锚点列表,但没有实际的换行符:

<p class="home_page_list"><a href="/home/personal-banking/checking/Category-Page-Classic-Checking/classic-checking.html">Classic Checking</a><br> <a href="/home/personal-banking/checking/Category-Page-Interest-Checking/interest-checking.html">Interest Checking</a><br> <a href="/home/personal-banking/checking/Category-Page-Interest-Checking/interest-premium-checking.html">Premium Checking</a><br> <a href="/home/personal-banking/Savings-Category-Page/Basic-Savings-Category-Page/basic-savings.html">Savings Plans</a><br> <a href="/home/personal-banking/Savings-Category-Page/Money-Market-Accounts-Category-Page/money-market-accounts.html">Money Market Accounts</a><br> <a href="/home/personal-banking/Savings-Category-Page/Certificates-of-Deposit-Category-Page/fixed-rate-CD.html">CDs</a><br> <a href="/home/personal-banking/Savings-Category-Page/Individual-Retirement-Account-Category-Page/individual-retirement-account.html">IRAs</a></p>

事实证明,这适用于给定的原始 HTML。

更新:已解决


在@ircmaxell 的回答的帮助下,以及@netcoder 和@Gordon 留下的cmets 这个问题已经解决了,它不是很优雅,但现在可以了。

例子:

foreach ($paragraphs as $paragraph)
    $p_text = new DOMDocument();
    $p_text->loadHTML(str_ireplace(array("<br>", "<br />"), "\r\n", DOMinnerHTML($paragraph)));
    //Do whatever, in this case get all of the words in an array.
    $words = explode(" ", str_ireplace(array(",", ".", "&", ":", "-", "\r\n"), " ", $p_text->textContent));
print_r($words);

这利用DOMinnerHTML(由@netcoder 建议)将&lt;br&gt; 的实例替换为“\r\n”(由@ircmaxell 建议),然后可以在textContent.

显然还有一些改进的余地,但它已经解决了我当前的问题。

感谢大家的帮助,

【问题讨论】:

@Ben:你确定?什么PHP版本?在 PHP 5.3.3 上按预期工作。 注意:要保留内部标签(例如:&lt;br&gt;&lt;span 等),您必须使用递归函数来提取元素的“innerHTML”。 @netcoder:很确定,虽然我不会说我做错了什么是不可能的。不幸的是,我们的主机使用的是 PHP 5.2.12。 @Ben:在 PHP 5.2.10 上也可以正常工作。你怎么输出这个?在网络浏览器中?如果是这样,您在看什么,格式化输出或页面源? @Ben:见innerHTML in PHP's DOMDocument。 【参考方案1】:

好吧,我要做的就是用文字换行符替换换行符:

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

$brs = $doc->getElementsByTagName('br');
foreach ($brs as $node) 
    $node->parentNode->replaceChild($doc->createTextNode("\r\n"), $node);



$xpath = new DOMXPath($doc);
$paragraphs = $xpath->evaluate("/html/body//p");

foreach ($paragraphs as $paragraph)
    echo $paragraph->textContent . "<br />";

【讨论】:

【参考方案2】:

一种可能性

echo simplexml_import_dom($paragraph)->asXML();

【讨论】:

【参考方案3】:

我有同样的情况,我用:

$document->loadHTML(str_replace('<br>', urlencode('<br>'), $string_or_file));

我使用 urlencode() 将其改回显示或插入数据库。

【讨论】:

以上是关于使用 DOMXPath 在 <p> 标记内保留换行符?的主要内容,如果未能解决你的问题,请参考以下文章

提取输入隐藏DOMXpath php的值

DOM xpath 查找#text 节点并包含在段落标记中

codeception 中的 fillField 方法不起作用抛出 DOMXPath::query(): Invalid expression

PHP DOMXPath 查询使用元素的 innerHTML/nodeValue 来查找并返回该元素

CSS选择器之基本选择器总结

使用CSS创建一个图片角标