【问题标题】:Php Recursive function to parse nested xml tags用于解析嵌套 xml 标签的 PHP 递归函数
【发布时间】:2013-07-05 03:03:54
【问题描述】:

我正在尝试解析此 XML 结构,但找不到使用递归解析“n”深度嵌套标签的方法。 xml结构:

<plist version="1.0">
    <key>1.1.1</key>
    <dict>
        <key>nag</key>
        <integer>1</integer>
    </dict>

    <key>2.2.2</key>
    <dict>
        <key>nag</key>
        <integer>1</integer>
    </dict>

    <key>3.3.3</key>
    <dict>
        <key>show_upgrade_button</key>
        <integer>0</integer>

        <key>nag_startup</key>
        <dict>
            <key>nag_gameover</key>
            <integer>3</integer>
        </dict>

        <key>my_stuff</key>
        <string>1=cb 2=rm 3=cb+rm =leave banner ads off</string>

    </dict>

    <key>4.4.4</key>
    <dict>
        <key>nag</key>
        <integer>1</integer>
    </dict>
</plist>

节点匹配 key - dict 是关键节点 dict 节点内的数据的版本号,但 xml 结构具有任意 dict 嵌套,如您在上面的代码中所见。到目前为止,我有这个递归函数,它接受一个 dict 节点,但我看不到光。

<? php
function recursiveNodes($nodes, $arr){
        $count=0;
        if($nodes->hasChildNodes() === true  ){ 

            foreach($nodes->childNodes as $node){

                $temp = array();
                if($node->nodeName === 'key'){

                    $temp['key_name'] = $node->nodeValue;
                    if($node->nextSibling->nodeName !== 'dict'){
                        $sibling = $node->nextSibling;                      
                        $temp['type_name'] = $sibling ->nodeName;
                        $temp['value_name'] = $sibling ->nodeValue;
                    }
                    if($sibling->nodeName === 'dict'){
                    return recursiveNodes($sibling, $arr[$count++][]=$temp);
                }   
                }

            }

        }
            return $arr;
    }
    ?>

【问题讨论】:

  • 你想用这个 XML 做什么?目前尚不清楚您实际递归查找的是什么。
  • 你想把这个结构扁平化成一个数组吗?你想用递归数组数据结构来表示它吗?
  • 对不起,如果不清楚,我正在尝试获取key nodeValue,以及下一个key 兄弟数据作为数组,我需要将该数据插入到数据库中。假设第一个 对,&lt;key&gt;1.1.1&lt;/key&gt; &lt;dict&gt; &lt;key&gt;nag&lt;/key&gt; &lt;integer&gt;1&lt;/integer&gt; &lt;/dict&gt; 节点我得到“1.1.1”,从 节点一个数组,其子节点 key_name ="nag" 的以下数据, type_name="integer" 和 type_value="1"。
  • @nickb 是的,问题是我不知道它会有多少嵌套的字典。它可能是dict标签内的一对key-dict,它将有更多的嵌套标签或一对key-anytag,它没有更多的子节点
  • 如果递归给您带来 XML 文档的麻烦,请查看 xpath,它通常已经能够返回您,例如一个列表。例如。您可以查询所有以&lt;key&gt; 为兄弟的&lt;dict&gt; 元素。

标签: php xml xml-parsing plist domdocument


【解决方案1】:

你的函数中的递归被破坏了。将其包装成一个对象而不是单个函数可能更容易。

这也将允许根据需要更轻松地扩展它。

请参阅以下用法示例:

$parser = new PlistXMLParser();
$parser->loadXML($xml);
print_r($parser->parse());

根据您的示例性输入,它给出了以下内容:

Array
(
    [1.1.1] => Array
        (
            [nag] => 1
        )

    [2.2.2] => Array
        (
            [nag] => 1
        )

    [3.3.3] => Array
        (
            [show_upgrade_button] => 0
            [nag_startup] => Array
                (
                    [nag_gameover] => 3
                )

            [my_stuff] => 1=cb 2=rm 3=cb+rm =leave banner ads off
        )

    [4.4.4] => Array
        (
            [nag] => 1
        )

)

在内部,这基本上可以按照您的方式工作,请参阅此处摘自the sources

...
switch ($type) {
    case self::NODE_INTEGER:
        $result[$keyString] = sprintf('%0.0f', trim($value));
        break;

    case self::NODE_STRING:
        $result[$keyString] = (string)$value;
        break;

    case self::NODE_DICT:
        $parser = new self();
        $parser->loadSimpleXMLElement($value);
        $result[$keyString] = $parser->parse();
        break;

    default:
        throw new UnexpectedValueException(sprintf('Unexpected type "%s" for key "%s"', $type, $key));
}
...

解析器使用switch 构造来更好地处理XML 结构中出现的各个类型标记。该异常突出显示您尚未实现的功能,并为 NODE_DICT 触发递归,它只是实例化一个新的解析器并让它完成工作。一种非常简单的递归形式。

【讨论】:

  • 非常感谢,它似乎应该可以工作,当尝试运行代码时,它给了我一个操作数错误list($value) = $key-&gt;xpath('following-sibling::*[1]') + [NULL]; 这里,第 33 行,这也适用于带有常规标题的 xml &lt;?xml version="1.0" encoding="UTF-8" .... 再次感谢!简单而强大的代码
  • 代码是用当前最旧的非生命周期结束的 PHP 版本编写的:5.4。请至少将 PHP 升级到 5.4 或向后移植代码 ([NULL] -> array(NULL))。是的,SimpleXMLElement 支持的所有 XML 都由那个支持。在这种情况下,它与 DOMDocument 相当。
【解决方案2】:
//Using SimpleXML library
public function getNodes($root) 
{   
    $output = array();

    if($root->children()) {
        $children = $root->children();   

        foreach($children as $child) {
            if(!($child->children())) {
                $output[] = (array) $child;
            }
            else {
                $output[] = self::getNodes($child->children());
            } 
        }
    }   
    else {
        $output = (array) $root;
    }   

    return $output;
}   

【讨论】:

    猜你喜欢
    • 2011-09-24
    • 2011-01-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-21
    相关资源
    最近更新 更多