当键是数字时,数组到XML写入对象

时间:2017-06-14 08:45:52

标签: php arrays xml

我有一个将数组转换为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>

实际上,我会根据accept标头返回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

1 个答案:

答案 0 :(得分: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标记。如果您需要单独的办公室标签,则需要为每个办公室多次调用该功能。