note 105697 modified in book.simplexml by danbrown
| From: | danbrown@php.net | Date: | Thu, 08 Sep 2011 16:21:03 +0000 |
| Subject: | note 105697 modified in book.simplexml by danbrown | ||
| References: | 1 | Groups: | php.notes |
| Request: | Send a blank email to php-notes+get-183048@lists.php.net to get a copy of this message | ||
None of the XML2Array functions that I found satisfied me completely; Their results did not always
fit the project I was working on, and I found none that would account for repeating XML elements
(such as
<fields><field/><field/><field/></fields>)
So I rolled out my own; hope it helps someone.
<?php
/**
* Converts a simpleXML element into an array. Preserves attributes.<br/>
* You can choose to get your elements either flattened, or stored in a custom
* index that you define.<br/>
* For example, for a given element
* <code>
* <field name="someName" type="someType"/>
* </code>
* <br>
* if you choose to flatten attributes, you would get:
* <code>
* $array['field']['name'] = 'someName';
* $array['field']['type'] = 'someType';
* </code>
* If you choose not to flatten, you get:
* <code>
* $array['field']['@attributes']['name'] = 'someName';
* </code>
* <br>__________________________________________________________<br>
* Repeating fields are stored in indexed arrays. so for a markup such as:
* <code>
* <parent>
* <child>a</child>
* <child>b</child>
* <child>c</child>
* ...
* </code>
* you array would be:
* <code>
* $array['parent']['child'][0] = 'a';
* $array['parent']['child'][1] = 'b';
* ...And so on.
* </code>
* @param simpleXMLElement $xml the XML to convert
* @param boolean|string $attributesKey if you pass TRUE, all values will be
* stored under an '@attributes' index.
* Note that you can also pass a string
* to change the default index.<br/>
* defaults to null.
* @param boolean|string $childrenKey if you pass TRUE, all values will be
* stored under an '@children' index.
* Note that you can also pass a string
* to change the default index.<br/>
* defaults to null.
* @param boolean|string $valueKey if you pass TRUE, all values will be
* stored under an '@values' index. Note
* that you can also pass a string to
* change the default index.<br/>
* defaults to null.
* @return array the resulting array.
*/
function simpleXMLToArray(SimpleXMLElement
$xml,$attributesKey=null,$childrenKey=null,$valueKey=null){
if($childrenKey && !is_string($childrenKey)){$childrenKey = '@children';}
if($attributesKey && !is_string($attributesKey)){$attributesKey = '@attributes';}
if($valueKey && !is_string($valueKey)){$valueKey = '@values';}
$return = array();
$name = $xml->getName();
$_value = trim((string)$xml);
if(!strlen($_value)){$_value = null;};
if($_value!==null){
if($valueKey){$return[$valueKey] = $_value;}
else{$return = $_value;}
}
$children = array();
$first = true;
foreach($xml->children() as $elementName => $child){
$value = simpleXMLToArray($child,$attributesKey, $childrenKey,$valueKey);
if(isset($children[$elementName])){
if(is_array($children[$elementName])){
if($first){
$temp = $children[$elementName];
unset($children[$elementName]);
$children[$elementName][] = $temp;
$first=false;
}
$children[$elementName][] = $value;
}else{
$children[$elementName] = array($children[$elementName],$value);
}
}
else{
$children[$elementName] = $value;
}
}
if($children){
if($childrenKey){$return[$childrenKey] = $children;}
else{$return = array_merge($return,$children);}
}
$attributes = array();
foreach($xml->attributes() as $name=>$value){
$attributes[$name] = trim($value);
}
if($attributes){
if($attributesKey){$return[$attributesKey] = $attributes;}
else{$return = array_merge($return, $attributes);}
}
return $return;
}
?>
--was--
Improved version of my simpleXMLToArray. If a moderator could delete/replace my previous version,
which has a bug, it would be great.
<?php
/**
* Converts a simpleXML element into an array. Preserves attributes.<br/>
* You can choose to get your elements either flattened, or stored in a custom
* index that you define.<br/>
* For example, for a given element
* <code>
* <field name="someName" type="someType"/>
* </code>
* <br>
* if you choose to flatten attributes, you would get:
* <code>
* $array['field']['name'] = 'someName';
* $array['field']['type'] = 'someType';
* </code>
* If you choose not to flatten, you get:
* <code>
* $array['field']['@attributes']['name'] = 'someName';
* </code>
* <br>__________________________________________________________<br>
* Repeating fields are stored in indexed arrays. so for a markup such as:
* <code>
* <parent>
* <child>a</child>
* <child>b</child>
* <child>c</child>
* ...
* </code>
* you array would be:
* <code>
* $array['parent']['child'][0] = 'a';
* $array['parent']['child'][1] = 'b';
* ...And so on.
* </code>
* @param simpleXMLElement $xml the XML to convert
* @param boolean|string $attributesKey if you pass TRUE, all values will be
* stored under an '@attributes' index.
* Note that you can also pass a string
* to change the default index.<br/>
* defaults to null.
* @param boolean|string $childrenKey if you pass TRUE, all values will be
* stored under an '@children' index.
* Note that you can also pass a string
* to change the default index.<br/>
* defaults to null.
* @param boolean|string $valueKey if you pass TRUE, all values will be
* stored under an '@values' index. Note
* that you can also pass a string to
* change the default index.<br/>
* defaults to null.
* @return array the resulting array.
*/
function simpleXMLToArray(SimpleXMLElement
$xml,$attributesKey=null,$childrenKey=null,$valueKey=null){
if($childrenKey && !is_string($childrenKey)){$childrenKey = '@children';}
if($attributesKey && !is_string($attributesKey)){$attributesKey = '@attributes';}
if($valueKey && !is_string($valueKey)){$valueKey = '@values';}
$return = array();
$name = $xml->getName();
$_value = trim((string)$xml);
if(!strlen($_value)){$_value = null;};
if($_value!==null){
if($valueKey){$return[$valueKey] = $_value;}
else{$return = $_value;}
}
$children = array();
$first = true;
foreach($xml->children() as $elementName => $child){
$value = simpleXMLToArray($child,$attributesKey, $childrenKey,$valueKey);
if(isset($children[$elementName])){
if(is_array($children[$elementName])){
if($first){
$temp = $children[$elementName];
unset($children[$elementName]);
$children[$elementName][] = $temp;
$first=false;
}
$children[$elementName][] = $value;
}else{
$children[$elementName] = array($children[$elementName],$value);
}
}
else{
$children[$elementName] = $value;
}
}
if($children){
if($childrenKey){$return[$childrenKey] = $children;}
else{$return = array_merge($return,$children);}
}
$attributes = array();
foreach($xml->attributes() as $name=>$value){
$attributes[$name] = trim($value);
}
if($attributes){
if($attributesKey){$return[$attributesKey] = $attributes;}
else{$return = array_merge($return, $attributes);}
}
return $return;
}
?>
PS: I have read and understood "What not to post", but the previous version had a bug;
knowing the number of people that use php.net as a reference, I could not possibly leave it like
that.
http://php.net/manual/en/book.simplexml.php