JQuery-подобный селектор для PHP DOMDocument

Я работаю с DOMDocument, и мне интересно, существует ли какой-то способ использования селекторов типа CSS для выбора как мы бы в jQuery.

Пример ситуации: я разбираю XML файл, один фрагмент которого выглядит следующим образом:

<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]")

чтобы получить все элементы Cube с атрибутом 'currency'.

Но как я могу сделать то же самое с PHP DOMDocument? Я хотел бы выбрать элементы, которые имеют атрибут, или имеют определенное значение атрибута.

Ответы

Ответ 1

Если вы хотите манипулировать 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');

Ответ 2

Взгляните на класс DOMXPath в PHP. Он использует XPath, поэтому вам нужно будет прочитать синтаксис XPath, если вы не знакомы с ним. Там есть документация по MSDN или W3Schools, или вы можете прочитать спецификацию W3, если вы особенно смелы.

Чтобы решить вашу проблему с примером: //cube[@currency] - это запрос XPath, который выбирает все элементы в документе с атрибутом валюты. Использование этого класса DOMXPath будет выглядеть так:

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

$cubesWithCurrencies теперь DOMNodeList, который вы можете перебрать.

Ответ 3

Я создал библиотеку, которая позволяет обходить HTML5 и XML-документы так же, как и с jQuery.

Вы можете найти библиотеку на 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 footer
$sitefooter = $body->select('.site-footer > .site-center');

// Set some attributes for the site 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 footer
$sitefooterparent = $sitefooter->parent();

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

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

[...]

Поддерживаемые методы:
  • Переименовано 'select', по понятным причинам
  • Переименовано 'void', так как 'empty' является зарезервированным словом в PHP

Ответ 4

Вы можете использовать компонент Symfony DomCrawler, позволяющий использовать селектора css для перемещения DOM: https://packagist.org/packages/symfony/dom-crawler