本文目录导读:

在PHP项目中,XML与数组的相互转换是非常常见的需求,以下是几种常用的实现方法:
XML转数组
使用 simplexml_load_string() 和 json_* 函数
function xmlToArray($xmlString) {
// 加载XML字符串
$xml = simplexml_load_string($xmlString, 'SimpleXMLElement', LIBXML_NOCDATA);
// 转换为JSON再转数组
$json = json_encode($xml);
$array = json_decode($json, true);
return $array;
}
// 使用示例
$xmlString = '<?xml version="1.0" encoding="UTF-8"?>
<root>
<name>张三</name>
<age>25</age>
<city>北京</city>
<hobbies>
<hobby>读书</hobby>
<hobby>运动</hobby>
</hobbies>
</root>';
$result = xmlToArray($xmlString);
print_r($result);
使用递归函数
function xmlToArrayRecursive($xmlObject, $out = []) {
foreach ((array)$xmlObject as $index => $node) {
$out[$index] = (is_object($node)) ?
xmlToArrayRecursive($node) : $node;
}
return $out;
}
// 使用示例
$xml = simplexml_load_string($xmlString, 'SimpleXMLElement', LIBXML_NOCDATA);
$array = xmlToArrayRecursive($xml);
数组转XML
使用 SimpleXMLElement
function arrayToXml($array, $rootElement = 'root', $xml = null) {
if ($xml === null) {
$xml = new SimpleXMLElement("<?xml version=\"1.0\" encoding=\"UTF-8\"?><{$rootElement}></{$rootElement}>");
}
foreach ($array as $key => $value) {
// 处理数字键名
if (is_numeric($key)) {
$key = 'item';
}
if (is_array($value)) {
// 检查是否为关联数组
$isAssoc = array_keys($value) !== range(0, count($value) - 1);
if ($isAssoc) {
$child = $xml->addChild($key);
arrayToXml($value, null, $child);
} else {
// 索引数组
foreach ($value as $item) {
$child = $xml->addChild($key);
if (is_array($item)) {
arrayToXml($item, null, $child);
} else {
$child->{0} = htmlspecialchars($item);
}
}
}
} else {
$xml->addChild($key, htmlspecialchars($value));
}
}
return $xml->asXML();
}
// 使用示例
$data = [
'name' => '张三',
'age' => 25,
'city' => '北京',
'hobbies' => ['读书', '运动', '编程'],
'address' => [
'province' => '北京',
'city' => '朝阳区',
'detail' => '某某路100号'
]
];
$xmlString = arrayToXml($data);
echo $xmlString;
使用 DOMDocument
function arrayToXmlDOM($array, $rootName = 'root') {
$dom = new DOMDocument('1.0', 'UTF-8');
$dom->formatOutput = true;
$root = $dom->createElement($rootName);
$dom->appendChild($root);
createXmlFromArray($array, $root, $dom);
return $dom->saveXML();
}
function createXmlFromArray($array, $parentElement, $dom) {
foreach ($array as $key => $value) {
// 处理数字键名
if (is_numeric($key)) {
$key = 'item';
}
$element = $dom->createElement($key);
if (is_array($value)) {
createXmlFromArray($value, $element, $dom);
} else {
$element->appendChild($dom->createTextNode($value));
}
$parentElement->appendChild($element);
}
}
// 使用示例
$xmlString = arrayToXmlDOM($data);
echo $xmlString;
完整的生产级封装类
class XmlArrayConverter
{
/**
* XML转数组
*/
public static function toArray($xmlString, $options = LIBXML_NOCDATA)
{
if (empty($xmlString)) {
return [];
}
// 如果是SimpleXMLElement对象
if ($xmlString instanceof SimpleXMLElement) {
$xml = $xmlString;
} else {
// 允许字符串缺失XML声明
if (strpos($xmlString, '<?xml') === false) {
$xmlString = '<?xml version="1.0" encoding="UTF-8"?>' . $xmlString;
}
libxml_use_internal_errors(true);
$xml = simplexml_load_string($xmlString, 'SimpleXMLElement', $options);
if ($xml === false) {
$errors = libxml_get_errors();
libxml_clear_errors();
throw new \InvalidArgumentException('XML解析错误: ' . print_r($errors, true));
}
}
return self::simpleXmlToArray($xml);
}
/**
* 递归转换SimpleXMLElement为数组
*/
private static function simpleXmlToArray($xml)
{
$result = [];
foreach ($xml->children() as $key => $child) {
$count = $xml->{$key}->count();
$attributes = $child->attributes();
$value = (string)$child;
// 如果有子元素
if ($child->children()->count() > 0) {
$value = self::simpleXmlToArray($child);
}
// 保留属性
if (count($attributes) > 0) {
$value = [
'@attributes' => iterator_to_array($attributes),
'@value' => $value
];
}
// 处理重复元素
if ($count > 1) {
if (!isset($result[$key])) {
$result[$key] = [];
}
$result[$key][] = $value;
} else {
$result[$key] = $value;
}
}
return $result;
}
/**
* 数组转XML
*/
public static function toXml($array, $rootElement = 'root', $encoding = 'UTF-8')
{
if (empty($array)) {
return '';
}
$xml = new SimpleXMLElement("<?xml version=\"1.0\" encoding=\"{$encoding}\"?><{$rootElement}></{$rootElement}>");
self::arrayToSimpleXml($array, $xml);
return $xml->asXML();
}
/**
* 递归转换数组为SimpleXMLElement
*/
private static function arrayToSimpleXml($array, &$xml)
{
foreach ($array as $key => $value) {
// 处理数字键名
if (is_numeric($key)) {
$key = 'item_' . $key;
}
if (is_array($value)) {
// 检查是否为索引数组(多个相同元素)
$isIndexed = array_keys($value) === range(0, count($value) - 1);
if ($isIndexed) {
foreach ($value as $item) {
$child = $xml->addChild($key);
if (is_array($item)) {
self::arrayToSimpleXml($item, $child);
} else {
$child[0] = self::escapeValue($item);
}
}
} else {
// 关联数组
if (isset($value['@attributes'])) {
$child = $xml->addChild($key);
foreach ($value['@attributes'] as $attrKey => $attrValue) {
$child->addAttribute($attrKey, $attrValue);
}
if (isset($value['@value'])) {
$child[0] = self::escapeValue($value['@value']);
} else {
self::arrayToSimpleXml($value, $child);
}
} else {
$child = $xml->addChild($key);
self::arrayToSimpleXml($value, $child);
}
}
} else {
$xml->addChild($key, self::escapeValue($value));
}
}
}
/**
* 转义特殊字符
*/
private static function escapeValue($value)
{
if ($value === null) {
return '';
}
return htmlspecialchars((string)$value, ENT_XML1 | ENT_QUOTES, 'UTF-8');
}
}
// 使用示例
$converter = new XmlArrayConverter();
// XML转数组
$xml = '<root><name>张三</name><age>25</age></root>';
$array = $converter->toArray($xml);
// 数组转XML
$data = ['name' => '李四', 'age' => 30];
$xml = $converter->toXml($data, 'person');
使用Composer包
推荐使用成熟的Composer包:
composer require ezyang/htmlpurifier # 或 composer require seldaek/jsonlint
但更推荐专门的XML处理库:
composer require mtazumal/xml-to-array
注意事项
- CDATA处理:使用
LIBXML_NOCDATA选项处理CDATA - 中文字符:确保UTF-8编码
- 特殊字符:使用
htmlspecialchars()转义XML特殊字符 - 性能考虑:大量数据时使用流式处理
这些方法覆盖了大部分使用场景,可以根据具体需求选择合适的方法。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播