【问题标题】:Find and append hrefs of a certain class查找并附加某个类的href
【发布时间】:2011-08-04 15:09:04
【问题描述】:

我一直在寻找解决方案,但还没有找到完全正确的方法。

情况是这样的: 我需要在给定类的页面上找到所有链接(比如class="tracker"),然后在末尾附加查询字符串值,因此当用户加载页面时,这些特定链接会使用一些动态信息进行更新。

我知道如何使用 Javascript 来做到这一点,但我真的很想将它改成在服务器端运行。我对 PHP 很陌生,但从外观上看,XPath 可能是我正在寻找的东西,但我还没有找到合适的示例来入门和。有GetElementByClass之类的吗?

任何帮助将不胜感激!

暗影

【问题讨论】:

标签: php xpath append href


【解决方案1】:

GetElementByClass之类的吗?

这是我创建的一个实现...

function getElementsByClassName(DOMDocument $domNode, $className) {
    $elements = $domNode->getElementsByTagName('*');
    $matches = array();
    foreach($elements as $element) {
        if ( ! $element->hasAttribute('class')) {
            continue;
        }
        $classes = preg_split('/\s+/', $element->getAttribute('class'));
        if ( ! in_array($className, $classes)) {
            continue;
        }
        $matches[] = $element;
    }
    return $matches;
}

这个版本不依赖上面的辅助函数。

$str = '<body>
    <a href="">a</a>
        <a href="http://example.com" class="tracker">a</a>
        <a href="http://example.com?hello" class="tracker">a</a>
    <a href="">a</a>
</body>
    ';

$dom = new DOMDocument;

$dom->loadHTML($str);

$anchors = $dom->getElementsByTagName('body')->item(0)->getElementsByTagName('a');

foreach($anchors as $anchor) {

    if ( ! $anchor->hasAttribute('class')) {
        continue;
    }

    $classes = preg_split('/\s+/', $anchor->getAttribute('class'));

    if ( ! in_array('tracker', $classes)) {
        continue;
    }

    $href = $anchor->getAttribute('href');

    $url = parse_url($href);

    $attach = 'stackoverflow=true';

    if (isset($url['query'])) {
        $href .= '&' . $attach;
    } else {
        $href .= '?' . $attach;
    }

    $anchor->setAttribute('href', $href);
}

echo $dom->saveHTML();

输出

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" "http://www.w3.org/TR/REC-html40/loose.dtd">
<html><body>
    <a href="">a</a>
        <a href="http://example.com?stackoverflow=true" class="tracker">a</a>
        <a href="http://example.com?hello&amp;stackoverflow=true" class="tracker">a</a>
    <a href="">a</a>
</body></html>

【讨论】:

  • 谢谢!这看起来是一个开始的好地方。首先,我可以将$dom-&gt;loadHTML($str); 更改为$dom-&gt;loadHTML($html); 以解析整个页面而不是加载字符串吗?
  • 我想我收集了您的代码是如何工作的,但是我将如何修改 $dom-&gt;loadHTML($str) 以解析当前页面的链接,然后就地编辑这些链接。我需要在现有页面上运行脚本,因此传入字符串并不可行。
  • @Shadowise 您需要使用它来预处理您的页面。如果您在页面上使用视图会容易得多;你可以在输出它们之前通过这个函数运行它们。
【解决方案2】:

我需要找到页面上的所有链接 给定的班级(比如说 class="tracker") [...] 我对 PHP 很陌生,但是从 看起来,XPath 可能就是我的样子 正在寻找但我没有找到 合适的例子开始。 有没有类似的 GetElementByClass?

这个 XPath 1.0 表达式:

//a[contains(
       concat(' ',normalize-space(@class),' '),
       ' tracker '
    )
]

【讨论】:

  • 顺便说一句,如果它是第一节课或最后一节课(考虑到在该示例中两边都没有空格),那会起作用吗?
  • @alex:是的。这就是串联的原因。
【解决方案3】:

短一点,使用 xpath:

$dom = new DomDocument();
$dom->loadXml('<?xml version="1.0" encoding="UTF-8" ?>
<root>
    <a href="somlink" class="tracker foo">label</a>
    <a href="somlink" class="foo">label</a>
    <a href="somlink">label</a>
    <a href="somlink" class="atrackerb">label</a>
    <a href="somlink">label</a>
    <a href="somlink" class="tracker">label</a>
    <a href="somlink" class="tracker">label</a>
</root>');

$xpath = new DomXPath($dom);

foreach ($xpath->query('//a[contains(@class, "tracker")]') as $node) {
    if (preg_match('/\btracker\b/', $node->getAttribute('class'))) {
        $node->setAttribute(
            'href',
            $node->getAttribute('href') . '#some_extra'
        );
    }

}

header('Content-Type: text/xml; charset"UTF-8"');
echo $dom->saveXml();

【讨论】:

  • @Yoshi 这似乎与 &lt;a href="" class="atrackera"&gt;&lt;/a&gt; 等元素匹配。这就是为什么我要拆分它们:)
  • @Yoshi 那么与班级不匹配,是吗? :P
  • @alex true,但这也可以在 foreach 循环中完成;)(更改了示例)
  • @Yoshi 这可以解决问题,但是,你不能 use regular expressions in XPath selectors 也一样吗?
  • @alex 是的,但是 php 不知道“匹配”功能。在 5.3 中可以使用:registerPhpFunctions,然后在查询中使用 preg_match。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多