Php用于解析嵌套xml标记的递归函数

时间:2013-07-05 03:03:54

标签: php xml xml-parsing plist domdocument

我正在尝试解析此XML结构,但无法找到使用递归解析“n”-deep嵌套标记的方法。 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 - dictdict节点内数据的版本号的关键节点,但xml结构具有arbrittrary 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;
    }
    ?>

2 个答案:

答案 0 :(得分: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触发了递归,它只是实例化一个新的解析器并让它完成工作。一种非常简单的递归形式。

答案 1 :(得分:0)

//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;
}