0

I'm having some trouble converting an array to an XML object, and keeping the associative keys from the array as tags in the created XML.

This is my code.

function to_xml($object, array $data) {
    foreach ($data as $key => $value) {
        if (is_array($value)) {
            $new_object = $object->addChild($key);
            to_xml($new_object, $value);
        } else {
            $object->addChild($key, $value);
        }
    }
}

$my_array = [
    "cbc:ID" => "myId",
    "cbc:IssueDate" => "2022-07-13",
    "cbc:DueDate" => "2022-07-20",
    "cbc:InvoiceTypeCode" => "380",
    "cbc:DocumentCurrencyCode" => "USD",
    "cac:InvoicePeriod" => [
        "cbc:DescriptionCode" => "35"
    ],
    "cac:ContractDocumentReference" => [
        "cbc:ID" => "123-456/22"
    ]
];

$xml = simplexml_load_string('<Invoice xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"/>','SimpleXMLElement',LIBXML_NOCDATA | LIBXML_NOBLANKS);

to_xml($xml, $my_array);

Header('Content-type: text/xml;charset=utf-8');
echo $xml->asXML();

This outputs:

<?xml version="1.0" encoding="UTF-8"?>
<Invoice xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2">
  <ID>myID</ID>
  <IssueDate>2022-07-13</IssueDate>
  <DueDate>2022-07-20</DueDate>
  <InvoiceTypeCode>380</InvoiceTypeCode>
  <DocumentCurrencyCode>USD</DocumentCurrencyCode>
  <InvoicePeriod>
    <DescriptionCode>35</DescriptionCode>
  </InvoicePeriod>
  <ContractDocumentReference>
    <ID>123-456/22</ID>
  </ContractDocumentReference>
</Invoice>

What I need it to do is to preserve the keys as they were in the array, and use them in the exact same format as tags in the XML, like so (shortened, for simplicity's sake):

  <cbc:ID>myID</cbc:ID>
  <cbc:IssueDate>2022-07-13</cbc:IssueDate>
  <cbc:DueDate>2022-07-20</cbc:DueDate>
  <cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
  <cbc:DocumentCurrencyCode>USD</cbc:DocumentCurrencyCode>

I am aware that I could do something along the lines of:

$object->addChild($tagName, $value, $schemaReference);

for example:

$object->addChild("ID", "myID", "urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2");

to get what I need.

However, I was wondering whether there's a native way (for lack of a better word) of doing this. By native, I mean some built-in functionality of SimpleXML (or DOM, if SimpleXML is not the right tool for this).

FiddlingAway
  • 1,598
  • 3
  • 14
  • 30
  • 1
    It's kind of hacky, but if you modify the keys in `$my_array` to be `cbc:cbc:ID`, it will then show up. Found in this answer: https://stackoverflow.com/a/35117280/1427345 – Jacob Mulquin Nov 29 '22 at 12:07
  • 1
    @JacobMulquin This would have never occurred to me. Thank you! Before trying that out, I'd started modifying my code, adding another level within a specific key, like so: `$arr = ["somekey" => ["schema" => "cbc", "value"=> "foo", "attribute" => "bar"] ]`, and it made everything look strange. Your solution keeps things simpler for me, despite being hacky. Please, post this as an answer, so that I can accept it. – FiddlingAway Nov 29 '22 at 12:14
  • 1
    You should use the `addChild` third parameter as you've shown in the question. – Nigel Ren Nov 29 '22 at 12:29

1 Answers1

2

It's kind of hacky, but you can modify the keys in $my_array to be cbc:cbc:ID, etc. When calling addChild, it will only omit one set of the prefix.

$my_array = [
    "cbc:cbc:ID" => "myId",
    "cbc:cbc:IssueDate" => "2022-07-13",
    "cbc:cbc:DueDate" => "2022-07-20",
    "cbc:cbc:InvoiceTypeCode" => "380",
    "cbc:cbc:DocumentCurrencyCode" => "USD",
    "cac:cac:InvoicePeriod" => [
        "cbc:cbc:DescriptionCode" => "35"
    ],
    "cac:cac:ContractDocumentReference" => [
        "cbc:cbc:ID" => "123-456/22"
    ]
];
Jacob Mulquin
  • 3,458
  • 1
  • 19
  • 22