【问题标题】:Array to xml - issue with repeated tags数组到 xml - 重复标签的问题
【发布时间】:2018-01-22 19:13:28
【问题描述】:

已编辑
我正在尝试将表单输入放入 xml 文件中。

搜索on this site I've found the following code,我用它来解析 $_POST 内容。

经过几次尝试,我意识到“数字标签”(由非关联数组产生)可能是我失败的原因,所以我修改了代码如下:

function array_to_xml(array $arr, SimpleXMLElement $xml, $NumK = false)
{
    foreach ($arr as $k => $v) {
        if (is_array($v)){
            preg_match('/^0|[1-9]\d*$/', implode(array_keys($v)))
            ? array_to_xml($v, $xml->addChild($k), true)
            : array_to_xml($v, $xml->addChild($k));
        }else{
            $NumK
            ? $xml->addChild('_'.$k.'_', $v)
            : $xml->addChild($k, $v);
        }
    }
    return $xml;
}

无论如何,我仍在与 xpath 命令“战斗”,因为我无法找到需要转换为重复标签的某些节点(来自非关联数组)的 GrandParent。

这就是我要遵循的逻辑:
1st - 查找要重新格式化的节点(唯一具有数字标签的节点);
第二 - 找到祖父母(我需要重复的标签);
第三 - 用每组孙子(每个孩子一个)的祖父母标签替换祖父母(和他的后代)。

到目前为止,由于 xpath 的误解,我仍然停留在第一步。

下面,我拥有的结果 xml 以及我将如何对其进行转换:

我的数组是这样的:

$TestArr = Array
    ("First" => array
        ("Martha" => "Text01"
        ,
        "Lucy" => "Text02"
        ,
        "Bob" => array 
            ("Jhon" => array
                ("01", "02")
            ),
        "Frank" => "One"
        ,
        "Jessy" => "Two"
        )
    ,
    "Second" => array
        ("Mary" => array 
            ("Jhon" => array
                ("03", "04")
            ,
            "Frank" => array
                ("Three", "Four")
            ,
            "Jessy" => array
                ("J3", "J4")
            )
        )
    );

使用函数array_to_xml($TestArr, new SimpleXMLElement('<root/>')) 我得到一个类似的xml:

<root>
    <First>
        <Martha>Text01</Martha>
        <Lucy>Text02</Lucy>
        <Bob>
            <Jhon>
                <_0_>01</_0_>
                <_1_>02</_1_>
            </Jhon>
        </Bob>
        <Frank>One</Frank>
        <Jessy>Two</Jessy>
    </First>
    <Second>
        <Mary>
            <Jhon>
                <_0_>03</_0_>
                <_1_>04</_1_>
            </Jhon>
            <Frank>
                <_0_>Three</_0_>
                <_1_>Four</_1_>
            </Frank>
            <Jessy>
                <_0_>J3</_0_>
                <_1_>J4</_1_>
            </Jessy>
        </Mary>
    </Second>
</root>

我需要的结果是这样的:

<root>
    <First>
        <Martha>Text01</Martha>
        <Lucy>Text02</Lucy>
            <Bob>
                <Jhon>01</Jhon>
            </Bob>
            <Bob>
                <Jhon>02</Jhon>
            </Bob>
        <Frank>One</Frank>
        <Jessy>Two</Jessy>
    </First>
    <Second>
        <Mary>
            <Jhon>03</Jhon>
            <Frank>Three</Frank>
            <Jessy>J3</Jessy>
        </Mary>
        <Mary>
            <Jhon>04</Jhon>
            <Frank>Four</Frank>
            <Jessy>J4</Jessy>
        </Mary>
    </Second>
</root>

【问题讨论】:

  • 你试过了吗? pastebin.com/pYuXQWee
  • @DanielO。抱歉:结果相同
  • 那么 JSON,为什么是 XML?
  • @DanielO。因为目标是在 xml 中插入一些数据并使用特定的架构发送它(我的意思是 xml 的结构)
  • 好的,可以手动生成XML吗?

标签: php xml parsing multidimensional-array


【解决方案1】:

我已更新代码以尝试更接近您想要实现的目标。我已经考虑了如何识别数据分组,为此我为以这种方式添加的每个元素添加了一个“id”属性。同样为方便起见,我为父元素设置了一个“最大”计数器。

第一个 XPath 表达式 (//*[@id]/..) 获取所有需要处理的元素。然后循环计算之前计算的子元素的数量。 XPath descendant::*[@id='{$i}'] 挑选出每组元素(因此所有元素的 id='0',然后是 '1' 等)这是数据的自然分组。

function array_to_xml(array $arr, SimpleXMLElement $xml, string $elementName = null)
{
    foreach ($arr as $k => $v) {
        if (is_array($v)){
            if ( preg_match('/^0|[1-9]\d*$/', implode(array_keys($v)))) {
                array_to_xml($v, $xml, $k);
            }
            else    {
                array_to_xml($v, $xml->addChild($k));
            }
        }
        else    {
            if ( $elementName != null )   {
                $newElement = $xml->addChild($elementName, $v);
                $newElement["id"] = $k;
                $xml["max"] = $k;
            }
            else    {
                $xml->addChild($k, $v);
            }
        }
    }
    //return $xml;
}
$xml = new SimpleXMLElement("<root />");
array_to_xml($TestArr, $xml);
$todoList = $xml->xpath("//*[@id]/..");
foreach ( $todoList as $todo )  {
    $parent = $todo->xpath("..")[0];
    for ( $i = 0; $i <= $todo['max']; $i++ )    {
        $content = $todo->xpath("descendant::*[@id='{$i}']");
        $newName = $todo->getName();
        $new = $parent->addChild($newName);
        foreach ( $content as $addIn )  {
            $new->addChild($addIn->getName(), (string)$addIn);
        }
    }
    unset ( $parent->$newName[0]);
}

print $xml->asXML(); 

输出...

<?xml version="1.0"?>
<root>
    <First>
        <Martha>Text01</Martha>
        <Lucy>Text02</Lucy>
        <Frank>One</Frank>
        <Jessy>Two</Jessy>
        <Bob>
            <Jhon>01</Jhon>
        </Bob>
        <Bob>
            <Jhon>02</Jhon>
        </Bob>
    </First>
    <Second>
        <Mary>
            <Jhon>03</Jhon>
            <Frank>Three</Frank>
            <Jessy>J3</Jessy>
        </Mary>
        <Mary>
            <Jhon>04</Jhon>
            <Frank>Four</Frank>
            <Jessy>J4</Jessy>
        </Mary>
    </Second>
</root>

【讨论】:

  • 感谢您的尝试,但原始代码使我能够找到需要替换的节点(唯一在下划线之间具有数字标签的节点)。在您的代码生成的 xml 中,无法自动选择我需要重新定位的节点。
  • 我还有一出戏,如果有帮助的话有兴趣。
  • 我想我已经接近我的目标了(如果我的检查没问题,我会作为答案发布)+1 以引起您的注意;)哎呀对不起,我没有仔细阅读。我会测试它,如果它有效,我会给你奖金
  • 我收到错误:Catchable fatal error: Argument 3 passed to array_to_xml() must be an instance of string, string given
  • 我做到了,但你的代码更短(更专业),你的输出似乎是我需要的。如果你成功了,我会很高兴地给你奖励
【解决方案2】:

迭代你的数组值并添加具有相同键的元素

if (is_array($v)){
    foreach($v as $arr_ele){
        $xml->addChild($k, $arr_ele);
    }
}

【讨论】:

  • 元素都是posted函数添加的。我需要按照我的问题中的说明重新排序它们
猜你喜欢
  • 1970-01-01
  • 2016-07-30
  • 1970-01-01
  • 2010-11-23
  • 2015-09-20
  • 1970-01-01
  • 1970-01-01
  • 2011-10-11
  • 1970-01-01
相关资源
最近更新 更多