在 php 中使用 xpath 创建 preg_match

creating preg_match using xpath in php

我正在尝试使用 XPATH 在 php 中获取内容。

<div class='post-body entry-content' id='post-body-37'>
<div style="text-align: left;">
<div style="text-align: center;">
Hi
</div></div></div>

我正在使用下面的 php 代码来获取输出。

 $dom = new DOMDocument;
 libxml_use_internal_errors(true);
 $dom->loadHTML($html);
 $xpath = new DOMXPath($dom);
 $xpath->registerPhpFunctions('preg_match');
 $regex = 'post-(content|[a-z]+)';
 $items = $xpath->query("div[ php:functionString('preg_match', '$regex', @class) > 0]");
 dd($items);

它returns输出如下

DOMNodeList {#580 
+length: 0 
} 

这是一个工作版本,其中包含您在评论中获得的不同建议:

libxml_use_internal_errors(true);

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

$xpath = new DOMXPath($dom);
// you need to register the namespace "php" to make it available in the query
$xpath->registerNamespace("php", "http://php.net/xpath"); 
$xpath->registerPhpFunctions('preg_match');

// add delimiters to your pattern
$regex = '~post-(content|[a-z]+)~';

// search your node anywhere in the DOM tree with "//"
$items = $xpath->query("//div[php:functionString('preg_match', '$regex', @class)>0]");

var_dump($items);

显然,这种模式是无用的,因为您可以使用可用的 XPATH 字符串函数获得相同的结果,例如 contains.

对于像这样的简单任务 - 获取具有 class 属性且以 post- 开头并包含 contentdiv 节点,您应该使用常规的简单 XPath 查询:

$xp->query('//div[starts-with(@class,"post-") and contains(@class, "content")]');

在这里, - //div - 获取所有 div... - starts-with(@class,"post-") - 具有以 "post-" 开头的 "class" 属性 - and - 和... - contains(@class, "content") - 在 class 属性值中包含 "content" 子字符串。

要使用 php:functionString,您需要注册 php 命名空间(使用 $xpath->registerNamespace("php", "http://php.net/xpath");)和 PHP functions(注册它们都使用 $xp->registerPHPFunctions(); ).

对于复杂的场景,当您需要更深入地分析值时,您可能需要创建并注册自己的函数:

function example($attr) {
    return preg_match('/post-(content|[a-z]+)/i', $attr) > 0;
}

然后在 XPath 中:

$divs = $xp->query("//div[php:functionString('example', @class)]");

此处,functionString@class 属性的字符串内容传递给 example 函数,而不是对象(如 php:function 的情况)。

IDEONE demo:

function example($attr) {
    return preg_match('/post-(content|[a-z]+)/i', $attr) > 0;
}
$html = <<<HTML
<body>
<div class='post-body entry-content' id='post-body-37'>
<div style="text-align: left;">
<div style="text-align: center;">
Hi
</div></div></div>
</body>
HTML;
$dom = new DOMDocument;
$dom->loadHTML($html, LIBXML_HTML_NOIMPLIED|LIBXML_HTML_NODEFDTD);

$xp = new DOMXPath($dom);
$xp->registerNamespace("php", "http://php.net/xpath");
$xp->registerPHPFunctions('example');
$divs = $xp->query("//div[php:functionString('example', @class)]");
foreach ($divs as $div) {
    echo $div->nodeValue;    
}

另请参阅 Using PHP Functions in XPath Expressions 中关于在 XPath 中使用 PhpFunctions 的精彩文章。