您可以使用递归来解决您的问题。递归可以很好地处理嵌套数据。
您可以通过创建一个将值添加到父 XML 元素的函数来实现此目的。
然后,该函数会调用自身,以防发现嵌套数据。然后,它首先将子元素添加到父元素,然后调用自身并将新元素添加为父元素。
如果要添加的数据只是一个字符串,它仍然会创建子级,但直接添加字符串值并离开。那是叶节点,最多在外面。
然后 add 函数只需要读取您解析的数据并找出要处理四种情况中的哪一种:
- 只需添加一个带有字符串值的新元素(命名元素的字符串)
- 添加多个具有相同名称的新元素(命名元素的 0-n 索引数组)
- 添加一个新的子元素,然后在其中添加 N 个新的子元素(命名元素的键控数组)
- 将 N 个新子级添加到父级(编号(未命名)元素的键控数组)
对于这个答案,我认为使用匿名函数尝试一下会很好。为了使其递归,它需要引用自身。然后可以将其包装在另一个函数中,该函数将允许创建和导入程序SimpleXMLElement
它允许轻松创建 XML。进一步包装甚至允许将 XML 生成为字符串,但我将其保留给外部以使用法清晰:
require('inc/simplexml_pretty_print.php');
$xml = new SimpleXMLElement('<root/>');
$importer = $createArrayImporter($xml);
echo simplexml_pretty_print($importer($array));
在这个例子中$array
是你问题中的数组。它包含这四种情况,在此处进行处理$add
调用时将返回包装在另一个匿名函数中的函数$createArrayImporter()
在上面的例子中。
在进入之前,我们先回顾一下输入数组:
$array = [
'name' => 'ABC',
'email' => '[email protected] /cdn-cgi/l/email-protection',
'phones' =>
[
'phone' =>
[
[
'mobile' => '9000199193',
'land' => ' 9999999 ',
],
[
'mobile' => '9000199193',
'land' => ' 9999999 ',
],
[
'mobile' => '9000199194',
'land' => ' 5555555 ',
],
[
'mobile' => '9000199195',
'land' => ' 8888888 ',
],
],
],
];
这创建的输出:
<?xml version="1.0"?>
<root>
<name>ABC</name>
<email>[email protected] /cdn-cgi/l/email-protection</email>
<phones>
<phone>
<mobile>9000199193</mobile>
<land> 9999999 </land>
</phone>
<phone>
<mobile>9000199193</mobile>
<land> 9999999 </land>
</phone>
<phone>
<mobile>9000199194</mobile>
<land> 5555555 </land>
</phone>
<phone>
<mobile>9000199195</mobile>
<land> 8888888 </land>
</phone>
</phones>
</root>
以及如何递归函数:
$add = function (SimpleXMLElement $subject, $key, $value) use (&$add)
主题是要添加数据的 XML 元素,键是数组中的键,值同样可以嵌套也可以不嵌套。
因此,考虑到最直接的情况,您的键控(所有数组索引都是字符串)数组应该添加到根元素。
case $isKeyed:
foreach ($value as $oneof_key => $oneof_value) {
$add($subject, $oneof_key, $oneof_value);
}
这会将值作为嵌套传递。例如,下一个级别的第一个是[name] => ABC
,所以一个键控字符串:
case $isString && $hasKey:
return $subject->addChild($key, $value);
这只是添加具有名为键的字符串值的子元素。
下一个案例是
[phones] => Array
(
[phone] => Array
(
...
这是一个命名元素的键控数组:
case $isKeyed && $hasKey:
$subject = $subject->addChild($key);
// fall-through intended
它需要添加它自己的键作为与$isString && $hasKey
情况,但随后需要进一步处理它的数组值。这也是具有索引子项(0-N 作为索引)的键控数组的嵌套情况,因此可以添加多个同名元素:
case $isKeyed:
foreach ($value as $oneof_key => $oneof_value) {
$add($subject, $oneof_key, $oneof_value);
}
return true;
它将经历这种情况,并为没有键但只是编号的键控数组创建第四种情况。
这也是为什么我写道他的案件是三个半案件,最后两个案件彼此共享一些部分。
将其包装在闭包内可以使其更易于访问,我将仅在此处的一个小示例中概述:
$createArrayImporter = function (SimpleXMLElement $subject) {
$add = function (SimpleXMLElement $subject, $key, $value) use (&$add) {
...
};
return function (Array $array) use ($subject, $add) {
$add($subject, null, $array);
return $subject;
};
};
所以这可以开始事情。您可以阅读完整的代码我的要点 https://gist.github.com/4445046.
您在下面的答案中找到了一个类似的示例,但更多的是面向对象的,它也通过递归解决了这个问题:
- php:导出数组到xml的麻烦 https://stackoverflow.com/a/13219372/367456
数组的格式 - 即使它可能看起来相似 - 实际上与您的不同。
对于更多指针,有:
- 如何将数组转换为 SimpleXML https://stackoverflow.com/q/1397036/367456
其中处理不同类型的数组到 XML 的转换。