基于PHP foreach循环的XML文档过滤



我正在尝试筛选出特定类别的每个XML类别字符串。我该怎么做?

例如,我只想要类别1中的x元素。

示例XML:

<store id="1" name="store">
    <species name="stud">
        <Category1 name="Category1">
            <x category="Hairs" id="20098288"/>
            <x category="Hairs" id="20098289"/>
        </Category1>
        <Category2 name="Category2">
            <x category="Shirts" id="24342342"/>
            <x category="Shirts" id="24342342"/>
        </Category2>
        <Category3 name="Category3">
            <x category="Jackets" id="423423423"/>
            <x category="Jackets" id="423423423"/>
        </Category3>
    </species>
</store>

我的实际代码,它可以让我访问每个类别的子元素:

<?php
    foreach($xmlDocument->species as $species_elem){
        foreach($species_elem->attributes() as $child){
            foreach ($child->x as $item){
                $itemID = $item->attributes()->id;
            }
        }
    }
?>

但我想指定一个只能访问的类别。例如

$category='类别1';

伪代码:

<?php
foreach($species as $species_elem){
    foreach($species_elem which contains $Category1 as $category){
        foreach ($child->x as $item){
            $itemID = $item->attributes()->id;
        }
    }
}
?>
Paul Crovella的回答很好。XPath是最好的选择。

但是,节点名称不应编号。如果你能改变格式,我建议把它们改成更通用的格式,比如"类别"。

使用name属性可以筛选类别元素。

XPath逐步

选择store文档元素节点:
/store

species子元素:
/store/species

任何子元素节点(Category1Category2…):
/store/species/*

如果属性nameCategory1:
/store/species/*[@name = 'Category1']

它们的x子元素:
/store/species/*[@name = 'Category1']/x

DOM

在DOM中,您可以使用DOMXPath::evaluate()DOMXPath::query()在DOM上执行XPath表达式。

$category = 'Category1';
$dom = new DOMDocument();
$dom->loadXML($xml);
$xpath = new DOMXPath($dom);
foreach ($xpath->evaluate("/store/species/*[@name='$category']/x") as $node) {
  echo $dom->saveXML($node), "n";
}

输出:

<x category="Hairs" id="20098288"/>
<x category="Hairs" id="20098289"/>

SimpleXML

SimpleXML使用SimpleXMLElement::xpath()方法。表达式是在元素的上下文中执行的。(store),并且结果被转换为SimpleXMLElement对象的数组。

$category = 'Category1';
$element = new SimpleXMLElement($xml);
foreach ($element->xpath("species/*[@name='$category']/x") as $child) {
  echo $child->asXml(), "n";
}

对于您在问题中提出的XML文档,它实际上是非常直接的(在您的特定情况下):

$xml = simplexml_load_string($buffer);
foreach ($xml->species->Category1->x as $x) {
    echo ' - ', $x->asXML(), "n";
}

输出:

 - <x category="Hairs" id="20098288"/>
 - <x category="Hairs" id="20098289"/>

然后,您可以使用类别的变量对其进行参数化:

$category = 'Category1';
foreach ($xml->species->$category->x as $x) {
    ...

然而,这实际上应该有一些错误处理:

$elements = $xml->species->$category;
if ($elements) foreach ($elements->x as $x) {
    echo ' - ', $x->asXML(), "n";
}

因为由变量命名的元素可能并不总是存在。则该值将为null

完整示例:

<?php
/**
 * PHP foreach loop based filtering on XML document
 *
 * @link http://stackoverflow.com/q/29280839/367456
 */
$buffer = <<<XML
<store id="1" name="store">
    <species name="stud">
        <Category1 name="Category1">
            <x category="Hairs" id="20098288"/>
            <x category="Hairs" id="20098289"/>
        </Category1>
        <Category2 name="Category2">
            <x category="Shirts" id="24342342"/>
            <x category="Shirts" id="24342342"/>
        </Category2>
        <Category3 name="Category3">
            <x category="Jackets" id="423423423"/>
            <x category="Jackets" id="423423423"/>
        </Category3>
    </species>
</store>
XML;
$xml = simplexml_load_string($buffer);
foreach ($xml->species->Category1->x as $x) {
    echo ' - ', $x->asXML(), "n";
}
$category = 'Category1';
foreach ($xml->species->$category->x as $x) {
    echo ' - ', $x->asXML(), "n";
}
$elements = $xml->species->$category;
if ($elements) foreach ($elements->x as $x) {
    echo ' - ', $x->asXML(), "n";
}

最新更新