Фильтрация XML-элементов по значению дочернего узла

#php #xml #simplexml

#php #xml #simplexml

Вопрос:

У меня есть канал с продуктами, у всех продуктов есть дочерний узел под названием «категория» со значением. Я не могу найти способ вернуть все продукты с определенным значением категории.

XML выглядит примерно так

 <product>
    <name>xxxx</name>
    <category>Category A</category>
</product>
<product>
    <name>xxxx</name>
    <category>Category B</category>
</product>
<product>
    <name>xxxx</name>
    <category>Category A</category>
</product>
<product>
    <name>xxxx</name>
    <category>Category B</category>
</product>
<product>
    <name>xxxx</name>
    <category>Category B</category>
</product> 
 

Я пробовал перебирать XML, используя PHP-код, подобный этому:

 $xml = simplexml_load_file('file.xml');

foreach ($xml as $product) {

    if ((string) $product['category'] == 'Category A') {
        echo (string) $product['name'];
    }

}
 

Ожидаемый результат — возврат / эхо других дочерних узлов для этого продукта. Каков наилучший подход для этого?

Ответ №1:

Ваш подход кажется разумным, я недостаточно знаком с SimpleXML, чтобы сказать, почему он не работает. Но, поскольку вы просили наилучший подход, я сам неравнодушен к DOMDocument и XPath:

 $xml = <<< XML
<?xml version="1.0"?>
<products>
    <product>
        <name>xxxx</name>
        <category>Category A</category>
    </product>
    <product>
        <name>xxxx</name>
        <category>Category B</category>
    </product>
    <product>
        <name>xxxx</name>
        <category>Category A</category>
    </product>
    <product>
        <name>xxxx</name>
        <category>Category B</category>
    </product>
    <product>
        <name>xxxx</name>
        <category>Category B</category>
    </product>
</products>
XML;

$dom = new DomDocument;
$dom->loadXML($xml);
$xpath = new DomXPath($dom);
$search = "Category A";
$nodes = $xpath->query("//product[category='$search']/name");

foreach ($nodes as $node) {
    printf("%sn", $node->textContent);
}
 

Для SimpleXML, после небольшого копания, похоже, что ему нужно обращаться к элементам с обозначением объекта, а не с обозначением массива. Это сработало для меня:

 $x = simplexml_load_string($xml);
foreach ($x->product as $product) {
    if ((string) $product->category == 'Category A') {
        echo (string) $product->name;
    }
}
 

Но я утверждаю, что изучение методов DOM и XPath сослужит вам лучшую службу в долгосрочной перспективе; оба они являются хорошо зарекомендовавшими себя стандартами, которые используются во многих языках. Знания о SimpleXML — это не то, что вы можете перенести в другую среду.