我如何使用php dom扩展名(或必要时其他扩展名或库(找到特定节点或属性的偏移。
例如,说我有此HTML文档:
<html><a href="/foo">bar</a></html>
并使用以下代码(具有适当的修改(:
$dom = new DOMDocument;
$dom->loadHTML($html);
$xpath = new DOMXPath($dom);
$nodes = $xpath->query('//a/@href');
foreach($nodes as $href) {
// Find start of $href attribute here
echo $href->something;
}
我希望看到输出15或效果的内容,以表明该属性从字符15开始到文档中。
似乎有返回行号的方法DOMNode::getLineNo()
- 这与我想要的相似,但找不到文本中的一般偏移的替代方案。
找到所需的属性后,
- 将其值替换为独特的价值,您将在文档中永远不会看到
- 再次将DOMDOCUMENT再次转换为HTML
- 搜索字符串中的唯一值的位置
$html = <<<HTML
<html><a href="/foo">bar</a></html>
HTML;
$dom = new DOMDocument;
$dom->loadHTML($html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
$xpath = new DOMXPath($dom);
$nodes = $xpath->query('//a/@href');
$mySecretId = 'abc123';
foreach($nodes as $href) {
$href->value = $mySecretId;
}
$html = $dom->saveHTML();
echo strpos($html, $mySecretId) . "n";
" strpos "将为您第一次出现替换值,这是您想要的位置。
注意标志" libxml_html_noimplied"one_answers" libxml_html_nodefdtd",此处更多。
如果您想找到匹配元素的所有位置,请执行:
foreach($nodes as $href) {
$previousValue = $href->value;
$href->value = $mySecretId;
$html = $dom->saveHTML();
echo strpos($html, $mySecretId) . "n";
$href->value = $previousValue;
}
假设
以下基于一些假设:
-
a.href
属性是唯一应处理的候选者 - 如果是更多的正则表达方式可能会变得复杂 -
a.href
属性始终封装在双引号"
中,属性节点的值不得为空 - 如果
a.href
属性在同一节点中多次出现,则最后一次出现优先
使用 preg_match_all
的代码
<?php
// define some HTML, could be retrieved by e.g. file_get_contents() as well
$html = <<< HTML
<!DOCTYPE html>
<html lang="en">
<body>
<a href="https://google.com/">Google</a><div><a href=
"https://stackoverflow.com/">StackOverflow</a></div>
<A HREF="https://google.com/" href="https://goo.gl/">
Google URL</a>
</body>
</html>
HTML;
// search href attributes in anchor tags (case insensitive & multi-line)
preg_match_all(
'#<a[^>]*s+hrefs*=s*"(?P<value>[^"]*)"[^>]*>#mis',
$html,
$matches,
PREG_OFFSET_CAPTURE
);
$positions = array_map(
function (array $match) {
$length = mb_strlen($match[0]);
return [
'value' => $match[0],
'length' => $length,
'start' => $match[1],
'end' => $match[1] + $length,
];
},
$matches['value']
);
var_dump($positions);
将输出如下的位置信息(注意:最后一个位置使用第二个href
属性,该属性已定义了两次的同一锚标签((
array(3) {
[0] => array(4) {
'value' => string(19) "https://google.com/"
'length' => int(19)
'start' => int(49)
'end' => int(68)
}
[1] => array(4) {
'value' => string(26) "https://stackoverflow.com/"
'length' => int(26)
'start' => int(95)
'end' => int(121)
}
[2] => array(4) {
'value' => string(15) "https://goo.gl/"
'length' => int(15)
'start' => int(183)
'end' => int(198)
}
}