PHP数组转换为XML,即使是嵌套数据也可以。

4

我有一个需要转换为XML格式的数组。

[name] => ABC
[email] => email@email.com
[phones] => Array
                (
                 [phone] => Array
                          (
                                [0] => Array
                                    (
                                        [mobile] => 91454599193
                                        [land] =>  9999999 
                                    )

                                [1] => Array
                                    (
                                        [mobile] => 54520199193
                                        [land] =>  9999999 
                                    )

                                [2] => Array
                                    (
                                        [mobile] => 90424249194
                                        [land] =>  5555555 
                                    )

                                [3] => Array
                                    (
                                        [mobile] => 44224199195
                                        [land] =>  8888888 
                                    )

                            )
)

我希望您能按照以下格式进行排版:

我想让这个内容以以下格式呈现

<name>ABC</name>
<email>email@email.com</email>
 <phones>
 <phone>
   <mobile>545450199193</mobile>
   <land>9999999</land>
</phone>
 <phone>
   <mobile>575199193</mobile>
   <land>9999999</land>
</phone>
</phones>

请帮我忙...

这是我的函数,我是这样写的。我面临的问题是:必须在具有数字的索引中显示XML节点中的文本。例如:在电话数组下面,有索引[0],[1]。我希望在我的XML页面中将[0],[1]替换为<phone>

  function array_to_xml($value, &$xml_student_info) {
  foreach($value as $key => $value) {
    if(is_array($value)) {
        if(!is_numeric($key)){
            $subnode = $xml_student_info->addChild("$key");
            array_to_xml($value, $subnode);
        }
        else{
            array_to_xml($value, $xml_student_info);
         }
       }
        else {
            $xml_student_info->addChild("$key","$value");
        }
    }
}

4
你尝试过什么?(http://whathaveyoutried.com/) - DaveRandom
@devOp 结果不是我需要的,我已经检查了函数。 - user1933865
@devOp 我也尝试了这个函数,但它不支持嵌套的<phone>标签。 - user1933865
你能否发布一下你所贴出的函数的当前输出结果? - devOp
我之前的函数输出:<?xml version="1.0"?> <root><name>ABC</name><email>email@email.com</email><phones><phone><0> <mobile>9000199193</mobile><land> 9999999 </land></0><1><mobile>9000199193</mobile><land> 9999999 </land></1><2><mobile>9000199194</mobile><land> 5555555 </land></2></phones></root> - user1933865
显示剩余3条评论
2个回答

3
您可以通过使用递归来解决您的问题。递归可以很好地处理嵌套数据。
您可以创建一个单一的函数,将值添加到父XML元素中。如果发现有嵌套数据,则该函数将调用自身。然后它将首先将子元素添加到父级,然后使用新的元素作为父级再次调用自身。
如果要添加的数据只是一个字符串,则它仍然会创建子元素,但直接添加字符串值并离开。这些是叶节点,最多在外部。
然后,添加函数只需要读取您解析的数据,并找出要处理的四种情况:
1. 仅添加具有字符串值的新元素(命名元素的字符串)。 2. 添加具有相同名称的多个新元素(命名元素的0-n索引数组)。 3. 添加一个新的子项,然后在其中添加N个新的子项(命名元素的键入数组)。 4. 将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@email.com',
    '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@email.com</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;
    };
};

所以这可以启动事物。您可以在我的Gist中阅读完整的代码。
您可以在以下答案中找到一个类似的示例,但更加面向对象,它也通过递归来解决:
- php:导出数组到XML麻烦 数组的格式 - 即使看起来可能相似 - 实际上与您的不同。
另外还有更多指针:
- 如何将数组转换为SimpleXML 它处理不同类型的数组转换为XML。

非常感谢你,hakre。但有一个小疑问,如果键是[0]、[1],那么你在上面的函数中到底用键替换了什么? - user1933865

0
问题在于一个数组或对象中不能有相同的键。在simplexml的情况下,有一个保存xml的对象。解决方案是自己构建xml。

是的,我同意,但是我必须得到<phone></phone>标签,而不是<0>,<1>等。 - user1933865
我的意思是,当你在foreach中自己构建它并将结果保存到字符串中时,你可以按照自己的方式编写键。 - devOp
嗯,是的,如果始终使用相同的数组,那就没有问题。 - devOp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接