我需要一个递归的php函数来循环遍历xml文件

问题描述:

I'm trying to loop through a xml file and save nodes pared with it's value into an array (key => value). I also want it to keep track of the nodes it passed (something like array(users_user_name => "myName", users_user_email => "myEmail") etc.).

I know how to do this but there is a problem. All the nodes could have children and those children might also have children etc. so I need some sort of recursive function to keep looping through the children until it reaches the last child.

So far I got this:

//loads the xml file and creates simpleXML object
        $xml = simplexml_load_string($content);

        // for each root value
        foreach ($xml->children() as $children) {
            // for each child of the root node
            $node = $children;
            while ($children->children()) {
                foreach ($children as $child) {

                    if($child->children()){
                        break;
                    }
                    $children = $node->getName();
                    //Give key a name
                    $keyOfValue = $xml->getName() . "_" . $children . "_" . $child->getName();
                    // pass value from child to children
                    $children = $child;

                    // no children, fill array: key => value
                    if ($child->children() == false) {
                        $parent[$keyOfValue] = (string)$child;
                    }
                }
            }
            $dataObject[] = $parent;
        }

The "break;" is to prevent it from giving me the wrong values because "child" is an object and not the last child.

我正在尝试遍历一个xml文件,并将节点与它的值保存在一个数组中(key => ;价值)。 我还希望它跟踪它传递的节点(例如array(users_user_name =>“myName”,users_user_email =>“myEmail”)等)。 p>

我知道怎么做但是有问题。 所有的节点都可以有孩子,那些孩子也可能有孩子等。所以我需要某种递归功能来保持孩子们的循环直到它到达最后一个孩子。 p>

到目前为止我得到了这个: p>

  //加载xml文件并创建simpleXML对象
 $ xml = simplexml_load_string($ content  ); 
 
 //为每个根值
 foreach($ xml-> children()为$ children){
 //为根节点的每个子节点
 $ node = $ children; 
  while($ children-> children()){
 foreach($ children as $ child){
 
 if($ child-> children()){
 break; 
} 
 $ children  = $ node-> getName(); 
 //为密钥命名
 $ keyOfValue = $ xml-> getName()。  “_”。  $ children。  “_”。  $ child-> getName(); 
 //将值从子级传递给子级
 $ children = $ child; 
 
 //没有子级,填充数组:key =>  value 
 if($ child-> children()== false){
 $ parent [$ keyOfValue] =(string)$ child; 
} 
} 
} 
 $ dataObject [] = $  parent; 
} 
  code>  pre> 
 
 

“break;” 是为了防止它给我错误的值,因为“child”是一个对象,而不是最后一个孩子。 p> div>

Using recursion, you can write some 'complicated' processing, but the problem is loosing your place.

The function I use here passed in a couple of things to keep track of the name and the current output, but also the node it's currently working with. As you can see - the method checks if there are any child nodes and calls the function again to process each one of them.

$content = <<< XML
<users>
    <user>
        <name>myName</name>
        <email>myEmail</email>
        <address><line1>address1</line1><line2>address2</line2></address>
    </user>
</users>
XML;

function processNode ( $base, SimpleXMLElement $node, &$output )  {
    $base[] = $node->getName();
    $nodeName = implode("_", $base);
    $childNodes = $node->children();
    if ( count($childNodes) == 0 )  {
        $output[ $nodeName ] = (string)$node;
    }
    else    {
        foreach ( $childNodes as $newNode ) {
            processNode($base, $newNode, $output);
        }
    }
}

$xml = simplexml_load_string($content);
$output = [];
processNode([], $xml, $output);
print_r($output);

This prints out...

Array
(
    [users_user_name] => myName
    [users_user_email] => myEmail
    [users_user_address_line1] => address1
    [users_user_address_line2] => address2
)

With this implementation, there are limitations to the content - so for example - repeating content will only keep the last value (say for example there were multiple users).

You'll want to use recursion!

Here's a simple example of recursion:

function doThing($param) {
    // Do what you need to do
    $param = alterParam($param);
    // If there's more to do, do it again
    if ($param != $condition) {
        $param = doThing($param);
    }
    // Otherwise, we are ready to return the result
    else {
        return $param;
    }
}

You can apply this thinking to your specific use case.

//Using SimpleXML library 


// Parses XML but returns an Object for child nodes

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