PHP基于循环的XML文档过滤

时间:2015-03-26 14:19:08

标签: php xml

我正在尝试过滤掉特定类别的每个XML类别字符串。 我怎么能这样工作?

例如,我只想要类别Category1中的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 ='Category1';

伪代码:

<?php

foreach($species as $species_elem){
    foreach($species_elem which contains $Category1 as $category){
        foreach ($child->x as $item){
            $itemID = $item->attributes()->id;
        }
    }
}

?>

3 个答案:

答案 0 :(得分:1)

XPath将为您节省大量嵌套循环。


实施例

//$xml = your xml string;
$category = 'Category1';

$dom = new DOMDocument();
$dom->loadXML($xml);
$xpath = new DOMXPath($dom);

foreach ($xpath->query("/store/species/$category/x") as $node) {
    echo $dom->saveXML($node), "\n";
}

输出:

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

这是通过PHP的DOM extension来完成的,但如果你真的想要,你可以用SimpleXMLElement::xpath做同样的基本事情。

答案 1 :(得分:1)

Paul Crovella的答案很好。 XPath是要走的路。

但是,节点名称不应编号。如果您可以更改格式,我建议将其更改为更通用的格式,例如“类别”。

使用name属性过滤类别元素。

XPath Step by Step

选择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";
}

答案 2 :(得分:0)

对于您在问题中提出的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";
}