在DOM属性中找到文本偏移量



我如何使用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)
  }
}

最新更新