Transform array into XML

Asked

Viewed 1,922 times

1

I’m trying to turn an array into an XML

My XML needs to have the following structure

<Products>
  <Product name="TR-501">
    <Descricao texto="55.180.198 / 46789771" />
    <Detalhes>
      <Variacao modelo="Palio" ano="2006" motor="1.0 FIRE 8V (FLEX)" />
    </Detalhes>
  </Product>
</Products>

to make the conversion I am using the following function in php

// function defination to convert array to xml
function array_to_xml( $data, &$xml_data ) {
    foreach( $data as $key => $value ) {
        if( is_numeric($key) ){
            $key = 'item'.$key; //dealing with <0/>..<n/> issues
        }
        if( is_array($value) ) {
            $subnode = $xml_data->addChild($key);
            array_to_xml($value, $subnode);
        } else {
            $xml_data->addChild("$key",htmlspecialchars("$value"));
        }
    }
}

and I’m getting the following feedback

<?xml version="1.0"?>
<Products>
    <product>
        <name>TR-501</name>
        <description>55.180.198 / 46789771</description>
        <detalhes>
            <variacao>
                <item0>
                    <modelo>Palio</modelo>
                    <ano>2006</ano>
                    <motor>1.0 FIRE 8V (FLEX)</motor>
                </item0>
                <item1>
                    <modelo>Palio</modelo>
                    <ano>2006</ano>
                    <motor>1.0 FIRE 8V (FLEX)</motor>
                </item1>
                <item2>
                    <modelo>Palio</modelo>
                    <ano>2006</ano>
                    <motor>1.0 FIRE 8V (FLEX)</motor>
                </item2>
            </variacao>
        </detalhes>
    </product>
</Products>

How can I make it so that I can get multiple rows of with the relative data in instead of <item0> <item1> <item2>? Note: the way the data is displayed inside the items, whether by property or content of the tags is irrelevant, it is relevant only that I can get several lines of <variacao> different without <item0> <item1>. Ex:

<Variacao modelo="Palio" ano="2006" motor="1.0 FIRE 8V (FLEX)" />
  <Variacao modelo="Palio" ano="2001/2004" motor="1.0 FIRE 8V (FLEX)" />
  <Variacao modelo="Palio" ano="2003/2006" motor="1.3 FIRE 8V" />

1 answer

0


The problem is that you are adding the keys of the associative array to "item" plus a number:

$key = 'item'.$key;

In addition, there is no way to distinguish the attributes of the descending elements.

I leave another implementation for what you want:

<?php

function array_to_xml(array $data) {
    $document = new DOMDocument();
    array_to_xml_aux($data, $document);
    $document->formatOutput = true;
    return $document;
}

function array_to_xml_aux(array $data, DOMNode $parent, $name = null)
{
    foreach ($data as $key => $value) {
        if ($key[0] == '@') {
            $parent->setAttribute(
                substr($key, 1),
                $value
            );
            continue;
        }

        if (is_numeric($key)) {
            $key = $name;
        }

        if (is_array($value)) {
            $areAllInt = true;
            foreach(array_keys($value) as $k) {
                if (!is_int($k)) {
                    $areAllInt = false;
                    break;
                }
            }
            if ($areAllInt) {
                array_to_xml_aux($value, $parent, $key);
            } else {
                $subnode = new DOMElement($key);
                $parent->appendChild($subnode);
                array_to_xml_aux($value, $subnode, $key);
            }

        } else {
            $xml_data->appendChild(new DOMElement($key, $value));
        }
    }
}

Note that for reasons of simplification I did not put validations and I am assuming that the strings are in ASCII format. I used the DOM library instead of Simplexml (which you were using).

If you do:

$document = array_to_xml(
array(
     'Products' => array(
            'Product' => array('@name' => 'TR-501'),
            'Descricao' => array('@text' => '55.180.198 / 46789771'),
            'Detalhes' => array(
                'Variacao' => array(
                    array(
                        '@modelo' => 'Palio',
                        '@ano' => '2006',
                        '@motor' => '1.0 FIRE 8V (FLEX)',
                    ),
                    array(
                        '@modelo' => 'Palio2',
                        '@ano' => '2007',
                        '@motor' => '1.0 FIRE 9V (FLEX)',
                    ),
                )
            ),
        )
    )
);
echo $document->saveXML();

the exit will be:

<?xml version="1.0"?>
<Products>
  <Product name="TR-501"/>
  <Descricao text="55.180.198 / 46789771"/>
  <Detalhes>
    <Variacao modelo="Palio" ano="2006" motor="1.0 FIRE 8V (FLEX)"/>
    <Variacao modelo="Palio2" ano="2007" motor="1.0 FIRE 9V (FLEX)"/>
  </Detalhes>
</Products>

The code can be viewed and tested on: https://3v4l.org/78Pjl (if no one changes it)

Again I notice I’m using the DOM library:

http://php.net/manual/en/class.domdocument.php

You were using the Simplexml library:

http://php.net/manual/en/book.simplexml.php

DOM is a standard that even browsers and Javascript use and is faster than Simplexml (which uses DOM internally).

It is also necessary to differentiate the attributes of the descending elements. I did this with the prefix "@".

To add multiple elements with the same name within the same element, just use an array without explicit keys. Example:

               [...]
               'Variacao' => array(
                    array(
                        '@modelo' => 'Palio',
                        '@ano' => '2006',
                        '@motor' => '1.0 FIRE 8V (FLEX)',
                    ),
                    array(
                        '@modelo' => 'Palio2',
                        '@ano' => '2007',
                        '@motor' => '1.0 FIRE 9V (FLEX)',
                    ),
                )
                [...]

If you want a different format, there must be an explanation of how you want it.

  • Hello Peter, I tested using your implementation, but the problem persists the same, I can not generate two lines of <Variacao> with different values

  • There seems to be something strange about this Else } else {&#xA; $xml_data->appendChild(new DOMElement($key, $value)); }

  • I made a correction and changed the answer to show an example with "two lines of <Variation> with different values". The code can be tested on: https://3v4l.org/BquYA

  • Good Peter! It worked!

Browser other questions tagged

You are not signed in. Login or sign up in order to post.