【问题标题】:Array to XML write object when key is numeric当键为数字时,数组到 XML 写入对象
【发布时间】:2017-06-14 08:45:52
【问题描述】:

我有一个将数组转换为 XML 的函数,但它在任何情况下都不起作用。

public function array_to_xml($data, &$xml_data) {
    foreach($data as $key => $value) {
        if (is_numeric($key)) {
            $key = 'item'.$key;
        }
        if (is_array($value)) {
            $subnode = $xml_data->addChild($key);
            $this->array_to_xml($value, $subnode);
        } else {
            $xml_data->addChild("$key",htmlspecialchars("$value"));
        }
     }
}

但是如果我发送这个数组,它将返回<item0...n>

$xml = new \SimpleXMLElement('<?xml version="1.0"?><offices></offices>');

$first = array("id" => 1, "name" => "firstOffice");
$second = array("id" => 2, "name" => "secondOffice");
$offices = array("office" => array($first, $second));

return array_to_xml($data, $xml);

输出

<offices>
    <office>
        <item0>
            <id>1</id>
            <name>firstOffice</name>
        </item0>
        <item1>
            <id>2</id>
            <name>secondOffice</name>
        </item1>
    </office>
</offices>

如何编辑我的函数以获得此结果:

<offices>
    <office>
        <id>1</id>
        <name>firstOffice</name>
    </office>
    <office>
        <id>2</id>
        <name>secondOffice</name>
    </office>
</offices>

实际上,我将根据接受标头返回 JSON 或 XML,然后我必须为 JSON 和 XML 使用相同的数组。

这是我当前代码的一部分:

public function getOffices() {
    $tools = new Tools();
    $accept = $this->request->getHeader('accept');
    $xml = new \SimpleXMLElement('<?xml version="1.0"?><offices></offices>');

    $offices = Offices::find();  // Find all offices, I'm using Phalcon PHP ORM

    return $tools->formatAdapter($accept, array("office" => $offices->toArray()), 200, $xml);
}

工具函数类

public function array_to_xml($data, &$xml_data) {
    foreach($data as $key => $value) {
        if (is_numeric($key)) {
            $key = 'item'.$key;
        }
        if (is_array($value)) {
            $subnode = $xml_data->addChild($key);
            $this->array_to_xml($value, $subnode);
        } else {
            $xml_data->addChild("$key",htmlspecialchars("$value"));
        }
     }
}

public function formatAdapter($type, $data, $code, &$xml_data) {
    if ($type == 'application/json') {
        return $this->JSONBuilder($data, $code);
    } else {
        $this->array_to_xml($data, $xml_data);
        return $this->XMLBuilder($xml_data->asXML(), $code);
    }
}

public function JSONBuilder($data, $code) {
    $response = new Response();

    $message = $this->getResponseDescription($code);

    $response->setHeader('Content-Type', 'application/json');
    $response->setStatusCode($code, $message);
    $response->setJsonContent($data);

    return $response;
}

function XMLBuilder($xml, $code) {
    $response = new Response();

    $message = $this->getResponseDescription($code);

    $response->setHeader('Content-Type', 'application/xml');
    $response->setStatusCode($code, $message);
    $response->setContent($xml);

    return $response;
}

编辑 formatAdapter 函数

public function formatAdapter($type, $data, $code, &$xml_data, $loop = false) {
    if ($type == 'application/json') {
        return $this->JSONBuilder($data, $code);
    } else {
        if ($loop) {
            foreach ($data as $key => $value) {
                foreach ($value as $obj) {
                    $this->array_to_xml(array($key => $obj), $xml_data);
                }
            }
        } else {
            $this->array_to_xml($data, $xml_data);
        }
        return $this->XMLBuilder($xml_data->asXML(), $code);
    }
}

如果我在我的函数和 $loop 参数中添加这个循环,它就会起作用。但正如你所看到的,我有 2 个 foreach 循环。可以避免第一个 foreach 循环吗?因为我每次都会循环一次。我尝试使用 array_value() 但它不起作用。

编辑修复

最后我找到了我的 formatAdapter 函数的解决方案,但它只适用于第一个对象。如果有人有更好的解决方案:

public function formatAdapter($type, $data, $code, &$xml_data, $loop = false) {
    if ($type == 'application/json') {
        return $this->JSONBuilder($data, $code);
    } else {
        if ($loop) {
            $key = key($data);
            foreach ($data[$key] as $obj) {
                $this->array_to_xml(array($key => $obj), $xml_data);
            }
        } else {
            $this->array_to_xml($data, $xml_data);
        }
        return $this->XMLBuilder($xml_data->asXML(), $code);
    }
}

感谢@iainn

【问题讨论】:

  • 不确定我是否理解这个问题。而不是第一个输出,您有兴趣获得第二个输出?
  • 是的。 item0, item1 不明确。我需要指定对象名称。这里我有一系列办公室,然后我想为每个办公室写&lt;office&gt;
  • 但是你正在运行 'foreach' $key = 'item'.$key; ...?
  • 是的,我必须用前一个键替换这一行,但我不知道如何

标签: php arrays xml


【解决方案1】:

如果你不想修改已有的功能,那么你可以使用如下:

$xml = new \SimpleXMLElement('<?xml version="1.0"?><offices></offices>');

$first = array("id" => 1, "name" => "firstOffice");
$second = array("id" => 2, "name" => "secondOffice");

array_to_xml(array("office" => $first), $xml);
array_to_xml(array("office" => $second), $xml);

echo $xml->asXML();

该函数假定如果您只传入一个数组,您希望将它们分组到 itemX 标记中。如果你想要单独的办公室标签,你需要对每个办公室多次调用该函数。

【讨论】:

  • 感谢您的回答。我不想循环并调用 array_to_xml,因为我创建了一个返回 XML 或 JSON 的函数,然后我只需要发送一个数组。然后 JSON 和 XML 使用相同的数组。在这种情况下,也许我必须创建另一个函数?
  • 也许我可以在我的 formatAdapter 函数中为 XML 添加一个 foreach 循环和一个参数 $loop true / false
  • 我在我的函数中调整了您的解决方案,它适用于 JSON 和 XML。谢谢。但是,如果我必须在另一个子节点上循环,它将不起作用
猜你喜欢
  • 2020-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-13
  • 2021-11-27
相关资源
最近更新 更多