在DOM属性的文档中查找文本偏移量

时间:2018-03-27 13:06:08

标签: php 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()返回行号 - 这与我想要的类似,但我找不到文本中一般偏移的替代方法。

2 个答案:

答案 0 :(得分:2)

找到你想要的属性后,

  • 将其值替换为您将永远不会在文档中看到的唯一值
  • 再次将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”和“LIBXML_HTML_NODEFDTD”,更多here

如果要查找匹配元素的所有位置,请执行:

foreach($nodes as $href) {
    $previousValue = $href->value;
    $href->value = $mySecretId;
    $html = $dom->saveHTML();
    echo strpos($html, $mySecretId) . "\n";
    $href->value = $previousValue;
}

答案 1 :(得分:1)

假设

以下是基于一些假设:

  • a.href属性是唯一应该处理的候选者 - 如果使用的正则表达式模式可能会变得更复杂
  • a.href属性始终封装在双引号"中,属性节点的值不能为空
  • 如果a.href属性在同一节点中多次出现,则最后一次出现优先

使用preg_match_all使用offset-capture

的代码
<?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+href\s*=\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)
  }
}
相关问题