近日MyQEE里加入了xml和数组互转的功能,调用代码分别是:
- XML字符串转数组:
Text::xml_to_array($xmlstr);
- 数组转XML:
Arr::to_xml($array);
其中XML转数组支持直接获取XML的URL转换,例如:
$arr = Text::xml_to_array('http://flash.weather.com.cn/wmaps/xml/china.xml');
print_r($arr)
XML代码示例:
<?xml version="1.0" encoding="UTF-8"?>
<TrafficEventResponse aa="true" bb="aaaa">
<status>success</status>
<currentCity aaa="aaaa">北京</currentCity>
<test>true</test>
<dateTime>2013/07/23/18/32/41</dateTime>
<results>
<result aa="11">
<startTime>2013/03/08/10/51/00</startTime>
<endTime>2013/10/08/12/00/00</endTime>
<title ID="12" active="1" permission="13">东四西大街1车道限行(长期)</title>
<description>东四西大街因为道路施工,导致1车道限行。</description>
<location ID="12" active="1" permission="13">
<lng>116.420497</lng>
<lat>39.930511</lat>
<root>
<folder ID="aaa" active="1" permission="13"><![CDATA[aaaaaaaaaaaaaaaaaaaa]]></folder>
<folder ID="bbb" active="1" permission="1"><![CDATA[bbbbbbbbbbbbbbbbbbbbbb]]></folder>
</root>
</location>
<type>2</type>
</result>
<result aa="22">
<startTime>2013/01/01/00/00/00</startTime>
<endTime>2013/12/31/23/59/00</endTime>
<title>清华东路3车道限行(长期)</title>
<description>清华东路因为道路施工,导致3车道限行。</description>
<location>
<lng>116.37618</lng>
<lat>40.007609</lat>
<root>
<folder ID="ccc" active="1" permission="1"><![CDATA[ccccccccccccccccccc]]></folder>
<folder ID="ddd" active="1" permission="1"><![CDATA[dddddddddddddddddd]]></folder>
</root>
</location>
<type>2</type>
</result>
</results>
</TrafficEventResponse>
<TrafficEventResponse aa="true" bb="aaaa">
<status>success</status>
<currentCity aaa="aaaa">北京</currentCity>
<test>true</test>
<dateTime>2013/07/23/18/32/41</dateTime>
<results>
<result aa="11">
<startTime>2013/03/08/10/51/00</startTime>
<endTime>2013/10/08/12/00/00</endTime>
<title ID="12" active="1" permission="13">东四西大街1车道限行(长期)</title>
<description>东四西大街因为道路施工,导致1车道限行。</description>
<location ID="12" active="1" permission="13">
<lng>116.420497</lng>
<lat>39.930511</lat>
<root>
<folder ID="aaa" active="1" permission="13"><![CDATA[aaaaaaaaaaaaaaaaaaaa]]></folder>
<folder ID="bbb" active="1" permission="1"><![CDATA[bbbbbbbbbbbbbbbbbbbbbb]]></folder>
</root>
</location>
<type>2</type>
</result>
<result aa="22">
<startTime>2013/01/01/00/00/00</startTime>
<endTime>2013/12/31/23/59/00</endTime>
<title>清华东路3车道限行(长期)</title>
<description>清华东路因为道路施工,导致3车道限行。</description>
<location>
<lng>116.37618</lng>
<lat>40.007609</lat>
<root>
<folder ID="ccc" active="1" permission="1"><![CDATA[ccccccccccccccccccc]]></folder>
<folder ID="ddd" active="1" permission="1"><![CDATA[dddddddddddddddddd]]></folder>
</root>
</location>
<type>2</type>
</result>
</results>
</TrafficEventResponse>
转换成数组后:
Array
(
[@name] => TrafficEventResponse
[@attributes] => Array
(
[aa] => 1
[bb] => aaaa
)
[status] => success
[currentCity] => Array
(
[@attributes] => Array
(
[aaa] => aaaa
)
[@data] => 北京
)
[test] => 1
[dateTime] => 2013/07/23/18/32/41
[results] => Array
(
[0] => Array
(
[@name] => result
[@attributes] => Array
(
[aa] => 11
)
[startTime] => 2013/03/08/10/51/00
[endTime] => 2013/10/08/12/00/00
[title] => Array
(
[@attributes] => Array
(
[ID] => 12
[active] => 1
[permission] => 13
)
[@data] => 东四西大街1车道限行(长期)
)
[description] => 东四西大街因为道路施工,导致1车道限行。
[location] => Array
(
[@attributes] => Array
(
[ID] => 12
[active] => 1
[permission] => 13
)
[lng] => 116.420497
[lat] => 39.930511
[root] => Array
(
[0] => Array
(
[@name] => folder
[@attributes] => Array
(
[ID] => aaa
[active] => 1
[permission] => 13
)
[@tdata] => aaaaaaaaaaaaaaaaaaaa
)
[1] => Array
(
[@name] => folder
[@attributes] => Array
(
[ID] => bbb
[active] => 1
[permission] => 1
)
[@tdata] => bbbbbbbbbbbbbbbbbbbbbb
)
)
)
[type] => 2
)
[1] => Array
(
[@name] => result
[@attributes] => Array
(
[aa] => 22
)
[startTime] => 2013/01/01/00/00/00
[endTime] => 2013/12/31/23/59/00
[title] => 清华东路3车道限行(长期)
[description] => 清华东路因为道路施工,导致3车道限行。
[location] => Array
(
[lng] => 116.37618
[lat] => 40.007609
[root] => Array
(
[0] => Array
(
[@name] => folder
[@attributes] => Array
(
[ID] => ccc
[active] => 1
[permission] => 1
)
[@tdata] => ccccccccccccccccccc
)
[1] => Array
(
[@name] => folder
[@attributes] => Array
(
[ID] => ddd
[active] => 1
[permission] => 1
)
[@tdata] => dddddddddddddddddd
)
)
)
[type] => 2
)
)
)
(
[@name] => TrafficEventResponse
[@attributes] => Array
(
[aa] => 1
[bb] => aaaa
)
[status] => success
[currentCity] => Array
(
[@attributes] => Array
(
[aaa] => aaaa
)
[@data] => 北京
)
[test] => 1
[dateTime] => 2013/07/23/18/32/41
[results] => Array
(
[0] => Array
(
[@name] => result
[@attributes] => Array
(
[aa] => 11
)
[startTime] => 2013/03/08/10/51/00
[endTime] => 2013/10/08/12/00/00
[title] => Array
(
[@attributes] => Array
(
[ID] => 12
[active] => 1
[permission] => 13
)
[@data] => 东四西大街1车道限行(长期)
)
[description] => 东四西大街因为道路施工,导致1车道限行。
[location] => Array
(
[@attributes] => Array
(
[ID] => 12
[active] => 1
[permission] => 13
)
[lng] => 116.420497
[lat] => 39.930511
[root] => Array
(
[0] => Array
(
[@name] => folder
[@attributes] => Array
(
[ID] => aaa
[active] => 1
[permission] => 13
)
[@tdata] => aaaaaaaaaaaaaaaaaaaa
)
[1] => Array
(
[@name] => folder
[@attributes] => Array
(
[ID] => bbb
[active] => 1
[permission] => 1
)
[@tdata] => bbbbbbbbbbbbbbbbbbbbbb
)
)
)
[type] => 2
)
[1] => Array
(
[@name] => result
[@attributes] => Array
(
[aa] => 22
)
[startTime] => 2013/01/01/00/00/00
[endTime] => 2013/12/31/23/59/00
[title] => 清华东路3车道限行(长期)
[description] => 清华东路因为道路施工,导致3车道限行。
[location] => Array
(
[lng] => 116.37618
[lat] => 40.007609
[root] => Array
(
[0] => Array
(
[@name] => folder
[@attributes] => Array
(
[ID] => ccc
[active] => 1
[permission] => 1
)
[@tdata] => ccccccccccccccccccc
)
[1] => Array
(
[@name] => folder
[@attributes] => Array
(
[ID] => ddd
[active] => 1
[permission] => 1
)
[@tdata] => dddddddddddddddddd
)
)
)
[type] => 2
)
)
)
接下来是整理后的代码,完全独立使用
<?php
/**
* 将一个XML字符串解析成一个数组
*
* 如果需要将数组转换成XML字符串,可使用 `array_to_xml($arr)` 方法
*
* ** 特殊的key **
*
* key | 说明
* ----------------|-------------------------------
* `@attributes` | XML里所有的 attributes 都存放在 `@attributes` key里,可自定义参数 `$attribute_key` 修改,设置成true则和标签里的内容合并
* `@name` | 循环数组XML的标签(tag)存放在 `@name` 的key里
* `@tdata` | CDATA内容存放在 `@tdata` 的key里
* `@data` | 如果本来的值是字符串,但是又有 attributes,则内容被转移至 `@data` 的key里
*
*
* print_r(xml_to_array('http://flash.weather.com.cn/wmaps/xml/china.xml'));
*
* @param string|SimpleXMLElement $xml_string XML字符串,支持http的XML路径,接受 SimpleXMLElement 对象
* @param string $attribute_key attributes所使用的key,默认 @attributes,设置成 true 则和内容自动合并
* @param int $max_recursion_depth 解析最高层次,默认25
* @return array | false 失败则返回false
*/
function xml_to_array($xml_string, $attribute_key = '@attributes', $max_recursion_depth = 25)
{
if (is_string($xml_string))
{
if (preg_match('#^http(s)?://#i', $xml_string))
{
$xml_string = file_get_contents($xml_string);
}
$xml_object = simplexml_load_string($xml_string, 'SimpleXMLElement', LIBXML_NOCDATA);
}
elseif (is_object($xml_string) && $xml_string instanceof SimpleXMLElement)
{
$xml_object = $xml_string;
}
else
{
return false;
}
if (!$attribute_key)$attribute_key = '@attributes';
if (null===$max_recursion_depth || false===$max_recursion_depth)$max_recursion_depth = 25;
$format_attribute_value = function (& $tmp_value)
{
switch ($tmp_value)
{
case 'true':
$tmp_value = true;
break;
case 'false':
$tmp_value = false;
break;
case 'null':
$tmp_value = null;
break;
default:
$tmp_value = trim($tmp_value);
}
};
$exec_xml_to_array = function ($xml_object, $attribute_key, $recursion_depth, $max_recursion_depth) use(&$exec_xml_to_array, $format_attribute_value)
{
/**
* @var $xml_object SimpleXMLElement
* @var $value SimpleXMLElement
*/
$rs = array
(
'@name' => $xml_object->getName(),
);
$attr = get_object_vars($xml_object->attributes());
if ($attr)
{
foreach($attr['@attributes'] as &$tmp_value)
{
$format_attribute_value($tmp_value);
}
unset($tmp_value);
if (true===$attribute_key)
{
# 合并到一起
$rs += $attr['@attributes'];
}
else
{
$rs[$attribute_key] = $attr['@attributes'];
}
}
$tdata = trim("$xml_object");
if (strlen($tdata)>0)
{
$rs['@tdata'] = $tdata;
}
$xml_object_var = get_object_vars($xml_object);
foreach($xml_object as $key => $value)
{
$obj_value = $xml_object_var[$key];
$attr = null;
if (is_object($value))
{
$attr = get_object_vars($value->attributes());
if ($attr)
{
foreach($attr['@attributes'] as &$tmp_value)
{
$format_attribute_value($tmp_value);
}
unset($tmp_value);
$attr = $attr['@attributes'];
}
}
if (is_string($obj_value))
{
$format_attribute_value($obj_value);
if ($attr)
{
if (true===$attribute_key)
{
# 合并到一起
$rs[$key] = $attr + array('@data' => $obj_value);
}
else
{
$rs[$key] = array
(
$attribute_key => $attr,
'@data' => $obj_value,
);
}
}
else
{
$rs[$key] = $obj_value;
}
}
else
{
if (is_array($obj_value))
{
if ($recursion_depth>0)unset($rs['@name']);
$rs[] = $exec_xml_to_array($value, $attribute_key, $recursion_depth+1, $max_recursion_depth);
}
else
{
$rs[$key] = $exec_xml_to_array($value, $attribute_key, $recursion_depth+1, $max_recursion_depth);
if (is_array($rs[$key]) && !isset($rs[$key][0]))
{
unset($rs[$key]['@name']);
}
}
}
}
return $rs;
};
return $exec_xml_to_array($xml_object, $attribute_key, 0, $max_recursion_depth);
}
/**
* 将数组转换成XML字符串
*
* 本方法的反向方法为 `xml_to_array($xml_string)`
*
* // 返回格式化好的XML字符串
* array_to_xml($arr);
*
* // XML缩进使用4个空格
* array_to_xml($arr, ' ');
*
* // 返回不带任何换行符、空格的XML
* array_to_xml($arr, '', '');
*
* @param array $array 数组
* @param string $tab 缩进字符,默认 tab 符
* @param string $crlf 换行符,默认window换行符
* @param string $attribute_key XML的attributes所在key,默认 `@attributes`
* @param string $xml_header_string XML第一行声明的字符串
* @return string
*/
function array_to_xml(array $array, $tab = "\t", $crlf = "\r\n", $attribute_key = '@attributes', $xml_header_string = null)
{
if (!$xml_header_string)
{
$w = '?';
$xml_header_string = '<'. $w . 'xml version="1.0" encoding="UTF-8"'. $w .'>';
}
$format_attribute_value = function (& $value)
{
if (true===$value)
{
$value = 'true';
}
elseif (false===$value)
{
$value = 'false';
}
elseif (null===$value)
{
$value = 'null';
}
};
$format_to_xml_string = function($array, $attribute_key, $crlf, $tab, $left_str = '') use(&$format_to_xml_string, $format_attribute_value)
{
$str = '';
if (isset($array['@name']))
{
$str .= "{$crlf}{$left_str}<{$array['@name']}";
if (isset($array[$attribute_key]))
{
foreach($array[$attribute_key] as $k=>$v)
{
$format_attribute_value($v);
$str .= " $k="{$v}"";
}
}
$str .= ">";
$close_str = "{$crlf}{$left_str}</{$array['@name']}>";
$left_str .= $tab;
}
else
{
$close_str = '';
}
if (isset($array['@tdata']))
{
$str .= "<![CDATA[{$array['@tdata']}]]></{$array['@name']}>";
}
else
{
$have_str = false;
foreach($array as $key => $value)
{
if ($key === '@name' || $key === $attribute_key || $key === '@data' || $key === '@tdata')continue;
$have_str = true;
if (is_array($value))
{
if (!is_numeric($key))
{
$str .= "{$crlf}{$left_str}<{$key}";
if (isset($value[$attribute_key]))
{
foreach($value[$attribute_key] as $k=>$v)
{
$str .= " $k="{$v}"";
}
}
$str .= ">";
if (isset($value['@data']))
{
$format_attribute_value($value['@data']);
$str .= "{$value['@data']}";
}
elseif (isset($value['@tdata']))
{
$str .= "<![CDATA[{$value['@tdata']}]]>";
}
else
{
$tmp_str = $format_to_xml_string($value, $attribute_key, $crlf, $tab, $left_str . $tab);
if (''!==$tmp_str)
{
$str .= $tmp_str."{$crlf}{$left_str}";
}
unset($tmp_str);
}
$str .= "</{$key}>";
}
else
{
$str .= $format_to_xml_string($value, $attribute_key, $crlf, $tab, $left_str);
}
}
else
{
$format_attribute_value($value);
$str .= "{$crlf}{$left_str}<{$key}>{$value}</{$key}>";
}
}
if ($have_str)
{
if ($close_str)
{
$str .= $close_str;
}
}
else
{
$str .= "</{$array['@name']}>";
}
}
return $str;
};
return $xml_header_string . $format_to_xml_string($array, $attribute_key, $crlf, $tab, '');
}
print_r($arr = xml_to_array('http://flash.weather.com.cn/wmaps/xml/china.xml'));
echo array_to_xml($arr);
/**
* 将一个XML字符串解析成一个数组
*
* 如果需要将数组转换成XML字符串,可使用 `array_to_xml($arr)` 方法
*
* ** 特殊的key **
*
* key | 说明
* ----------------|-------------------------------
* `@attributes` | XML里所有的 attributes 都存放在 `@attributes` key里,可自定义参数 `$attribute_key` 修改,设置成true则和标签里的内容合并
* `@name` | 循环数组XML的标签(tag)存放在 `@name` 的key里
* `@tdata` | CDATA内容存放在 `@tdata` 的key里
* `@data` | 如果本来的值是字符串,但是又有 attributes,则内容被转移至 `@data` 的key里
*
*
* print_r(xml_to_array('http://flash.weather.com.cn/wmaps/xml/china.xml'));
*
* @param string|SimpleXMLElement $xml_string XML字符串,支持http的XML路径,接受 SimpleXMLElement 对象
* @param string $attribute_key attributes所使用的key,默认 @attributes,设置成 true 则和内容自动合并
* @param int $max_recursion_depth 解析最高层次,默认25
* @return array | false 失败则返回false
*/
function xml_to_array($xml_string, $attribute_key = '@attributes', $max_recursion_depth = 25)
{
if (is_string($xml_string))
{
if (preg_match('#^http(s)?://#i', $xml_string))
{
$xml_string = file_get_contents($xml_string);
}
$xml_object = simplexml_load_string($xml_string, 'SimpleXMLElement', LIBXML_NOCDATA);
}
elseif (is_object($xml_string) && $xml_string instanceof SimpleXMLElement)
{
$xml_object = $xml_string;
}
else
{
return false;
}
if (!$attribute_key)$attribute_key = '@attributes';
if (null===$max_recursion_depth || false===$max_recursion_depth)$max_recursion_depth = 25;
$format_attribute_value = function (& $tmp_value)
{
switch ($tmp_value)
{
case 'true':
$tmp_value = true;
break;
case 'false':
$tmp_value = false;
break;
case 'null':
$tmp_value = null;
break;
default:
$tmp_value = trim($tmp_value);
}
};
$exec_xml_to_array = function ($xml_object, $attribute_key, $recursion_depth, $max_recursion_depth) use(&$exec_xml_to_array, $format_attribute_value)
{
/**
* @var $xml_object SimpleXMLElement
* @var $value SimpleXMLElement
*/
$rs = array
(
'@name' => $xml_object->getName(),
);
$attr = get_object_vars($xml_object->attributes());
if ($attr)
{
foreach($attr['@attributes'] as &$tmp_value)
{
$format_attribute_value($tmp_value);
}
unset($tmp_value);
if (true===$attribute_key)
{
# 合并到一起
$rs += $attr['@attributes'];
}
else
{
$rs[$attribute_key] = $attr['@attributes'];
}
}
$tdata = trim("$xml_object");
if (strlen($tdata)>0)
{
$rs['@tdata'] = $tdata;
}
$xml_object_var = get_object_vars($xml_object);
foreach($xml_object as $key => $value)
{
$obj_value = $xml_object_var[$key];
$attr = null;
if (is_object($value))
{
$attr = get_object_vars($value->attributes());
if ($attr)
{
foreach($attr['@attributes'] as &$tmp_value)
{
$format_attribute_value($tmp_value);
}
unset($tmp_value);
$attr = $attr['@attributes'];
}
}
if (is_string($obj_value))
{
$format_attribute_value($obj_value);
if ($attr)
{
if (true===$attribute_key)
{
# 合并到一起
$rs[$key] = $attr + array('@data' => $obj_value);
}
else
{
$rs[$key] = array
(
$attribute_key => $attr,
'@data' => $obj_value,
);
}
}
else
{
$rs[$key] = $obj_value;
}
}
else
{
if (is_array($obj_value))
{
if ($recursion_depth>0)unset($rs['@name']);
$rs[] = $exec_xml_to_array($value, $attribute_key, $recursion_depth+1, $max_recursion_depth);
}
else
{
$rs[$key] = $exec_xml_to_array($value, $attribute_key, $recursion_depth+1, $max_recursion_depth);
if (is_array($rs[$key]) && !isset($rs[$key][0]))
{
unset($rs[$key]['@name']);
}
}
}
}
return $rs;
};
return $exec_xml_to_array($xml_object, $attribute_key, 0, $max_recursion_depth);
}
/**
* 将数组转换成XML字符串
*
* 本方法的反向方法为 `xml_to_array($xml_string)`
*
* // 返回格式化好的XML字符串
* array_to_xml($arr);
*
* // XML缩进使用4个空格
* array_to_xml($arr, ' ');
*
* // 返回不带任何换行符、空格的XML
* array_to_xml($arr, '', '');
*
* @param array $array 数组
* @param string $tab 缩进字符,默认 tab 符
* @param string $crlf 换行符,默认window换行符
* @param string $attribute_key XML的attributes所在key,默认 `@attributes`
* @param string $xml_header_string XML第一行声明的字符串
* @return string
*/
function array_to_xml(array $array, $tab = "\t", $crlf = "\r\n", $attribute_key = '@attributes', $xml_header_string = null)
{
if (!$xml_header_string)
{
$w = '?';
$xml_header_string = '<'. $w . 'xml version="1.0" encoding="UTF-8"'. $w .'>';
}
$format_attribute_value = function (& $value)
{
if (true===$value)
{
$value = 'true';
}
elseif (false===$value)
{
$value = 'false';
}
elseif (null===$value)
{
$value = 'null';
}
};
$format_to_xml_string = function($array, $attribute_key, $crlf, $tab, $left_str = '') use(&$format_to_xml_string, $format_attribute_value)
{
$str = '';
if (isset($array['@name']))
{
$str .= "{$crlf}{$left_str}<{$array['@name']}";
if (isset($array[$attribute_key]))
{
foreach($array[$attribute_key] as $k=>$v)
{
$format_attribute_value($v);
$str .= " $k="{$v}"";
}
}
$str .= ">";
$close_str = "{$crlf}{$left_str}</{$array['@name']}>";
$left_str .= $tab;
}
else
{
$close_str = '';
}
if (isset($array['@tdata']))
{
$str .= "<![CDATA[{$array['@tdata']}]]></{$array['@name']}>";
}
else
{
$have_str = false;
foreach($array as $key => $value)
{
if ($key === '@name' || $key === $attribute_key || $key === '@data' || $key === '@tdata')continue;
$have_str = true;
if (is_array($value))
{
if (!is_numeric($key))
{
$str .= "{$crlf}{$left_str}<{$key}";
if (isset($value[$attribute_key]))
{
foreach($value[$attribute_key] as $k=>$v)
{
$str .= " $k="{$v}"";
}
}
$str .= ">";
if (isset($value['@data']))
{
$format_attribute_value($value['@data']);
$str .= "{$value['@data']}";
}
elseif (isset($value['@tdata']))
{
$str .= "<![CDATA[{$value['@tdata']}]]>";
}
else
{
$tmp_str = $format_to_xml_string($value, $attribute_key, $crlf, $tab, $left_str . $tab);
if (''!==$tmp_str)
{
$str .= $tmp_str."{$crlf}{$left_str}";
}
unset($tmp_str);
}
$str .= "</{$key}>";
}
else
{
$str .= $format_to_xml_string($value, $attribute_key, $crlf, $tab, $left_str);
}
}
else
{
$format_attribute_value($value);
$str .= "{$crlf}{$left_str}<{$key}>{$value}</{$key}>";
}
}
if ($have_str)
{
if ($close_str)
{
$str .= $close_str;
}
}
else
{
$str .= "</{$array['@name']}>";
}
}
return $str;
};
return $xml_header_string . $format_to_xml_string($array, $attribute_key, $crlf, $tab, '');
}
print_r($arr = xml_to_array('http://flash.weather.com.cn/wmaps/xml/china.xml'));
echo array_to_xml($arr);