Transform array into XML

1

I'm trying to transform 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 do the conversion I'm 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 return

<?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 do so that I can get multiple rows of relative data inside instead of <item0> <item1> <item2> ? Note: the way the data is displayed inside the items, whether it's property or content of the tags is irrelevant, it's only relevant 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" />
    
asked by anonymous 17.04.2018 / 17:57

1 answer

0

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

$key = 'item'.$key;

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

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));
        }
    }
}

Please note that for simplification reasons I have not implemented any 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 output 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 at: link (if nobody changes it)

I again notice that I'm using the DOM library:

link

You were using the SimpleXML library:

link

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 inside the same element, simply use an array with no 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 should be an explanation of how you want it.

    
18.04.2018 / 12:18