我想将以下XML转换成PHP数组。有什么建议吗?
<aaaa Version="1.0">
<bbb>
<cccc>
<dddd Id="id:pass" />
<eeee name="hearaman" age="24" />
</cccc>
</bbb>
</aaaa>
简单!
$xml = simplexml_load_string($xmlstring, "SimpleXMLElement", LIBXML_NOCDATA);
$json = json_encode($xml);
$array = json_decode($json,TRUE);
$xml = new SimpleXMLElement($xmlString);
echo $xml->bbb->cccc->dddd['Id'];
echo $xml->bbb->cccc->eeee['name'];
// or...........
foreach ($xml->bbb->cccc as $element) {
foreach($element as $key => $val) {
echo "{$key}: {$val}";
}
}
[CDATA[TEXT]]
,但是它们无法解析。它被解析为 SimpleXMLElement Object
。有什么解决方法吗? - masterFly$buffer
)转换为简化的数组,忽略属性并分组具有相同名称的(非空)子元素。function XML2Array(SimpleXMLElement $parent)
{
$array = array();
foreach ($parent as $name => $element) {
($node = & $array[$name])
&& (is_array($node) || ($node = array($node)))
&& $node = & $node[];
$node = $element->count() ? XML2Array($element) : trim($element);
}
return $array;
}
$xml = simplexml_load_string($buffer);
$array = XML2Array($xml);
$array = array($xml->getName() => $array);
print_r($array)
):Array
(
[aaaa] => Array
(
[bbb] => Array
(
[cccc] => Array
(
[dddd] =>
[eeee] =>
)
)
)
)
如果您还想要属性,可以通过SimpleXMLElement的JSON编码/解码来获取。这通常是最简单快捷的解决方案:
$xml = simplexml_load_string($buffer);
$array = json_decode(json_encode((array) $xml), true);
$array = array($xml->getName() => $array);
结果:
Array
(
[aaaa] => Array
(
[@attributes] => Array
(
[Version] => 1.0
)
[bbb] => Array
(
[cccc] => Array
(
[dddd] => Array
(
[@attributes] => Array
(
[Id] => id:pass
)
)
[eeee] => Array
(
[@attributes] => Array
(
[name] => hearaman
[age] => 24
)
)
)
)
)
)
&& (is_countable($node) && 1 === count($node) ? $node = array($node) : 1)
,但是在下一行我遇到了一个错误:[] operator not supported for strings
。 - andreshg112$array = json_decode(json_encode((array)simplexml_load_string($xml)),true);
json_encode
和 json_decode
。 - Ismael Miguel$array
变量中没有文本值,可能是因为CDATA。要解决此问题,请使用以下代码加载XML:new SimpleXMLElement($xml, LIBXML_NOCDATA)
。 - Jonathan Petitcolas<?xml version="1.0" encoding="UTF-8"?><note a="b"><body c="d">Hello!</body></note>
,那段代码也无法转换。运行代码,你会发现 <body> 的 c
属性丢失了!如果你不想有任何坏的惊喜,请在这里检查完整的代码 https://github.com/gaarf/XML-string-to-PHP-array/blob/master/xmlstr_to_array.php 或者看看我的答案 https://dev59.com/cWw15IYBdhLWcg3wfb3i#30234924 - Francesco Casula$xml = '<container><element attribute="123">abcd</element></container>';
print_r(json_decode(json_encode(simplexml_load_string($xml, "SimpleXMLElement", LIBXML_NOCDATA)),1));
Array
(
[element] => abcd
)
我的解决方案(我希望我能够在这里给出信用,因为我肯定是从某个地方调整过来的):
function XMLtoArray($xml) {
$previous_value = libxml_use_internal_errors(true);
$dom = new DOMDocument('1.0', 'UTF-8');
$dom->preserveWhiteSpace = false;
$dom->loadXml($xml);
libxml_use_internal_errors($previous_value);
if (libxml_get_errors()) {
return [];
}
return DOMtoArray($dom);
}
function DOMtoArray($root) {
$result = array();
if ($root->hasAttributes()) {
$attrs = $root->attributes;
foreach ($attrs as $attr) {
$result['@attributes'][$attr->name] = $attr->value;
}
}
if ($root->hasChildNodes()) {
$children = $root->childNodes;
if ($children->length == 1) {
$child = $children->item(0);
if (in_array($child->nodeType,[XML_TEXT_NODE,XML_CDATA_SECTION_NODE])) {
$result['_value'] = $child->nodeValue;
return count($result) == 1
? $result['_value']
: $result;
}
}
$groups = array();
foreach ($children as $child) {
if (!isset($result[$child->nodeName])) {
$result[$child->nodeName] = DOMtoArray($child);
} else {
if (!isset($groups[$child->nodeName])) {
$result[$child->nodeName] = array($result[$child->nodeName]);
$groups[$child->nodeName] = 1;
}
$result[$child->nodeName][] = DOMtoArray($child);
}
}
}
return $result;
}
$xml = '
<aaaa Version="1.0">
<bbb>
<cccc>
<dddd id="123" />
<eeee name="john" age="24" />
<ffff type="employee">Supervisor</ffff>
</cccc>
</bbb>
</aaaa>
';
print_r(XMLtoArray($xml));
Array
(
[aaaa] => Array
(
[@attributes] => Array
(
[Version] => 1.0
)
[bbb] => Array
(
[cccc] => Array
(
[dddd] => Array
(
[@attributes] => Array
(
[id] => 123
)
)
[eeee] => Array
(
[@attributes] => Array
(
[name] => john
[age] => 24
)
)
[ffff] => Array
(
[@attributes] => Array
(
[type] => employee
)
[_value] => Supervisor
)
)
)
)
)
<?php
/**
* convert xml string to php array - useful to get a serializable value
*
* @param string $xmlstr
* @return array
*
* @author Adrien aka Gaarf & contributors
* @see http://gaarf.info/2009/08/13/xml-string-to-php-array/
*/
function xmlstr_to_array($xmlstr) {
$doc = new DOMDocument();
$doc->loadXML($xmlstr);
$root = $doc->documentElement;
$output = domnode_to_array($root);
$output['@root'] = $root->tagName;
return $output;
}
function domnode_to_array($node) {
$output = array();
switch ($node->nodeType) {
case XML_CDATA_SECTION_NODE:
case XML_TEXT_NODE:
$output = trim($node->textContent);
break;
case XML_ELEMENT_NODE:
for ($i=0, $m=$node->childNodes->length; $i<$m; $i++) {
$child = $node->childNodes->item($i);
$v = domnode_to_array($child);
if(isset($child->tagName)) {
$t = $child->tagName;
if(!isset($output[$t])) {
$output[$t] = array();
}
$output[$t][] = $v;
}
elseif($v || $v === '0') {
$output = (string) $v;
}
}
if($node->attributes->length && !is_array($output)) { //Has attributes but isn't an array
$output = array('@content'=>$output); //Change output into an array.
}
if(is_array($output)) {
if($node->attributes->length) {
$a = array();
foreach($node->attributes as $attrName => $attrNode) {
$a[$attrName] = (string) $attrNode->value;
}
$output['@attributes'] = $a;
}
foreach ($output as $t => $v) {
if(is_array($v) && count($v)==1 && $t!='@attributes') {
$output[$t] = $v[0];
}
}
}
break;
}
return $output;
}
很惊讶没有人提到 xml_parse_into_struct
:
$simple = "<para><note>simple note</note></para>";
$p = xml_parser_create();
xml_parse_into_struct($p, $simple, $vals, $index);
xml_parser_free($p);
echo "Index array\n";
print_r($index);
echo "\nVals array\n";
print_r($vals);
更多详细信息请访问https://github.com/sapankumarmohanty/lamp/blob/master/Crate-XML-2-Array
//将XML和SOAP XML转换为数组
function xml2array($contents, $get_attributes = 1, $priority = 'tag')
{
if (!$contents) return array();
if (!function_exists('xml_parser_create')) {
// print "'xml_parser_create()' function not found!";
return array();
}
// Get the XML parser of PHP - PHP must have this module for the parser to work
$parser = xml_parser_create('');
xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, "UTF-8"); // http://minutillo.com/steve/weblog/2004/6/17/php-xml-and-character-encodings-a-tale-of-sadness-rage-and-data-loss
xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
xml_parse_into_struct($parser, trim($contents) , $xml_values);
xml_parser_free($parser);
if (!$xml_values) return; //Hmm...
// Initializations
$xml_array = array();
$parents = array();
$opened_tags = array();
$arr = array();
$current = & $xml_array; //Refference
// Go through the tags.
$repeated_tag_index = array(); //Multiple tags with same name will be turned into an array
foreach($xml_values as $data) {
unset($attributes, $value); //Remove existing values, or there will be trouble
// This command will extract these variables into the foreach scope
// tag(string), type(string), level(int), attributes(array).
extract($data); //We could use the array by itself, but this cooler.
$result = array();
$attributes_data = array();
if (isset($value)) {
if ($priority == 'tag') $result = $value;
else $result['value'] = $value; //Put the value in a assoc array if we are in the 'Attribute' mode
}
// Set the attributes too.
if (isset($attributes) and $get_attributes) {
foreach($attributes as $attr => $val) {
if ( $attr == 'ResStatus' ) {
$current[$attr][] = $val;
}
if ($priority == 'tag') $attributes_data[$attr] = $val;
else $result['attr'][$attr] = $val; //Set all the attributes in a array called 'attr'
}
}
// See tag status and do the needed.
//echo"<br/> Type:".$type;
if ($type == "open") { //The starting of the tag '<tag>'
$parent[$level - 1] = & $current;
if (!is_array($current) or (!in_array($tag, array_keys($current)))) { //Insert New tag
$current[$tag] = $result;
if ($attributes_data) $current[$tag . '_attr'] = $attributes_data;
//print_r($current[$tag . '_attr']);
$repeated_tag_index[$tag . '_' . $level] = 1;
$current = & $current[$tag];
}
else { //There was another element with the same tag name
if (isset($current[$tag][0])) { //If there is a 0th element it is already an array
$current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;
$repeated_tag_index[$tag . '_' . $level]++;
}
else { //This section will make the value an array if multiple tags with the same name appear together
$current[$tag] = array(
$current[$tag],
$result
); //This will combine the existing item and the new item together to make an array
$repeated_tag_index[$tag . '_' . $level] = 2;
if (isset($current[$tag . '_attr'])) { //The attribute of the last(0th) tag must be moved as well
$current[$tag]['0_attr'] = $current[$tag . '_attr'];
unset($current[$tag . '_attr']);
}
}
$last_item_index = $repeated_tag_index[$tag . '_' . $level] - 1;
$current = & $current[$tag][$last_item_index];
}
}
elseif ($type == "complete") { //Tags that ends in 1 line '<tag />'
// See if the key is already taken.
if (!isset($current[$tag])) { //New Key
$current[$tag] = $result;
$repeated_tag_index[$tag . '_' . $level] = 1;
if ($priority == 'tag' and $attributes_data) $current[$tag . '_attr'] = $attributes_data;
}
else { //If taken, put all things inside a list(array)
if (isset($current[$tag][0]) and is_array($current[$tag])) { //If it is already an array...
// ...push the new element into that array.
$current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;
if ($priority == 'tag' and $get_attributes and $attributes_data) {
$current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;
}
$repeated_tag_index[$tag . '_' . $level]++;
}
else { //If it is not an array...
$current[$tag] = array(
$current[$tag],
$result
); //...Make it an array using using the existing value and the new value
$repeated_tag_index[$tag . '_' . $level] = 1;
if ($priority == 'tag' and $get_attributes) {
if (isset($current[$tag . '_attr'])) { //The attribute of the last(0th) tag must be moved as well
$current[$tag]['0_attr'] = $current[$tag . '_attr'];
unset($current[$tag . '_attr']);
}
if ($attributes_data) {
$current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;
}
}
$repeated_tag_index[$tag . '_' . $level]++; //0 and 1 index is already taken
}
}
}
elseif ($type == 'close') { //End of tag '</tag>'
$current = & $parent[$level - 1];
}
}
return ($xml_array);
}
// Let's call the this above function xml2array
xml2array($xmlContent, $get_attributes = 3, $priority = 'tag'); // it will work 100% if not ping me @skype: sapan.mohannty
// Enjoy coding
两行代码 (https://www.php.net/manual/en/book.simplexml.php#113485)
$xml = new SimpleXMLElement("<your><xml><string>ok</string></xml></your>");
$array = (array)$xml;
我知道我来晚了10亿年,但我和你遇到了相同的问题,需要更复杂的解决方案,所以这里有一个函数(xml_decode()
),可以将SimpleXMLElements
转换为PHP数组,而不会丢失属性,并带有参数,以便进行更多定制化使用。
val()
函数旨在让您自定义如何处理元素值 - 例如,如果您想将<elem>true</elem>
转换为true
,而不是"true"
。
免责声明:我知道只需使用PHP SimpleXML扩展就可以轻松解决问题,但我需要将大量XML文件转换为JSON文件,以进行我的项目中的重大更改。此外,这个问题是关于如何将XML转换为PHP数组,而不是如何在PHP中使用XML。
<?php
function val($input) {
return strval($input);
}
/**
* Transform an SimpleXMLElement into an associative array.
*
* @param SimpleXMLElement $xml The XML element to be decoded.
*
* @param bool $attributes_key If the element attributes should be grouped into a single element.
*
* Example: <elem foo="true" bar="false" />
*
* If true, xml_decode() will output
* array("attributes" => array("foo" => "true", "bar" => "false"))
*
* If false, xml_decode() will output
* array("foo" => "true", "bar" => "false")
*
* @param bool $reduce If unecessary keys created due to XML structure should be eliminated.
*
* Example: <fruits><fruit>apple</fruit><fruit>banana</fruit></fruits>
*
* If true, xml_decode() will output the element as
* array("fruits" => array(0 => "apple", 1 => "banana"))
*
* If false, xml_decode() will output the element as
* array("fruits" => array("fruit" => array(0 => "apple", 1 => "banana")))
*
* @param array $always_array List of which childs should be treated aways as an array.
*
* Example: <fruits><fruit>apple</fruit></fruits>
*
* If array("fruit") is passed as $aways_array, xml_decode() will output the element as
* array("fruits" => array("fruit" => array(0 => "apple")))
*
* If not, xml_decode() will output the element as
* array("fruits" => array("fruit" => "apple"))
*
* @param array $value_keys List of custom element's value names. This argument is only
* used when values need to passed as elements because of attributes or other reasons.
*
* The default value key name is "value".
*
* Example: <fruits><fruit id="123">apple</fruit></fruits>
*
* If array("fruit" => "name) is passed as $value_keys, xml_decode() will output the element as
* array("fruits" => array("fruit" => array("attributes" => array("id" => "123"), "name" => "apple")))
*
* If not, xml_decode() will output the element as
* array("fruits" => array("fruit" => array("attributes" => array("id" => "123"), "value" => "apple")))
*/
function xml_decode(SimpleXMLElement $xml, bool $attributes_key = true, bool $reduce = true,
array $always_array = array(), array $value_keys = array()): string|array {
// Inicialize the array.
$arr = array();
// XML tag name.
$xml_name = $xml->getName();
// Turn attributes into elements.
foreach ($xml->attributes() as $key => $value) {
// Use a key for attributes if $attributes_key argument is true.
if ($attributes_key) {
$arr['attributes'][val($key)] = val($value);
} else {
$arr[val($key)] = val($value);
}
}
// Count children.
$children_count = $xml->children()->count();
// No children? Value will be text.
if ($children_count == 0) {
// If attributes were found and turned into elements
// the value shall be an element.
if (count($arr) > 0) {
// If attributes were found previosly.
$key = $value_keys[$xml_name] ?? $value_keys['*'] ?? "value";
$arr[$key] = val($xml);
// Else, no need for an array.
} else {
$arr = val($xml);
}
// Children? Loop continues.
} else {
// Defines if there are unecessary array keys - due to the XML structure - to be cut.
// Example: <fruits><fruit /><fruit /><fruits />
// could be turned into arr['fruits'][0] and arr['fruits'][1] instead of
// arr['fruits']['fruit'][0] and arr['fruits']['fruit'][1] for a
// cleaner organization.
$children_names = array();
foreach ($xml->children() as $child) {
$child_name = $child->getName();
in_array($child_name, $children_names) or $children_names[] = $child_name;
}
$reducible = empty($arr) && count($children_names) === 1;
foreach ($xml->children() as $child) {
// Child's name shall be the element key.
$name = $child->getName();
// Children with the same name will be turned into a list.
// Example: $arr['repeating-child'][...] = $value;
if ($xml->$name->count() > 1 || in_array($name, $always_array)) {
// Reduction, if possible and requested by the $reduce argument.
if ($reduce && $reducible) {
$arr[] = xml_decode($child, $attributes_key, $reduce, $always_array, $value_keys);
} else {
$arr[$name][] = xml_decode($child, $attributes_key, $reduce, $always_array, $value_keys);
}
// Normal children will be normally decoded.
// Example: $arr['no-repeating-child] = $value;
} else {
$arr[$name] = xml_decode($child, $attributes_key, $reduce, $always_array, $value_keys);
}
}
}
return $arr;
}
对所有文档和注释进行总结后,该函数将属性和元素值转换为简单的数组元素,并使用循环处理包含子元素的元素。
参数允许您:
fruits->fruit
转换为 $arr['fruits'] ['fruit'][n]
);使用您的XML元素的示例用法(我想您在11年后已经解决了它,但我正在回答,所以...):
test.xml
<test>
<aaaa Version="1.0">
<bbb>
<cccc>
<dddd Id="id:pass" />
<eeee name="hearaman" age="24" />
</cccc>
</bbb>
</aaaa>
</test>
PHP
$xml = simplexml_load_file("test.xml");
$decode = xml_decode($xml);
echo "<pre>" . print_r($decode,true) . "</pre>";
输出
Array
(
[aaaa] => Array
(
[attributes] => Array
(
[Version] => 1.0
)
[bbb] => Array
(
[cccc] => Array
(
[dddd] => Array
(
[attributes] => Array
(
[Id] => id:pass
)
[value] =>
)
[eeee] => Array
(
[attributes] => Array
(
[name] => hearaman
[age] => 24
)
[value] =>
)
)
)
)
)
__toString()
方法的存在,您可能希望使用val()
函数来执行类似return $input === "true" ? true : $input;
的操作,因为JSON接受除字符串以外的其他数据类型。我将其返回为strval($input)
作为占位符。 - Rafael