使用PHP中的SimpleXML从XML文件中提取数据

时间:2010-04-05 12:59:00

标签: php simplexml

简介

我想循环使用灵活的类别结构的XML文件。

问题:

我不知道循环理论的infinte子类别而不必为每个“语句”制作x量(参见底部的编码示例)。如何动态遍历类别结构?

<?xml version="1.0" encoding="utf-8"?>
<catalog>
    <category name="Category - level 1">
        <category name="Category - level 2" />
        <category name="Category - level 2">
            <category name="Category - level 3" />
        </category>
        <category name="Category - level 2">
            <category name="Category - level 3">
                <category name="Category - level 4" />
            </category>
        </category>
    </category>
</catalog>

我现在拥有的内容:

使用set结构循环遍历XML文件没有问题:

<catalog>
    <category name="Category - level 1">
        <category name="Category - level 2">
            <category name="Category - level 3" />
        </category>
        <category name="Category - level 2">
            <category name="Category - level 3" />
        </category>
    </category>
</catalog>

编码示例:

//$xml holds the XML file
foreach ( $xml AS $category_level1 )
{
    echo $category_level1['name'];

    foreach ( $category_level1->category AS $category_level2 )
    {
        echo $category_level2['name'];

        foreach ( $category_level2->category AS $category_level3 )
        {
           echo $category_level3['name'];
        }
    }
}

4 个答案:

答案 0 :(得分:6)

通过XPath获取类别中的名称属性可能是最快的,例如

$categoryNames = $doc->xpath('//category/@name');

但是,如果要递归迭代任意嵌套的XML结构,还可以使用SimpleXMLIterator,例如{0}}。 $xml是您提供的字符串:

$sxi = new RecursiveIteratorIterator(
           new SimpleXMLIterator($xml), 
           RecursiveIteratorIterator::SELF_FIRST);

foreach($sxi as $node) {
    echo str_repeat("\t", $sxi->getDepth()), // indenting
         $node['name'],                      // getting attribute name
         PHP_EOL;                            // line break
}

将给出

Category - level 1
    Category - level 2
    Category - level 2
        Category - level 3
    Category - level 2
        Category - level 3
            Category - level 4

就像开头所说的那样,当只想获取所有名称属性时,使用XPath,因为遍历每个节点都很慢。仅当您想要对节点执行更复杂的操作时才使用此方法,例如向其添加内容。

答案 1 :(得分:2)

<?php
$xml= new SimpleXMLElement('.....');
foreach ($xml->xpath('//category') as $cat)
{
    echo $cat['name'];
}

答案 2 :(得分:1)

一种可能的解决方案是编写recursive function,即:

  • 当前深度的Foreach类别
    • 写下当前类别的名称
    • 如果有任何儿童类型,请自行调整。

这种解决方案的一个优点是,您可以在XML文档中跟踪当前的深度 - 如果您需要将数据表示为树,则可能非常有用实例


例如,如果您的XML加载如下:

$string = <<<XML
<catalog>
    <category name="Category - level 1">
        <category name="Category - level 2">
            <category name="Category - level 3" />
        </category>
        <category name="Category - level 2">
            <category name="Category - level 3" />
        </category>
    </category>
</catalog>
XML;

$xml = simplexml_load_string($string);


您可以像这样调用递归函数:

recurse_category($xml);


而这个功能可以这样写:

function recurse_category($categories, $depth = 0) {
    foreach ($categories as $category) {
        echo str_repeat('&nbsp; ', 2*$depth);
        echo (string)$category['name'];
        echo '<br />';

        if ($category->category) {
            recurse_category($category->category, $depth + 1);
        }
    }
}


最后,运行此代码将提供此类输出:

Category - level 1
    Category - level 2
        Category - level 3
    Category - level 2
        Category - level 3

答案 3 :(得分:1)

使用simplexml和xpath作为精细
...但是作为旁注,如果您想要实现的只是获取文档DOMDocument::getElementsByTagName()中每个<category>元素的name属性就足够了。
您可以通过dom_import_simplexml()simplexml_import_dom()在DOM和simplexml之间切换。两者都使用相同的内部数据表示,因此不需要进行昂贵的转换。

$xml = '<?xml version="1.0" encoding="utf-8"?>
<catalog>
    <category name="Category - level 1">
        <category name="Category - level 2" />
        <category name="Category - level 2">
            <category name="Category - level 3" />
        </category>
        <category name="Category - level 2">
            <category name="Category - level 3">
                <category name="Category - level 4" />
            </category>
        </category>
    </category>
</catalog>';

$doc = new DOMDocument;
$doc->loadxml($xml);

foreach( $doc->getElementsByTagName('category') as $c) {
  echo $c->getAttribute('name'), "\n";
}

打印

Category - level 1
Category - level 2
Category - level 2
Category - level 3
Category - level 2
Category - level 3
Category - level 4