xpath匹配第一个和最后一个孩子
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了xpath匹配第一个和最后一个孩子相关的知识,希望对你有一定的参考价值。
试图确定任何P标签文本是否完全在strong / B标签内
// Match (unacceptable, flag to user):
<p><strong>Any text and <span>maybe</span> other <em>tags</em></strong></p>
// Don't match (acceptable):
<p>Any text and <strong>maybe</strong> other <em>tags</em></p>
答案
- 任何
p
......//p
- 至少有一个
strong
后代节点......//p[.//strong]
- 有一些文本内容,只有空格...
//p[.//strong[normalize-space(.) != ""]]
- 并且没有没有
strong
祖先节点的内容的文本节点后代://p[ .//strong[normalize-space(.) != ""] and not(.//text()[normalize-space(.) != "" and not(ancestor::strong)]) ]
这将检查两个条件。首先,该段落有一些实际内容在strong
内部,并且没有实际内容没有在strong
内 - 换句话说,内容格式不同。
例:
$html = <<<'HTML'
<p><strong>Any text and <span>maybe</span> other <em>tags</em></strong></p>
<p>Any text and <strong>maybe</strong> other <em>tags</em></p>
<p><strong>Builder's</strong> <strong>tea</strong></p>
<p><em><strong>Builder's</strong> <strong> tea</strong></em></p>
HTML;
$document = new DOMDocument();
$document->loadHTML($html);
$xpath = new DOMXpath($document);
$expression =
'//p[
.//strong[normalize-space(.) != ""] and
not(.//text()[normalize-space(.) != "" and not(ancestor::strong)])
]';
foreach ($xpath->evaluate($expression) as $p) {
var_dump(
$document->saveXml($p)
);
}
输出:
string(75) "<p><strong>Any text and <span>maybe</span> other <em>tags</em></strong></p>"
string(54) "<p><strong>Builder's</strong> <strong>tea</strong></p>"
string(64) "<p><em><strong>Builder's</strong> <strong> tea</strong></em></p>"
表达式可以扩展到覆盖b
:
//p[
(
.//strong[normalize-space(.) != ""] or
.//b[normalize-space(.) != ""]
) and
not(
.//text()[
normalize-space(.) != "" and
not(ancestor::*[self::strong or self::b])
]
)
]
另一答案
这是一种方式,部分基于@gangabass的建议。它计算仅包含单个<p>
元素的<strong>
元素,这些元素可选地仅由空白文本包围。
$unacceptableNodesCount = $xpath->evaluate( 'count(//p[count(*) = 1 and name(*) = "strong" and normalize-space() = string(strong)])' );
var_dump( $unacceptableNodesCount );
说实话,如果目标是阻止用户仅使用粗体文本并确定用户,他们可能会找到一种方法。例如,通过用Unicode空格字符或类似的东西包围<strong>
元素。
另一答案
您的问题描述表明您也想抓住
<p><strong>Builder's</strong><strong> tea</strong></p>
也许也是
<p><strong>Builder's</strong> <strong>tea</strong></p>
一些建议的解决方案没有抓住这些解决方案。
但目前尚不清楚你是否也想抓住
<p><emph><strong>Builder's</strong> <strong> tea</strong></emph></p>
我认为XPath 2.0中最接近“任何P标签文本完全在强/ B标签内”是
//p[empty(.//text()[normalize-space()] except .//strong//text()])]
它选择所有不具有非白色后代文本节点的p元素,该节点不是p中强元素的后代。
我无法立即在XPath 1.0中看到这样做的方法,但我的XPath 1.0非常生疏。
另一答案
以下代码检查P标记在任何Strong标记之前和之后是否包含任何文本或其他HTML标记,确定P标记完全是粗体(强)。
$false_headings = $xpath->query("//p/strong");
foreach ($false_headings as $heading) {
if ($heading->previousSibling === null and $heading->nextSibling === null) {
// Report to user
break;
}
}
以上是关于xpath匹配第一个和最后一个孩子的主要内容,如果未能解决你的问题,请参考以下文章