Search code examples
phpforeachsimplexml

PHP, simplexml and foreach


This is my first time asking a question here, and I am also a novice at PHP and simple XML, but am determined to learn this.

the problem: my 1st foreach works fab....

the 2nd one dupes the publiccss.tpl into both dirs and ignore the other 2.....

    $xml = simplexml_load_file($target_path);
if($xml['product'] == 'style'){
$sname =                                 str_replace(' ','_',$xml['sname']);
$vers = $xml['version'];
$sp = 'library/templates/'.$sname;
if($i = mysql_query("INSERT INTO skins VALUES ('". mysql_insert_id() ."','". str_replace('_',' ',$sname) ."','". $vers ."','".$sp."')")){
if(!is_dir($sp)) mkdir($sp,0777);
foreach($xml->templategroup as $dir){
$dir = str_replace(' ','_',$dir['name']);
$p = 'library/templates/'.$sname.'/'.$dir;
if(!is_dir($p)) mkdir($p,0777);
foreach($xml->templategroup->template as $tpl){
$p = 'library/templates/'.$sname.'/'.$dir.'/'.str_replace(' ','_',$tpl['name']);            
$fp = fopen($p,"wb");
fwrite($fp,$tpl);
fclose($fp);
}
}
}else{
echo mysql_error();
}
}else{
echo 'Not a style';
}
}


<?xml version="1.0" encoding="ISO-8859-1"?>

<style sname="DSkin" version="1.0.0" product="style">
<templategroup name="CSS Templates">
<template name="PublicCSS.tpl" date="" username="Andy?">
#body{}
</template>
</templategroup>
<templategroup name="Forum Home">
<template name="Forumhome.tpl" date="" username="Andy?">
Main index page.
</template>
<template name="Forumhome_L.tpl" date="" username="Andy?">
Level one forums.       
</template>

</templategroup>
</style>    $xml = simplexml_load_file($target_path);
if($xml['product'] == 'style'){
$sname =                                 str_replace(' ','_',$xml['sname']);
$vers = $xml['version'];
$sp = 'library/templates/'.$sname;
if($i = mysql_query("INSERT INTO skins VALUES ('". mysql_insert_id() ."','". str_replace('_',' ',$sname) ."','". $vers ."','".$sp."')")){
if(!is_dir($sp)) mkdir($sp,0777);
foreach($xml->templategroup as $dir){
$dir = str_replace(' ','_',$dir['name']);
$p = 'library/templates/'.$sname.'/'.$dir;
if(!is_dir($p)) mkdir($p,0777);
foreach($xml->templategroup->template as $tpl){
$p = 'library/templates/'.$sname.'/'.$dir.'/'.str_replace(' ','_',$tpl['name']);            
$fp = fopen($p,"wb");
fwrite($fp,$tpl);
fclose($fp);
}
}
}else{
echo mysql_error();
}
}else{
echo 'Not a style';
}
}


<?xml version="1.0" encoding="ISO-8859-1"?>

<style sname="DSkin" version="1.0.0" product="style">
<templategroup name="CSS Templates">
<template name="PublicCSS.tpl" date="" username="Andy?">
#body{}
</template>
</templategroup>
<templategroup name="Forum Home">
<template name="Forumhome.tpl" date="" username="Andy?">
Main index page.
</template>
<template name="Forumhome_L.tpl" date="" username="Andy?">
Level one forums.       
</template>

</templategroup>
</style>

Solution

  • The way you've written the second loop is going back to the root of the document, and SimpleXML doesn't know which templategroup you want, so it assumes you just want the first one:

    $xml->templategroup->template
    

    is the same as:

    $xml->templategroup[0]->template
    

    You want to loop over all the template elements in the current templategroup from the outer loop, which you've called $dir, so what you actually want ought to be this:

    foreach($dir->template as $tpl){
    

    However, you're overwriting the variable $dir further down, with this line:

    $dir = str_replace(' ','_',$dir['name']);
    

    It's generally a bad idea to use the same variable for two different purposes, and in this case, $dir isn't really a good name for the first purpose, so I suggest you change it to:

    foreach($xml->templategroup as $templategroup){
    

    And:

    $dir = str_replace(' ','_',$templategroup['name']);
    

    Giving you an inner loop of:

    foreach($templategroup->template as $tpl){