使用XPATH从XML文件中检索信息的更好方法

时间:2014-05-23 17:27:59

标签: php xml xpath

到目前为止,我有一个名为Menu.php的非常简单的类,其中包含以下内容:

<?php
class Menu
{
    private $_dom;
    private $categoryItems;

    function __construct()
    {
        if(file_exists('Menu.xml'))
        {
            $this->_dom = simplexml_load_file('Menu.xml');
            }

    }

    public function retrieveMenu($category)
    {       
        $products = $this->_dom->xpath('/menu/category[@name="'.$category.'"]');
        return $products;
    }
} // end of class Menu

我知道,相当简陋,只是出于测试目的。 现在,我还有一个XML文件,如下所示:

<?xml version="1.0" encoding="UTF-8" ?>
<menu>

    <category name="pizza">
        <item name="Tomato and Cheese">
            <type>Regular</type>
            <available>true</available>
            <size name="Small">
                <price>5.50</price>
            </size>
            <size name="Large">
                <price>9.75</price>
            </size>
        </item>
    </category>

    <category name="pizza">
        <item name="Pepperoni">
            <type>Regular</type>
            <available>true</available>
            <size name="Small">
                <price>6.85</price>
            </size>
            <size name="Large">
                <price>10.85</price>
            </size>
        </item>
    </category>

随着多种产品的发展。所以,想法是通过课程访问这个文件, 并实现我在index.php中执行以下操作:

<?php
require 'Menu.php';
$menu = new Menu();
$tests = $menu->retrieveMenu('pizza');
foreach($tests as $test) {
    echo $test->attributes();
    echo '<br />';
    foreach($test->item as $item) {
        echo $item->attributes();
        echo '<br />';
        echo $item->type;
        echo '<br />';
        echo $item->available;
        echo '<br />';
        foreach($item->size as $price) {
            echo $price->attributes();
            echo '<br />';
            echo $price->price;
            echo '<br />';
            echo '<br />';
            echo $price->price;
            echo '<br />';*/
        }
        //echo $item->size->attributes();
        echo '<br /><br /><br /><br />';
    }
}

我给了我预期的结果:

>pizza
>Tomato and Cheese
>Regular
>true
>Small
>5.50
>Large
>9.75

现在,我的问题是:由于我没有使用3个嵌套for循环,因为我没有错,复杂性是n ^ 3,这非常糟糕,原始XML包含很多产品,有吗更好的访问方式?我做错了吗?

顺便说一句,是,我必须使用XML和XPATH

1 个答案:

答案 0 :(得分:1)

在这种情况下,嵌套循环没有错。您可以访问并输出单个资源上的所有子元素。但是,是的,Xpath可以将不同级别的节点提取到列表中。

Xpath表达式可以使用|结合几个位置路径。所以它实际上是三个位置路径,表达式返回所有匹配的节点:

    来自所有元素的
  1. name个属性节点://*/@name
  2. item的子元素,size除外://item/*[not(self::size)]
  3. price item/size {$ 1}}的子元素://item/size/price
  4. 此示例使用DOM:

    $dom = new DOMDocument();
    $dom->loadXml($xml);
    $xpath = new DOMXpath($dom);
    
    $expression = '//*/@name|//item/*[not(self::size)]|//item/size/price';
    
    foreach ($xpath->evaluate($expression) as $node) {
      echo trim($node->nodeValue), "<br/>\n"; 
    }
    

    输出:

    pizza<br/>
    Tomato and Cheese<br/>
    Regular<br/>
    true<br/>
    Small<br/>
    5.50<br/>
    Large<br/>
    9.75<br/>
    pizza<br/>
    Pepperoni<br/>
    Regular<br/>
    true<br/>
    Small<br/>
    6.85<br/>
    Large<br/>
    10.85<br/>
    

    Xpath中的位置路径就像过滤器一样,节点按顺序返回,具体取决于它们在文档中的位置。

    它也适用于SimpleXML:

    $element = simplexml_load_string($xml);
    
    $expression = '//*/@name|//item/*[not(self::size)]|//item/size/price';
    
    foreach ($element->xpath($expression) as $node) {
      echo trim($node), "<br/>\n"; 
    }
    

    演示:https://eval.in/156266