在PHP中使用XPath创建preg_match

3
我正在尝试在PHP中使用XPATH获取内容。
<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);

它的输出结果如下:
DOMNodeList {#580 
+length: 0 
} 

正则表达式是否需要加限定符?尝试使用 $regex = '/post-(content|[a-z]+)/'; - hjpotter92
请查看此演示,您无需使用正则表达式。 - Wiktor Stribiżew
是的。但我正在寻找以post-开头且包含content的类。如上面的代码所述,我使用上面的正则表达式,因为有些人会像<div class='post-body entry-content' id='post-body-37'>,而有些人则会像<div class='post-content' id='post-body-37'>。我需要解析这两个选项。如果您看第一个选项,它包含两个类post-body entry-content,如果您看第二个选项,它只包含一个类post-content。我也需要通过这个。 - karthick
我会发布已纠正的代码。 - Casimir et Hippolyte
显示剩余3条评论
2个回答

4
这是一个可行的版本,其中包含您在评论中得到的不同建议:
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)获得相同的结果。

>0 的意思是如果匹配就执行 do something,否则忽略它? - Motivated

3

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

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

在这里, - //div - 获取所有的 div 元素... - starts-with(@class,"post-") - 选择 "class" 属性以 "post-" 开头的元素 - and - 并且... - contains(@class, "content") - 选择 "class" 属性值中包含 "content" 子字符串的元素。
要使用 php:functionString,您需要注册 php 命名空间(使用 $xpath->registerNamespace("php", "http://php.net/xpath");)和PHP函数(注册所有函数,请使用 $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演示
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;    
}

还可以查看一篇关于在XPath中使用PhpFunctions的好文章,链接在Using PHP Functions in XPath Expressions


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接