0

Im having some trouble with creating an Multidimensional SimpleXMLElement, it works well with simple Array's but when there are multidimensional Array the SimpleXMLElement wont write in multid SimpleXMLEelement. Like this:

createXML function:

public function createXML($data, $root = null) {
    $xml = new \SimpleXMLElement($root ? '<' . $root . '/>' : '<marathon/>');
    array_walk_recursive($data, function($value, $key)use($xml){
        $xml->addChild($key, $value);
    });

    $dom = dom_import_simplexml($xml)->ownerDocument;
    $dom->encoding = "UTF-8";
    $dom->formatOutput = true;
    print $dom->saveXML();
}

This prints:

<marathon>
  <media_id>FACE</media_id>
  <agreement_id>****</agreement_id>
  <client_reference>123456</client_reference>
  <client_contact>Asim</client_contact>
  <plan_number>407</plan_number>
  <plan_name>TEST</plan_name>
  <cuid>123456</cuid>
  <status>P</status>
  <colour>0</colour>
  <insertion_date>2018-09-19</insertion_date>
  <end_date>2018-09-20</end_date>
  <client_reference>1234</client_reference>
  <price_code>0</price_code>
  <number_of_units>250000</number_of_units>
  <gross>1000</gross>
  <comment>THIS IS A TEST DO NOT FAKTURER</comment>
</marathon>

When what i want is:

<marathon>
  <media_id>FACE</media_id>
  <agreement_id>REDP</agreement_id>
  <client_reference>123456</client_reference>
  <client_contact>Asim Tariq</client_contact>
  <plan_number>407</plan_number>
  <plan_name>TEST</plan_name>
  <cuid>123456</cuid>
  <status>P</status>
  <colour>0</colour>
     <insertion>
        <insertion_date>2018-09-19</insertion_date>
        <end_date>2018-09-20</end_date>
        <client_reference>1234</client_reference>
              <price_row>
                  <price_code>0</price_code>
                  <number_of_units>250000</number_of_units>
                  <gross>1000</gross>
                  <comment>THIS IS A TEST DO NOT FAKTURER</comment>
             </price_row>
     </insertion>
</marathon>

How can i manage this with the code i have in createXML ? The XML does not get multidimensional?

This is the Array i send in as $data:

[
            "media_id" => 'FACE',
            "agreement_id" => 'REDP',
            "client_reference" => 123456,
            "client_contact" => "Asim Tariq",
            "plan_number" => 407,
            "plan_name" => "TEST",
            "cuid" => 123456,
            "status" => 'P',
            "colour" => 0,
            "insertion" => [
                "insertion_date" => '2018-09-19',
                "end_date" => '2018-09-20',
                "client_reference" => 1234,
                "price_row" => [
                    "price_code" => 000,
                    "number_of_units" => 250000,
                    "gross" => 1000,
                    "discount" => [

                    ], 
                 "comment" => "THIS IS A TEST DO NOT FAKTURER",
                ],
            ],
        ]
Asim
  • 936
  • 2
  • 10
  • 29
  • 1
    Well right now you are only ever appending elements to the root element, `$xml->addChild()` - so that part would have to be changed accordingly, in a way that you somehow pass in the correct current parent element to work with. – misorude Sep 24 '18 at 12:12
  • @PhilippMaurer its not a duplicate. I am having trouble not only adding elements to root. The link you provide does not give this details. – Asim Sep 24 '18 at 12:14
  • Yes @misorude it looks like even the "insertion" key is missing and the key/value inside that array is put on root element. How can i make it a key and add elements inside that in XML? – Asim Sep 24 '18 at 12:15
  • 1
    Have your tried [this](https://stackoverflow.com/a/5965940/8913537) answer? – Philipp Maurer Sep 24 '18 at 12:15
  • Yes @PhilippMaurer. Im getting errors like this on that function: Call to a member function addChild() on a non-object – Asim Sep 24 '18 at 12:19
  • 1
    _“it looks like even the "insertion" key is missing”_ - probably due to the fact that you are trying to do `addChild($key, $value)` in that case as well, even though the value in this case will itself be an array. You would need to differentiate between those two cases. Not sure if `array_walk_recursive` is the best way to go about this; a self-written function that calls itself recursively might be the better alternative. – misorude Sep 24 '18 at 12:19
  • @Asim You probably did not provide a `SimpleXMLElement` as `$xml_data` then. Give that answer another chance. It is most likely the solution to your problem. – Philipp Maurer Sep 24 '18 at 12:21

1 Answers1

2

According to the documentation for array_walk_recursive, "any key that holds an array will not be passed to the function".

Write a recursive function instead which adds the value to a subelement if it is an array. For example:

private function addXMLData(\SimpleXMLElement $xml, array $data)
{
    array_walk($data, function($value, $key) use($xml){
        if (is_array($value)) {
            $child = $xml->addChild($key);
            self::addXMLData($child, $value);
        } else {
            $xml->addChild($key, $value);
        }
    });
}

public function createXML($data, $root = null) {
    $xml = new \SimpleXMLElement($root ? '<' . $root . '/>' : '<marathon/>');

    self::addXMLData($xml, $data);

    $dom = dom_import_simplexml($xml)->ownerDocument;
    $dom->encoding = "UTF-8";
    $dom->formatOutput = true;
    print $dom->saveXML();
}
Asim
  • 936
  • 2
  • 10
  • 29
Matt Raines
  • 4,149
  • 8
  • 31
  • 34
  • Yes so array_walk_recursive is then not possible to use. I tried just fast copy/paste your code to check if it works out of box, but i get this error: Using $this when not in object context. This is well related to private/public function?. The method i use to call the function createXML: $request_xml = self::createXML($request); – Asim Sep 24 '18 at 12:25
  • I've edited the answer correspondingly. I didn't realise you were calling the function statically. – Matt Raines Sep 24 '18 at 12:29
  • Thats my fault sorry @Matt. Your solution work perfectly now!! Thanks alot :) – Asim Sep 24 '18 at 12:29