The SimpleXMLIterator class

Введение

...

Class synopsis

SimpleXMLIterator
class SimpleXMLIterator extends SimpleXMLElement implements RecursiveIterator , Traversable , Iterator , Countable {
/* Methods */
mixed current ( void )
object getChildren ( void )
bool hasChildren ( void )
mixed key ( void )
void next ( void )
void rewind ( void )
bool valid ( void )
}

Содержание

Коментарии

The documentation is a bit sparse for SimpleXmlIterator.  Here is an example showing the use of its methods. xml2Array and sxiToArray work together to convert an XML document to an associative array structure.

The contents of cats.xml:
======================================
<cats>
  <cat>
      <name>Jack</name>
      <age>2</age>
      <color>grey</color>
      <color>white</color>
  </cat>
  <cat>
      <name>Maxwell</name>
      <age>12</age>
      <color>orange</color>
      <color>black</color>
  </cat>
</cats>
======================================

<?php
function xml2array($fname){
 
$sxi = new SimpleXmlIterator($fnamenulltrue);
  return 
sxiToArray($sxi);
}

function 
sxiToArray($sxi){
 
$a = array();
  for( 
$sxi->rewind(); $sxi->valid(); $sxi->next() ) {
    if(!
array_key_exists($sxi->key(), $a)){
     
$a[$sxi->key()] = array();
    }
    if(
$sxi->hasChildren()){
     
$a[$sxi->key()][] = sxiToArray($sxi->current());
    }
    else{
     
$a[$sxi->key()][] = strval($sxi->current());
    }
  }
  return 
$a;
}

// Read cats.xml and print the results:
$catArray xml2array('cats.xml');
print_r($catArray);
?>

Results (reformatted a bit for compactness and clarity):
======================================
Array(
  [cat] => Array(
    [0] => Array(
      [name] => Array(  [0] => Jack    )
      [age] => Array(   [0] => 2       )
      [color] => Array( [0] => grey,
                        [1] => white   )
    )
    [1] => Array(
      [name] => Array(  [0] => Maxwell )
      [age] => Array(   [0] => 12      )
      [color] => Array( [0] => orange
                        [1] => black   )
    )
  )
)
2009-07-19 20:08:28
http://php5.kiev.ua/manual/ru/class.simplexmliterator.html
Here's a simple function to convert an XML string to an array -

<?php
// PHP5.3 and above only
function parse($str) {
   
$f = function($iter) {
      foreach(
$iter as $key=>$val)
       
$arr[$key][] = ($iter->hasChildren())?
         
call_user_func (__FUNCTION__$val)
          : 
strval($val);
      return 
$arr;
    };
    return 
$f(new SimpleXmlIterator($strnull));
}
?>

PHP 5.2 and below do not have anonymous functions.
But you can create a helper function to achieve the same thing -

<?php
 
function parse($str) {
    return 
parseHelper(new SimpleXmlIterator($strnull));
  }
  function 
parseHelper($iter) {
    foreach(
$iter as $key=>$val)
     
$arr[$key][] = ($iter->hasChildren())?
       
call_user_func (__FUNCTION__$val)
        : 
strval($val);
    return 
$arr;
  }
?>

Using it is straightforward enough -

<?php

$xml 
'
<movies>
  <movie>abcd</movie>
  <movie>efgh</movie>
  <movie>hijk</movie>
</movies>'
;
var_dump(parse($xml));

?>

This will output -

array
  'movie' => 
    array
      0 => string 'abcd' (length=4)
      1 => string 'efgh' (length=4)
      2 => string 'hijk' (length=4)
2011-03-17 12:14:57
http://php5.kiev.ua/manual/ru/class.simplexmliterator.html
Most of the time we need to convert the XML to array or JSON , but now I have to completed the requirement of converting XML to XPath which make our template easily geting the data from XML data source due to the Xpath mapping .Here is the function:

<?php

function sxiToXpath($sxi$key null, &$tmp null)
{
   
$keys_arr = array();
   
//get the keys count array
   
for ($sxi->rewind(); $sxi->valid(); $sxi->next())
    {
       
$sk $sxi->key();
        if (
array_key_exists($sk$keys_arr))
        {
           
$keys_arr[$sk]+=1;
           
$keys_arr[$sk] = $keys_arr[$sk];
        }
        else
        {
           
$keys_arr[$sk] = 1;
        }
    }
   
//create the xpath 
   
for ($sxi->rewind(); $sxi->valid(); $sxi->next())
    {
       
$sk $sxi->key();
        if (!isset($
$sk))
        {
            $
$sk 1;
        }
        if (
$keys_arr[$sk] >= 1)
        {
           
$spk $sk '[' . $$sk ']';
           
$keys_arr[$sk] = $keys_arr[$sk] - 1;
            $
$sk++;
        }
        else
        {
           
$spk $sk;
        }
       
$kp $key $key '/' $spk '/' $sxi->getName() . '/' $spk;
        if (
$sxi->hasChildren())
        {
           
sxiToXpath($sxi->getChildren(), $kp$tmp);
        }
        else
        {
           
$tmp[$kp] = strval($sxi->current());
        }
       
$at $sxi->current()->attributes();
        if (
$at)
        {
           
$tmp_kp $kp;
            foreach (
$at as $k => $v)
            {
               
$kp .= '/@' $k;
               
$tmp[$kp] = $v;
               
$kp $tmp_kp;
            }
        }
    }
    return 
$tmp;
}

function 
xmlToXpath($xml)
{
   
$sxi = new SimpleXmlIterator($xml);
    return 
sxiToXpath($sxi);
}

/**
 *  How to use the function 
 */
$xml = <<<EOT
<?xml version="1.0" encoding="utf8" ?>       
<data>
   <item ID="30001">
      <Company>Navarro Corp.</Company>
   </item>
   <item ID="30002" IDd="30002">
      <Company>Performant Systems</Company>
   </item>
   <item ID="30003">
      <Company id='id_test'><g id='id_g'>glove</g></Company>   
   </item>
    <item>
    </item>
</data>
EOT;

$rs xmlToXpath($xml);
print_r($rs);

/**
 * the results may lkie this:
Array
(
    [/data/item[1]/Company[1]] => Navarro Corp.
    [/data/item[1]/@ID] => SimpleXMLIterator Object
        (
            [0] => 30001
        )
    [/data/item[2]/Company[1]] => Performant Systems
    [/data/item[2]/@ID] => SimpleXMLIterator Object
        (
            [0] => 30002
        )

    [/data/item[2]/@IDd] => SimpleXMLIterator Object
        (
            [0] => 30002
        )

    [/data/item[3]/Company[1]/g[1]] => glove
    [/data/item[3]/Company[1]/g[1]/@id] => SimpleXMLIterator Object
        (
            [0] => id_g
        )

    [/data/item[3]/Company[1]/@id] => SimpleXMLIterator Object
        (
            [0] => id_test
        )

    [/data/item[3]/@ID] => SimpleXMLIterator Object
        (
            [0] => 30003
        )

    [/data/item[4]] => 
   

 */

echo "Total:" count($rs);

echo 
"<hr>";
/* You can check the xpath result like this */
$xml = new SimpleXMLElement($xml);
foreach (
$rs as $k => $v)
{
    echo 
"Xpath:" $k " |Value:" $v " ";
   
var_dump($xml->xpath($k));
    echo 
"<br>";
}
2013-04-11 07:34:14
http://php5.kiev.ua/manual/ru/class.simplexmliterator.html
I filled my database from an XML file about 1260 Kb.
I made my process less than a second. Simply by using SimpleXML.

I give you a little example of the usage to fill a database.
Given the table universe.
With 4 columns Coords, Planet_Name, Player_id, Moon_Size.

Now You have a XML file named universe.xml with this kind of data.
I enclose the data within php tags but it's a file :p
<?php
$xml 
= <<<EOT
<?xml version="1.0" encoding="UTF-8"?>
<universe xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" -
xsi:noNamespaceSchemaLocation="http://s127-fr.ogame.gameforge.com/api/xsd/universe.xsd" -
timestamp="1405413350" serverId="fr127">
    <planet id="1" player="1" name="Arakis" coords="1:1:2">
        <moon id="2" name="Mond" size="4998"/>
    </planet>
    <planet id="33620176" player="100000" name="GameAdmin" coords="1:1:3"/>
    <planet id="33620179" player="100003" name="Heimatplanet" coords="1:1:1"/>
    <planet id="33620186" player="100004" name="OGame Team" coords="6:250:1"/>
    <planet id="33620242" player="100058" name="KnS" coords="9:1:6">
        <moon id="33668391" name="Lune" size="8831"/>
    </planet>
</universe>
EOT;
?>

Now how to bring these data in my 4 columns table :

<?php
$newfname 
$path."Universe.XML";
$mydata = new SimpleXmlIterator($newfname0true);
$myquery "INSERT INTO `".$tablename."` (`coords`,`planet_name`, `player_id`, `moon_size`) VALUES ";
for (
$mydata->rewind();$mydata->valid();$mydata->next()) {
   
$myquery.= " ('".$mydata->current()->attributes()['coords']
_."','".utf8_decode($mydata->current()->attributes()['name'])
_."','".utf8_decode($mydata->current()->attributes()['player'])
_."','";
    if (
$mydata->haschildren()) {
       
$myquery.= $mydate->current()->children()->attributes()['size']."'),";
    } else {
       
$myquery.= "'),";
    }
}
$myquery rtrim($myquery",");
$datatosql mysql_query($myquery);
?>
2014-07-16 06:22:10
http://php5.kiev.ua/manual/ru/class.simplexmliterator.html
Function to extract SimpleXMLElement data to array.

function extract($sxe = null) {
    if (!$sxe instanceOf SimpleXMLElement)
        return array();

    $extract = array();

    foreach ($sxe->children() as $key => $value) {
        if (array_key_exists($key, $extract)) {
            if (!isset($extract[$key][0])) {
                $tmp_extract = $extract[$key];
                $extract[$key] = array();
                $extract[$key][0] = $tmp_extract; 
            } else
                $extract[$key] = (array) $extract[$key];
        } 

        if ($value->count()) {
            if (isset($extract[$key]) && is_array($extract[$key]))
                $extract[$key][] = $this->extract($value);
            else
                $extract[$key] = $this->extract($value);
        } else {
            if (isset($extract[$key]) && is_array($extract[$key]))
                $extract[$key][] = empty(strval($value)) ? null : strval($value);
            else
                $extract[$key] = empty(strval($value)) ? null : strval($value);
        }
    }

    return $extract;
}
2015-10-06 00:50:34
http://php5.kiev.ua/manual/ru/class.simplexmliterator.html
I think it's worth mentioning that you need to call the rewind() method on the SimpleXMLIterator object immediately after initialization before you can start doing any other operations on the object. An example: 

<?php
$xml 
= new SimpleXMLIterator('file.xml'nulltrue);

// $x here will be set to null because the rewind() method has not been called
$x $xml->current(); 

$xml->rewind(); 

// $x here will be set to the first element
$x $xml->current(); 

?>
2018-12-16 20:54:00
http://php5.kiev.ua/manual/ru/class.simplexmliterator.html
<?php
=======================================================
$index 
<?
xml version="1.0" encoding="UTF-8"?>
<root>
    <article id="8" visibility="true" filename="2020-10-08" fileExtension="xml">
            <tag>xml</tag>
            <tag>php</tag>
            <tag>experiment</tag>       
    </article>
    <article id="7" visibility="true" filename="2020-10-07" fileExtension="xml">
            <tag>xml</tag>
            <tag>php</tag>
            <tag>experiment</tag>       
    </article>
    <article id="6" visibility="true" filename="2020-10-02" fileExtension="xml">
            <tag>xml</tag>
            <tag>php</tag>
            <tag>experiment</tag>       
    </article>
    <article id="5" visibility="true" filename="2020-09-30" fileExtension="xml">
            <tag>xml</tag>
            <tag>php</tag>
            <tag>experiment</tag>       
    </article>
    <article id="4" visibility="true" filename="2020-09-26" fileExtension="xml">
            <tag>xml</tag>
            <tag>php</tag>
            <tag>experiment</tag>       
    </article>
    <article id="3" visibility="true" filename="2020-09-22"     fileExtension="xml">
            <tag>xml</tag>
            <tag>php</tag>
            <tag>experiment</tag>       
    </article>
    <article id="2" visibility="true" filename="2020-09-20"     fileExtension="xml">
            <tag>xml</tag>
            <tag>php</tag>
            <tag>experiment</tag>       
    </article>
        <article id="1" visibility="true" filename="hello world" fileExtension="xml">
            Hello World
            <tag>xml</tag>
            <tag>php</tag>
            <tag>experiment</tag>       
    </article>
</root>
====================================================================
?>
If you have to use an iterator to parse your XML
and need tu get an attribute of tags of this iterator then
use the fonction
->current()
of simpleXMLIterator on your object before 
->attributes()->{attibute name}
<?php
$file
="";
try{
     
$index = new SimpleXMLIterator file_get_contents FILEDIRECTORY'index.xml' ) );}
catch(
Exception $e) {whatever you want to do on error}}

for( 
$index->rewind(); $index->valid(); $index->next() ) {
    try {
         
$file file_get_contents(FILESDIRECTORY.$index->current()->attributes()->{'fileName'}. '.xml' );
    } catch (
Exception $e) {whatever you want to do on error}
   
$article = new Article ();
   
$article->setXMLArticle ($file);
   
array_push$this->articles$article );
   
$file ="";
    }
}
?>
This exemple use a custom made Article object that itself parse the file given to him to initialise its properties .
Here we open a file (Yes I use constant for my directories)
make it a simpleXMLIterator and parse article elements to get the filename attribute to use it to open another XML file for data collection.
don't forget !!! In PHP Object created by new ClassName() are ALWAYS given by reference that is why new Article() in inside the loop and not outside
(yhea, I did that mistake)
XMLIterator are powerfull yet harder to understand in themselves but once passed that one point.
They are very more easier to use than plain arrays.
2020-10-10 15:47:25
http://php5.kiev.ua/manual/ru/class.simplexmliterator.html

    Поддержать сайт на родительском проекте КГБ