有没有办法使用Xpath解析两个 SETS 标签之间的文字?例如,请参见示例:
<div class="par">
<p class="pp">
<span class="dv">1 </span>Blah blah blah blah. <span class="dv">2 </span> Yada
yada yada yada. <span class="dv">3 </span>Foo foo foo foo.
</p>
</div>
<div class="par">
<p class="pp">
<span class="dv">4 </span>Hmm hmm hmm hmm.
</p>
</div>
我想通过在SPAN标记集之间获取文本来解析以获得如下所示的数组:
array[0] = "Blah blah blah blah.";
array[1] = "Yada yada yada yada.";
array[2] = "Foo foo foo foo.";
array[3] = "Hmm hmm hmm hmm.";
我可以使用DOMDocument来做到这一点吗?如果没有,实现这一目标的最佳方法是什么?请注意,句子中间可能有标签或标签。如:
...<span class="dv">5 </span>Uhh uhh <a href="www.uhh.com">uhh</a> uhh. <span class="dv">6 </span>...
答案 0 :(得分:3)
<强>更新强>
似乎你确实想要一个平面列表,所以我添加这个特定的例子,所以没有混淆:
$html = '<div class="par">
<p class="pp">
<span class="dv">1 </span>Blah blah blah blah. <span class="dv">2 </span> Yada
yada yada yada. <span class="dv">3 </span>Foo foo foo foo.
</p>
</div>
<div class="par">
<p class="pp">
<span class="dv">4 </span>Hmm hmm hmm hmm.
</p>
</div>';
$dom = DOMDocument::loadHTML($html);
$finder = new DOMXPath($dom);
// select THE TEXT NODES of all p elements with the class pp
// - note that means its explictly class="pp",
// not that "pp" is anywhere in the class list you may need to change this up depending...
// post additional questions for specific xpath help
$found = $finder->query('//p[@class="pp"]/text()');
$nodes = array();
// simply transform the resulting DOMNodeList into an array
// for easier consumption/manipulation
foreach($found as $textNode) {
$node[] = $textNode->nodeValue;
}
print_r($nodes);
产地:
Array
(
[0] =>
[1] => Blah blah blah blah.
[2] => Yada
yada yada yada.
[3] => Foo foo foo foo.
[4] =>
[5] => Hmm hmm hmm hmm.
)
如果案例总是这么简单我认为你可以使用xpath来获取p.pp中子DOMText节点的内容。
$html = '<div class="par">
<p class="pp">
<span class="dv">1 </span>Blah blah blah blah. <span class="dv">2 </span> Yada
yada yada yada. <span class="dv">3 </span>Foo foo foo foo.
</p>
</div>
<div class="par">
<p class="pp">
<span class="dv">4 </span>Hmm hmm hmm hmm.
</p>
</div>';
$dom = DOMDocument::loadHTML($html);
$finder = new DOMXPath($dom);
// select all p elements with the class pp - note that means its explictly class="pp",
// not that "pp" is anywhere in the class list you may need to change this up depending...
// post additional questions for specific xpath help
$found = $finder->query('//p[@class="pp"]');
$nodes = array();
foreach($found as $p) {
// for each p element, pull its text nodes.
$textNodes = $finder->query('text()', $p);
$textStr = '';
// loop over the textNodes and concat them into a single string
foreach ($textNodes as $n) {
$textStr .= $n->nodeValue;
}
// push the compiled string onto the array
$nodes[] = $textStr;
}
print_r($nodes);
这将产生如下结果:
Array
(
[0] =>
Blah blah blah blah. Yada
yada yada yada. Foo foo foo foo.
[1] =>
Hmm hmm hmm hmm.
)
如果您确实需要单独使用每个文本节点,则只需更改循环:
foreach($found as $p) {
// for each p element, pull its text nodes.
$textNodes = $finder->query('text()', $p);
$textArr = array();
// loop over the textNodes and concat them into a single string
foreach ($textNodes as $n) {
$textArr[] = $n->nodeValue;
}
// push the compiled string onto the array
$nodes[] = $textArr;
}
哪个会给你:
Array
(
[0] => Array
(
[0] =>
[1] => Blah blah blah blah.
[2] => Yada
yada yada yada.
[3] => Foo foo foo foo.
)
[1] => Array
(
[0] =>
[1] => Hmm hmm hmm hmm.
)
)
显然,你可以看到它已经抓住了换行符,你可以轻松地使用你选择的数组过滤方法过滤它们,如果它们不合需要的话。或者您可以查看XPath和DOMDocument设置来调整这个,IIRC有一些设置处理如何解释(或不解释)空格,这可能会让您避免这种情况,但如果您在进行其他处理时可能会产生其他一些后果相同的DOMDocument
实例。
答案 1 :(得分:1)
你想要第一个文本节点,它是span元素之后的直接兄弟节点:
//span/following-sibling::text()[1]
这是PHP语法中的1:1:
$doc = new DOMDocument();
$doc->loadHTML($buffer, LIBXML_HTML_NOIMPLIED);
$xpath = new DOMXPath($doc);
$expr = '//span/following-sibling::text()[1]';
$result = $xpath->evaluate($expr);
然后,您希望生成的文本节点变为字符串数组。我已经说过,当你自己完成这项工作时,就可以对它进行一些空白规范化:
$array = array_map(function(DOMText $text) {
return preg_replace(['~\s+~u', '~^ | $~'], [' ', ''], $text->nodeValue);
}, iterator_to_array($result));
结果是:
[
"Blah blah blah blah.",
"Yada yada yada yada.",
"Foo foo foo foo.",
"Hmm hmm hmm hmm."
]
完整的代码示例:
<?php
/**
* http://stackoverflow.com/questions/27674012/php-domdocument-get-text-between-two-sets-of-tags
*/
$buffer = <<<HTML
<div class="par">
<p class="pp">
<span class="dv">1 </span>Blah blah blah blah. <span class="dv">2 </span> Yada
yada yada yada. <span class="dv">3 </span>Foo foo foo foo.
</p>
</div>
<div class="par">
<p class="pp">
<span class="dv">4 </span>Hmm hmm hmm hmm.
</p>
</div>
HTML;
$doc = new DOMDocument();
$doc->loadHTML($buffer, LIBXML_HTML_NOIMPLIED);
$xpath = new DOMXPath($doc);
$expr = '//span/following-sibling::text()[1]';
$result = $xpath->evaluate($expr);
$array = array_map(function(DOMText $text) {
return preg_replace(['~\s+~u', '~^ | $~'], [' ', ''], $text->nodeValue);
}, iterator_to_array($result));
echo json_encode($array, JSON_PRETTY_PRINT);