PHP DOMDocument 的类 jQuery 选择器

Posted

技术标签:

【中文标题】PHP DOMDocument 的类 jQuery 选择器【英文标题】:jQuery-like selectors for PHP DOMDocument 【发布时间】:2010-11-10 14:09:50 【问题描述】:

我正在使用DOMDocument,我想知道是否有某种方法可以像在jQuery 中那样使用类似 CSS 的选择器来选择节点。

示例情况:我正在解析一个 XML 文件,其中一个 sn-p 如下所示:

<gesmes:Envelope>
    <gesmes:subject>Reference rates</gesmes:subject>
    <gesmes:Sender>
        <gesmes:name>European Central Bank</gesmes:name>
    </gesmes:Sender>
    <Cube>
        <Cube time="2009-07-13">
            <Cube currency="USD" rate="1.3975"/>
            <Cube currency="JPY" rate="129.03"/>
            <Cube currency="BGN" rate="1.9558"/>
            <Cube currency="CZK" rate="26.028"/>
        </Cube>
    </Cube>
</gesmes:Envelope>

使用类似 jQuery 的选择器访问这个结构非常简单。例如,我可以使用

$("Cube[currency]")

使用 'currency' 属性检索所有 Cube 元素。

但是我怎样才能用 phpDOMDocument 做同样的事情呢?我想选择具有属性或具有特定属性值的元素。

【问题讨论】:

【参考方案1】:

XPath 正是您正在寻找的,here is pretty good list of possible selectors

【讨论】:

虽然 XPath 适合按元素名称选择,但按属性值(类、id 等)选择就很可怕了。此外,它会阻塞无效的 XML,并且网络上的大多数 html 都不是有效的 XML。 其实你可以用 DOMDocument::loadHTML() 加载不正确的 HTML 并用 XPath 查询它。【参考方案2】:

看看 PHP 中的 DOMXPath 类。它使用 XPath,因此如果您不熟悉 XPath 语法,则需要阅读它。 MSDN 上有一些文档,如果你特别勇敢,也可以阅读 W3 spec。

解决您的示例问题://cube[@currency] 是一个 XPath 查询,它选择文档中具有货币属性的所有元素。在 DOMXPath 类中使用 this 如下所示:

$xpath = new DOMXpath($myDomDocument);
$cubesWithCurrencies = $xpath->query('//cube[@currency]');

$cubesWithCurrencies 现在是 DOMNodeList,您可以对其进行迭代。

【讨论】:

【参考方案3】:

如果你想操作 DOM ala Jquery,PHPQuery 适合你。

http://code.google.com/p/phpquery/

一个简单的例子说明你可以用它做什么。

// almost everything can be a chain
$li = null;
$doc['ul > li']
        ->addClass('my-new-class')
        ->filter(':last')
                ->addClass('last-li');

【讨论】:

哇,太棒了!我唯一的疑问是未来的可靠性……如果项目停止怎么办?我想使用 DomDocument 会更安全.. 但我会试一试! 它向后使用 DOMDocument,所以你不必担心 ;) 最后,它只是一个为你所有 DOM 需求提供语法糖的包装器...... 是的,我已经看到这实际上是“只是” php DOM API 的一个 API ;) 但它就像魔术一样工作,即使是大文件。谢谢大佬! -1; phpQuery 很烂,在遭受了可怕的缺陷之后,我建议不要使用它。它是带有 over 100 open bugs 的废弃软件(最后一次提交是 2010 年 2 月),包括来自 typoed variable names 的非常基本的东西,例如错误。远离这个;寻找另一个图书馆或学习use Xpath via the built-in DOM library。 我是 phpquery 的忠实粉丝,能够在 javascript 中使用相同的 css3 查询 id 真是太棒了。除了与本机 DOMDocument 相同的字符编码问题外,我从来没有遇到过 phpquery 的问题,而且看起来一年前有一个提交。他们的文档确实有点烂【参考方案4】:

您可以使用 Symfony DomCrawler 组件,使您能够使用 css 选择器进行 DOM 遍历: https://packagist.org/packages/symfony/dom-crawler

【讨论】:

也安装 CssSelector 组件并使用 filter() !【参考方案5】:

我创建了一个库,允许您像使用 jQuery 一样抓取 HTML5 和 XML 文档。

你可以找到图书馆on GitHub

它应该可以让你做你想做的事!

在底层,它使用symfony/DomCrawler 将 CSS 选择器转换为 XPath 选择器。即使将一个对象传递给另一个对象,它也始终使用相同的 DomDocument,以确保良好的性能。

该库还包括其自己的零配置自动加载器,用于 PSR-0 兼容库。包含的示例无需任何额外配置即可开箱即用。


使用示例:

namespace PowerTools;

// Get file content
$htmlcode = file_get_contents( 'https://github.com' );

// Define your DOMCrawler based on file string
$H = new DOM_Query( $htmlcode );

// Define your DOMCrawler based on an existing DOM_Query instance
$H = new DOM_Query( $H->select('body') );

// Passing a string (CSS selector)
$s = $H->select( 'div.foo' );

// Passing an element object (DOM Element)
$s = $H->select( $documentBody );

// Passing a DOM Query object
$s = $H->select( $H->select('p + p') );

// Select the body tag
$body = $H->select('body');

// Combine different classes as one selector to get all site blocks
$siteblocks = $body->select('.site-header, .masthead, .site-body, .site-footer');

// Nest your methods just like you would with jQuery
$siteblocks->select('button')->add('span')->addClass('icon icon-printer');

// Use a lambda function to set the text of all site blocks
$siteblocks->text(function( $i, $val) 
    return $i . " - " . $val->attr('class');
);

// Append the following HTML to all site blocks
$siteblocks->append('<div class="site-center"></div>');

// Use a descendant selector to select the site's footer
$sitefooter = $body->select('.site-footer > .site-center');

// Set some attributes for the site's footer
$sitefooter->attr(array('id' => 'aweeesome', 'data-val' => 'see'));

// Use a lambda function to set the attributes of all site blocks
$siteblocks->attr('data-val', function( $i, $val) 
    return $i . " - " . $val->attr('class') . " - photo by Kelly Clark";
);

// Select the parent of the site's footer
$sitefooterparent = $sitefooter->parent();

// Remove the class of all i-tags within the site's footer's parent
$sitefooterparent->select('i')->removeAttr('class');

// Wrap the site's footer within two nex selectors
$sitefooter->wrap('<section><div class="footer-wrapper"></div></section>');

[...]

支持的方法: [x]$(1) [x]$.parseHTML [x]$.parseXML [x]$.parseJSON [x]$selection.add [x]$selection.addClass [x]$selection.after [x]$selection.append [x]$selection.attr [x]$selection.before [x]$selection.children [x]$selection.closest [x]$selection.contents [x]$selection.detach [x]$selection.each [x]$selection.eq [x]$selection.empty(2) [x]$selection.find [x]$selection.first [x]$selection.get [x]$selection.insertAfter [x]$selection.insertBefore [x]$selection.last [x]$selection.parent [x]$selection.parents [x]$selection.remove [x]$selection.removeAttr [x]$selection.removeClass [x]$selection.text [x]$selection.wrap
    重命名为“select”,原因很明显 重命名为“void”,因为“empty”是 PHP 中的保留字

【讨论】:

@LucasBustamante :通常,您应该能够只下载 repo 并在“examples”文件夹中运行示例,而无需任何其他配置。这对你有用吗?如果没有,会发生什么?如果是,您打算如何使用该库?

以上是关于PHP DOMDocument 的类 jQuery 选择器的主要内容,如果未能解决你的问题,请参考以下文章

在 PHP 中使用 DOMDocument 缩进

PHP DOMDocument 添加了额外的标签

在 PHP 中从 DOMNode 创建 DOMDocument

PHP 4 中的新 DOMDocument()

PHP DOMDocument 丢失

这是 PHP 的 DOMDocument 库中的错误吗?