Como converter array para SimpleXML

Respostas:

209

uma curta:

<?php

$test_array = array (
  'bla' => 'blub',
  'foo' => 'bar',
  'another_array' => array (
    'stack' => 'overflow',
  ),
);
$xml = new SimpleXMLElement('<root/>');
array_walk_recursive($test_array, array ($xml, 'addChild'));
print $xml->asXML();

resulta em

<?xml version="1.0"?>
<root>
  <blub>bla</blub>
  <bar>foo</bar>
  <overflow>stack</overflow>
</root>

chaves e valores são trocados - você pode corrigir isso array_flip()antes do array_walk. array_walk_recursiverequer PHP 5. você poderia usar array_walk, mas não entrará 'stack' => 'overflow'no xml.

machado.
fonte
53
Isso não funcionará se $ test_array tiver 'more_another_array' como 'another_array', porque a chave 'another_array' não será convertida. Portanto, você terá várias '<overflow> stack </overflow>'.
understack
11
O array_flipnão funcionará, pois não pode inverter matrizes (como o another_arrayinterior da matriz principal).
Lode
14
Onde está o elemento xml "another_array"? Tudo está achatado :(
FMaz008
2
Funcionou muito bem quando adicionei array_flip antes de array_walk_recursive. obrigado.
8118 Mike Purcell
12
Voto negativo, porque array_flipsó funciona se a matriz não contém valores idênticos.
287 Martijn
385

Aqui está o código php 5.2 que converterá array de qualquer profundidade em documento xml:

Array
(
    ['total_stud']=> 500
    [0] => Array
        (
            [student] => Array
                (
                    [id] => 1
                    [name] => abc
                    [address] => Array
                        (
                            [city]=>Pune
                            [zip]=>411006
                        )                       
                )
        )
    [1] => Array
        (
            [student] => Array
                (
                    [id] => 2
                    [name] => xyz
                    [address] => Array
                        (
                            [city]=>Mumbai
                            [zip]=>400906
                        )   
                )

        )
)

XML gerado seria como:

<?xml version="1.0"?>
<student_info>
    <total_stud>500</total_stud>
    <student>
        <id>1</id>
        <name>abc</name>
        <address>
            <city>Pune</city>
            <zip>411006</zip>
        </address>
    </student>
    <student>
        <id>1</id>
        <name>abc</name>
        <address>
            <city>Mumbai</city>
            <zip>400906</zip>
        </address>
    </student>
</student_info>

Fragmento de PHP

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

// initializing or creating array
$data = array('total_stud' => 500);

// creating object of SimpleXMLElement
$xml_data = new SimpleXMLElement('<?xml version="1.0"?><data></data>');

// function call to convert array to xml
array_to_xml($data,$xml_data);

//saving generated xml file; 
$result = $xml_data->asXML('/file/path/name.xml');

?>

Documentação SimpleXMLElement::asXMLusada neste snippet

Hanmant
fonte
40
A IMO é uma solução muito melhor do que a resposta aceita. No entanto, isso tem a limitação de que, com matrizes numeradas com chave, ele gera XML malformado. <0> <1> <2> não são nomes de nó válidos.
KOGI 5/10
2
Porém, se sua matriz numerada com chave contiver apenas outra matriz que não seja numerada, ela não será.
Bryan Petty
15
@KOGI Modifiquei a resposta Hanmant. Agora, seu suporte matrizes multinível. pastebin.com/pYuXQWee
Mifas
1
Este exemplo escapa explicitamente caracteres especiais nos dados de texto do elemento usando htmlspecialchars, mas SimpleXMLElement :: addChild converte caracteres especiais xml em suas entidades char automaticamente para que htmlspecialchars possa ser deixado de fora. Curiosamente, isso parece não resultar em dados duplamente escapados.
mbaynton
3
@ Alex, sua edição nº 5 faz com que o exemplo falhe. Ele insere <item $ x> antes de cada registro <estudent>, fazendo com que a saída XML não seja o que o autor pretendia. Talvez forneça um exemplo do problema que você está tentando corrigir e podemos encontrar outra solução para os dois casos. Demorei um pouco antes de eu perceber que o código dos autores foi modificado.
Nicholas Blasgen
124

As respostas fornecidas aqui convertem apenas a matriz para XML com nós; você não pode definir atributos. Eu escrevi uma função php que permite converter uma matriz para php e também definir atributos para nós específicos no xml. A desvantagem aqui é que você precisa construir uma matriz de uma maneira específica com poucas convenções (somente se você quiser usar atributos)

O exemplo a seguir também permitirá que você defina atributos em XML.

A fonte pode ser encontrada aqui: https://github.com/digitickets/lalit/blob/master/src/Array2XML.php

<?php    
$books = array(
    '@attributes' => array(
        'type' => 'fiction'
    ),
    'book' => array(
        array(
            '@attributes' => array(
                'author' => 'George Orwell'
            ),
            'title' => '1984'
        ),
        array(
            '@attributes' => array(
                'author' => 'Isaac Asimov'
            ),
            'title' => 'Foundation',
            'price' => '$15.61'
        ),
        array(
            '@attributes' => array(
                'author' => 'Robert A Heinlein'
            ),
            'title' => 'Stranger in a Strange Land',
            'price' => array(
                '@attributes' => array(
                    'discount' => '10%'
                ),
                '@value' => '$18.00'
            )
        )
    )
);
/* creates 
<books type="fiction">
  <book author="George Orwell">
    <title>1984</title>
  </book>
  <book author="Isaac Asimov">
    <title>Foundation</title>
    <price>$15.61</price>
  </book>
  <book author="Robert A Heinlein">
    <title>Stranger in a Strange Land</title>
    <price discount="10%">$18.00</price>
  </book>
</books>
*/
?>
Lalit
fonte
9
Estou surpreso que ninguém tenha reagido a isso. Essa classe é realmente útil, pois está fazendo o oposto do que o simpleXMLElement gerará. Portanto, oferece a possibilidade de usar o SimpleXMLElement nos dois sentidos.
FMaz008
4
Eu marcaria isso como resposta em vez de atual. Resposta atual não criando matrizes recursivas
Oleksandr IY
2
Boa aula. Mudei linha 128 if(!is_array($arr)) {para if(!is_array($arr) && $arr !== '') {de modo que não irá acrescentar um novo nó de texto para cadeias vazias e, portanto, mantém o formato tag vazio taquigrafia isto 'tag'=>''é <tag/>, em vez de<tag></tag>
user1433150
Esta é a melhor resposta até agora. Além disso, possui a estrutura correta de vários itens com a mesma chave: 1º é a chave do nome do nó e, em seguida, contém a matriz com chaves numéricas. (o oposto da resposta Hanmant)
Vasil Popov
1
Encontrou um github do autor @Legionar github.com/digitickets/lalit/blob/master/src/Array2XML.php
Daryl Teo
57

Encontrei todas as respostas para usar muito código. Aqui está uma maneira fácil de fazer isso:

function to_xml(SimpleXMLElement $object, array $data)
{   
    foreach ($data as $key => $value) {
        if (is_array($value)) {
            $new_object = $object->addChild($key);
            to_xml($new_object, $value);
        } else {
            // if the key is an integer, it needs text with it to actually work.
            if ($key == (int) $key) {
                $key = "key_$key";
            }

            $object->addChild($key, $value);
        }   
    }   
}   

Então é uma simples questão de enviar a matriz para a função, que usa recursão, para lidar com uma matriz multidimensional:

$xml = new SimpleXMLElement('<rootTag/>');
to_xml($xml, $my_array);

Agora $ xml contém um belo objeto XML baseado em sua matriz exatamente como você o escreveu.

print $xml->asXML();
Francis Lewis
fonte
9
Eu amo essa solução mais. Embora, seria bom para adicionar um teste em teclas numéricas, como: if ( is_numeric( $key ) ) $key = "numeric_$key"; .
Wout 1/11
Boa captura. Adicionado. Fiz uma verificação int cast em vez de is_numeric, porque is_numeric pode fornecer alguns resultados, embora tecnicamente esperados, que realmente o afastariam.
Francis Lewis
Eu uso essa função, mas mudei $xml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8" ?><rootTag/>');para codificação UTF-8 válida.
Daantje 30/03
Eu gosto desta solução o mais bem, simples faz :-) Uma observação: Você pode querer mudar $object->addChild($key, $value);para $object->addChild($key, htmlspecialchars($value));para evitar que ele falha quando $ value contém caracteres como "&" essa necessidade XML-codificação.
leo
38
<? php
função array_to_xml (matriz $ arr, SimpleXMLElement $ xml)
{
    foreach ($ arr como $ k => $ v) {
        is_array ($ v)
            ? array_to_xml ($ v, $ xml-> addChild ($ k))
            : $ xml-> addChild ($ k, $ v);
    }
    retornar $ xml;
}

$ test_array = array (
    'bla' => 'blub',
    'foo' => 'barra',
    'another_array' => matriz (
        'pilha' => 'estouro',
    ),
);

echo array_to_xml ($ test_array, novo SimpleXMLElement ('<root />')) -> asXML ();
onokazu
fonte
1
isso falhará se sua matriz contiver uma matriz interna com índices numéricos. <0> ... </0> não é um XML válido.
Adriano Varoli Piazza 14/10
@AdrianoVaroliPiazza basta adicionar algo como $k = (is_numeric($k)) ? 'item' : $k;dentro doforeach()
AlienWebguy
Se uma das chaves da matriz for denominada "corpo", ela não funcionará - mais precisamente, a chave será ignorada e atravessada. Tentando descobrir o porquê.
Bambax
@Bambax A única razão pela qual consigo pensar é se o XML está sendo analisado como HTML em algum momento posterior.
Brilliand
16

Do PHP 5.4

function array2xml($data, $root = null){
    $xml = new SimpleXMLElement($root ? '<' . $root . '/>' : '<root/>');
    array_walk_recursive($data, function($value, $key)use($xml){
        $xml->addChild($key, $value);
    });
    return $xml->asXML();
}
user492589
fonte
Parece uma cópia direta da resposta selecionada, basta colocar em uma função.
phaberest
Eu adicionaria htmlspecialchars () à parte addChild, assim: $ xml-> addChild ($ key, htmlspecialchars ($ value));
Tyreal
15

Outra melhoria:

/**
* Converts an array to XML
*
* @param array $array
* @param SimpleXMLElement $xml
* @param string $child_name
*
* @return SimpleXMLElement $xml
*/
public function arrayToXML($array, SimpleXMLElement $xml, $child_name)
{
    foreach ($array as $k => $v) {
        if(is_array($v)) {
            (is_int($k)) ? $this->arrayToXML($v, $xml->addChild($child_name), $v) : $this->arrayToXML($v, $xml->addChild(strtolower($k)), $child_name);
        } else {
            (is_int($k)) ? $xml->addChild($child_name, $v) : $xml->addChild(strtolower($k), $v);
        }
    }

    return $xml->asXML();
}

Uso:

$this->arrayToXML($array, new SimpleXMLElement('<root/>'), 'child_name_to_replace_numeric_integers');
Syl
fonte
Obrigado! Sua função retorna o conteúdo exato de qualquer matriz n-dimensional.
besciualex
12

Aqui está a minha entrada, simples e limpa ..

function array2xml($array, $xml = false){
    if($xml === false){
        $xml = new SimpleXMLElement('<root/>');
    }
    foreach($array as $key => $value){
        if(is_array($value)){
            array2xml($value, $xml->addChild($key));
        }else{
            $xml->addChild($key, $value);
        }
    }
    return $xml->asXML();
}


header('Content-type: text/xml');
print array2xml($array);
Frans van Asselt
fonte
8

Enfim, peguei o código de onokazu (obrigado!) E acrescentei a capacidade de repetir tags em XML, ele também suporta atributos, espero que alguém ache útil!

 <?php

function array_to_xml(array $arr, SimpleXMLElement $xml) {
        foreach ($arr as $k => $v) {

            $attrArr = array();
            $kArray = explode(' ',$k);
            $tag = array_shift($kArray);

            if (count($kArray) > 0) {
                foreach($kArray as $attrValue) {
                    $attrArr[] = explode('=',$attrValue);                   
                }
            }

            if (is_array($v)) {
                if (is_numeric($k)) {
                    array_to_xml($v, $xml);
                } else {
                    $child = $xml->addChild($tag);
                    if (isset($attrArr)) {
                        foreach($attrArr as $attrArrV) {
                            $child->addAttribute($attrArrV[0],$attrArrV[1]);
                        }
                    }                   
                    array_to_xml($v, $child);
                }
            } else {
                $child = $xml->addChild($tag, $v);
                if (isset($attrArr)) {
                    foreach($attrArr as $attrArrV) {
                        $child->addAttribute($attrArrV[0],$attrArrV[1]);
                    }
                }
            }               
        }

        return $xml;
    }

        $test_array = array (
          'bla' => 'blub',
          'foo' => 'bar',
          'another_array' => array (
            array('stack' => 'overflow'),
            array('stack' => 'overflow'),
            array('stack' => 'overflow'),
          ),
          'foo attribute1=value1 attribute2=value2' => 'bar',
        );  

        $xml = array_to_xml($test_array, new SimpleXMLElement('<root/>'))->asXML();

        echo "$xml\n";
        $dom = new DOMDocument;
        $dom->preserveWhiteSpace = FALSE;
        $dom->loadXML($xml);
        $dom->formatOutput = TRUE;
        echo $dom->saveXml();
    ?>
CodePT
fonte
Pode ser útil comentar suas alterações para tornar o código mais claro; ainda, boa adição
StormeHawke
Isso funcionou para mim com o WP All Export. Eu tive que mudar um pouco a parte is_numeric: if (is_numeric($k)) { $i = $k + 1; $child = $xml->addChild("_$i"); array_to_xml($v, $child); }
achiever
4

Eu uso algumas funções que escrevi há algum tempo para gerar o xml para ir e voltar do PHP e do jQuery, etc. ) ...

Se for útil para alguém, use-o :)

function generateXML($tag_in,$value_in="",$attribute_in=""){
    $return = "";
    $attributes_out = "";
    if (is_array($attribute_in)){
        if (count($attribute_in) != 0){
            foreach($attribute_in as $k=>$v):
                $attributes_out .= " ".$k."=\"".$v."\"";
            endforeach;
        }
    }
    return "<".$tag_in."".$attributes_out.((trim($value_in) == "") ? "/>" : ">".$value_in."</".$tag_in.">" );
}

function arrayToXML($array_in){
    $return = "";
    $attributes = array();
    foreach($array_in as $k=>$v):
        if ($k[0] == "@"){
            // attribute...
            $attributes[str_replace("@","",$k)] = $v;
        } else {
            if (is_array($v)){
                $return .= generateXML($k,arrayToXML($v),$attributes);
                $attributes = array();
            } else if (is_bool($v)) {
                $return .= generateXML($k,(($v==true)? "true" : "false"),$attributes);
                $attributes = array();
            } else {
                $return .= generateXML($k,$v,$attributes);
                $attributes = array();
            }
        }
    endforeach;
    return $return;
}   

Amor a todos :)

Neil English
fonte
4

Eu queria um código que pegasse todos os elementos dentro de uma matriz e os tratasse como atributos, e todas as matrizes como subelementos.

Então, para algo como

array (
'row1' => array ('head_element' =>array("prop1"=>"some value","prop2"=>array("empty"))),
"row2"=> array ("stack"=>"overflow","overflow"=>"overflow")
);

Eu teria algo assim

<?xml version="1.0" encoding="utf-8"?>
<someRoot>
  <row1>
    <head_element prop1="some value">
      <prop2 0="empty"/>
    </head_element>
  </row1>
  <row2 stack="overflow" overflow="stack"/>
 </someRoot>

Para conseguir isso, o código está abaixo, mas tenha muito cuidado, é recursivo e pode realmente causar um stackoverflow :)

function addElements(&$xml,$array)
{
$params=array();
foreach($array as $k=>$v)
{
    if(is_array($v))
        addElements($xml->addChild($k), $v);
    else $xml->addAttribute($k,$v);
}

}
function xml_encode($array)
{
if(!is_array($array))
    trigger_error("Type missmatch xml_encode",E_USER_ERROR);
$xml=new SimpleXMLElement('<?xml version=\'1.0\' encoding=\'utf-8\'?><'.key($array).'/>');
addElements($xml,$array[key($array)]);
return $xml->asXML();
} 

Você pode adicionar verificações para o comprimento da matriz, para que algum elemento seja definido dentro da parte dos dados e não como um atributo.

lcornea
fonte
4

Com base em tudo o resto, lida com índices numéricos + atributos via prefixação com @ e pode injetar xml nos nós existentes:

Código

function simple_xmlify($arr, SimpleXMLElement $root = null, $el = 'x') {
    // based on, among others http://stackoverflow.com/a/1397164/1037948

    if(!isset($root) || null == $root) $root = new SimpleXMLElement('<' . $el . '/>');

    if(is_array($arr)) {
        foreach($arr as $k => $v) {
            // special: attributes
            if(is_string($k) && $k[0] == '@') $root->addAttribute(substr($k, 1),$v);
            // normal: append
            else simple_xmlify($v, $root->addChild(
                    // fix 'invalid xml name' by prefixing numeric keys
                    is_numeric($k) ? 'n' . $k : $k)
                );
        }
    } else {
        $root[0] = $arr;
    }

    return $root;
}//--   fn  simple_xmlify

Uso

// lazy declaration via "queryparam"
$args = 'hello=4&var[]=first&var[]=second&foo=1234&var[5]=fifth&var[sub][]=sub1&var[sub][]=sub2&var[sub][]=sub3&var[@name]=the-name&var[@attr2]=something-else&var[sub][@x]=4.356&var[sub][@y]=-9.2252';
$q = array();
parse_str($val, $q);

$xml = simple_xmlify($q); // dump $xml, or...
$result = get_formatted_xml($xml); // see below

Resultado

<?xml version="1.0"?>
<x>
  <hello>4</hello>
  <var name="the-name" attr2="something-else">
    <n0>first</n0>
    <n1>second</n1>
    <n5>fifth</n5>
    <sub x="4.356" y="-9.2252">
      <n0>sub1</n0>
      <n1>sub2</n1>
      <n2>sub3</n2>
    </sub>
  </var>
  <foo>1234</foo>
</x>

Bônus: Formatação XML

function get_formatted_xml(SimpleXMLElement $xml, $domver = null, $preserveWhitespace = true, $formatOutput = true) {
    // http://stackoverflow.com/questions/1191167/format-output-of-simplexml-asxml

    // create new wrapper, so we can get formatting options
    $dom = new DOMDocument($domver);
    $dom->preserveWhiteSpace = $preserveWhitespace;
    $dom->formatOutput = $formatOutput;
    // now import the xml (converted to dom format)
    /*
    $ix = dom_import_simplexml($xml);
    $ix = $dom->importNode($ix, true);
    $dom->appendChild($ix);
    */
    $dom->loadXML($xml->asXML());

    // print
    return $dom->saveXML();
}//--   fn  get_formatted_xml
drzaus
fonte
Uma versão atualizada que repete como elementos filhos, em vez de etiquetas numéricas: github.com/zaus/forms-3rdparty-xpost/blob/...
drzaus
3

Aqui está uma função que fez o truque para mim:

Basta chamá-lo com algo como

echo arrayToXml("response",$arrayIWantToConvert);
function arrayToXml($thisNodeName,$input){
        if(is_numeric($thisNodeName))
            throw new Exception("cannot parse into xml. remainder :".print_r($input,true));
        if(!(is_array($input) || is_object($input))){
            return "<$thisNodeName>$input</$thisNodeName>";
        }
        else{
            $newNode="<$thisNodeName>";
            foreach($input as $key=>$value){
                if(is_numeric($key))
                    $key=substr($thisNodeName,0,strlen($thisNodeName)-1);
                $newNode.=arrayToXml3($key,$value);
            }
            $newNode.="</$thisNodeName>";
            return $newNode;
        }
    }
Mike
fonte
3

Você pode usar o XMLParser em que estou trabalhando.

$xml = XMLParser::encode(array(
    'bla' => 'blub',
    'foo' => 'bar',
    'another_array' => array (
        'stack' => 'overflow',
    )
));
// @$xml instanceof SimpleXMLElement
echo $xml->asXML();

Resultaria em:

<?xml version="1.0"?>
<root>
    <bla>blub</bla>
    <foo>bar</foo>
    <another_array>
        <stack>overflow</stack>
    </another_array>
</root>
jtrumbull
fonte
3

Encontrei esta solução semelhante ao problema original

<?php

$test_array = array (
  'bla' => 'blub',
  'foo' => 'bar',
  'another_array' => array (
    'stack' => 'overflow',
  ),
);

class NoSimpleXMLElement extends SimpleXMLElement {
 public function addChild($name,$value) {
  parent::addChild($value,$name);
 }
}
$xml = new NoSimpleXMLElement('<root/>');
array_walk_recursive($test_array, array ($xml, 'addChild'));
print $xml->asXML();
caiofior
fonte
3

A maioria das respostas acima está correta. No entanto, eu vim com esta resposta que resolve o problema de compatibilidade array_walk_recursive e também o problema de chaves numéricas. Também passou em todos os testes que fiz:

function arrayToXML(Array $array, SimpleXMLElement &$xml) {

    foreach($array as $key => $value) {

        // None array
        if (!is_array($value)) {
            (is_numeric($key)) ? $xml->addChild("item$key", $value) : $xml->addChild($key, $value);
            continue;
        }   

        // Array
        $xmlChild = (is_numeric($key)) ? $xml->addChild("item$key") : $xml->addChild($key);
        arrayToXML($value, $xmlChild);
    }
}   

Também adicionei uma classe de teste para isso, que você pode achar útil:

class ArrayToXmlTest extends PHPUnit_Framework_TestCase {

    public function setUp(){ }
    public function tearDown(){ }

    public function testFuncExists() {
        $this->assertTrue(function_exists('arrayToXML'));
    }

    public function testFuncReturnsXml() {
        $array = array(
            'name' => 'ardi',
            'last_name' => 'eshghi',
            'age' => 31,
            'tel' => '0785323435'
        );

        $xmlEl =  new SimpleXMLElement('<root/>');
        arrayToXml($array, $xmlEl);

        $this->assertTrue($xmlEl instanceOf SimpleXMLElement);
    }

    public function testAssocArrayToXml() {

        $array = array(
            'name' => 'ardi',
            'last_name' => 'eshghi',
            'age' => 31,
            'tel' => '0785323435'
        );

        $expectedXmlEl = new SimpleXMLElement('<root/>'); 
        $expectedXmlEl->addChild('name', $array['name']);
        $expectedXmlEl->addChild('last_name', $array['last_name']);
        $expectedXmlEl->addChild('age', $array['age']);
        $expectedXmlEl->addChild('tel', $array['tel']);

        $actualXmlEl =  new SimpleXMLElement('<root/>');
        arrayToXml($array, $actualXmlEl);

        $this->assertEquals($expectedXmlEl->asXML(), $actualXmlEl->asXML());
    }

    public function testNoneAssocArrayToXml() {

        $array = array(
            'ardi',
            'eshghi',
            31,
            '0785323435'
        );

        // Expected xml value
        $expectedXmlEl = new SimpleXMLElement('<root/>'); 
        foreach($array as $key => $value)
            $expectedXmlEl->addChild("item$key", $value);

        // What the function produces       
        $actualXmlEl =  new SimpleXMLElement('<root/>');
        arrayToXml($array, $actualXmlEl);

        $this->assertEquals($expectedXmlEl->asXML(), $actualXmlEl->asXML());
    }

    public function testNestedMixArrayToXml() {

        $testArray = array(
            "goal",
            "nice",
            "funny" => array(
                'name' => 'ardi',
                'tel'   =>'07415517499',
                "vary",
                "fields" => array(
                    'small',
                    'email' => '[email protected]'
                ),

                'good old days'

            ),

            "notes" => "come on lads lets enjoy this",
            "cast" => array(
                'Tom Cruise',
                'Thomas Muller' => array('age' => 24)
            )
        );

        // Expected xml value
        $expectedXmlEl = new SimpleXMLElement('<root/>'); 
        $expectedXmlEl->addChild('item0', $testArray[0]);
        $expectedXmlEl->addChild('item1', $testArray[1]);
        $childEl = $expectedXmlEl->addChild('funny');
        $childEl->addChild("name", $testArray['funny']['name']);
        $childEl->addChild("tel", $testArray['funny']['tel']);
        $childEl->addChild("item0", "vary");
        $childChildEl = $childEl->addChild("fields");
        $childChildEl->addChild('item0', 'small');
        $childChildEl->addChild('email', $testArray['funny']['fields']['email']);
        $childEl->addChild("item1", 'good old days');
        $expectedXmlEl->addChild('notes', $testArray['notes']);
        $childEl2 = $expectedXmlEl->addChild('cast');
        $childEl2->addChild('item0', 'Tom Cruise');
        $childChildEl2 = $childEl2->addChild('Thomas Muller');
        $childChildEl2->addChild('age', $testArray['cast']['Thomas Muller']['age']);

        // What the function produces       
        $actualXmlEl = new SimpleXMLElement('<root/>');
        arrayToXml($testArray, $actualXmlEl);

        $this->assertEquals($expectedXmlEl->asXML(), $actualXmlEl->asXML());
    }
}      
Ardi
fonte
3

outra solução:

$marray=array(....);
$options = array(
                "encoding" => "UTF-8",
                "output_type" => "xml", 
                "version" => "simple",
                "escaping" => array("non-ascii, on-print, markup")
                );
$xmlres = xmlrpc_encode_request('root', $marray, $options);
print($xmlres);
Gaius Baltar
fonte
Isso tem um efeito inesperado de criar XML no estilo RPC com coisas como methodCall, methodName, escalares e vetores, etc. Não é realmente converter uma matriz em XML no sentido direto.
Volomike 4/16
3

Se a matriz for associativa e digitada corretamente, provavelmente seria mais fácil transformá-la em xml primeiro. Algo como:

  function array2xml ($array_item) {
    $xml = '';
    foreach($array_item as $element => $value)
    {
        if (is_array($value))
        {
            $xml .= "<$element>".array2xml($value)."</$element>";
        }
        elseif($value == '')
        {
            $xml .= "<$element />";
        }
        else
        {
            $xml .= "<$element>".htmlentities($value)."</$element>";
        }
    }
    return $xml;
}

$simple_xml = simplexml_load_string(array2xml($assoc_array));

A outra rota seria criar primeiro o seu XML básico, como

$simple_xml = simplexml_load_string("<array></array>");

e, em seguida, para cada parte da sua matriz, use algo semelhante ao meu loop de criação de texto e, em vez disso, use as funções simplexml "addChild" para cada nó da matriz.

Vou tentar isso mais tarde e atualizar este post com as duas versões.

Anthony
fonte
A parte em que mencionei "<array> </array>" me fez perceber que a versão em string precisa de algo semelhante. Basicamente, a matriz precisa ter um nó do lado de fora. Deixe-me dormir a coisa toda, vou ter algo que pega esse erro inicial imediatamente.
Anthony
2

Apenas uma edição em uma função acima, quando uma tecla for numérica, adicione um prefixo "key_"

// initializing or creating array
$student_info = array(your array data);

// creating object of SimpleXMLElement
$xml_student_info = new SimpleXMLElement("<?xml version=\"1.0\"?><student_info></student_info>");

// function call to convert array to xml
array_to_xml($student,$xml_student_info);

//saving generated xml file
$xml_student_info->asXML('file path and name');


function array_to_xml($student_info, &$xml_student_info) {
     foreach($student_info as $key => $value) {
          if(is_array($value)) {
            if(!is_numeric($key)){
                $subnode = $xml_student_info->addChild("$key");
                array_to_xml($value, $subnode);
            }
            else{
                $subnode = $xml_student_info->addChild("key_$key");
                array_to_xml($value, $subnode);
            }
          }
          else {
               if(!is_numeric($key)){
                    $xml_student_info->addChild("$key","$value");
               }else{
                    $xml_student_info->addChild("key_$key","$value");
               }
          }
     }
}
Frankey
fonte
1

Você pode usar a seguinte função no código diretamente,

    function artoxml($arr, $i=1,$flag=false){
    $sp = "";
    for($j=0;$j<=$i;$j++){
        $sp.=" ";
     }
    foreach($arr as $key=>$val){
        echo "$sp&lt;".$key."&gt;";
        if($i==1) echo "\n";
        if(is_array($val)){
            if(!$flag){echo"\n";}
            artoxml($val,$i+5);
            echo "$sp&lt;/".$key."&gt;\n";
        }else{
              echo "$val"."&lt;/".$key."&gt;\n";
         }
    }

}

Chame a função com o primeiro argumento como sua matriz e o segundo argumento deve ser 1, isso aumentará para um recuo perfeito e o terceiro deve ser verdadeiro.

por exemplo, se a variável da matriz a ser convertida for $ array1, a chamada seria, a função de chamada deve ser encapsulada com <pre>tag.

  artoxml ($ array1,1, true);   

Consulte a fonte da página após executar o arquivo, porque os símbolos <e> não serão exibidos em uma página html.

JosephVasantPrakash
fonte
1
function toXML($data, $obj = false, $dom) {
    $is_first_level = false;
    if($obj === false) {
        $dom = new DomDocument('1.0');
        $obj = $dom;
        $is_first_level = true;
    }

    if(is_array($data)) {
        foreach($data as $key => $item) {
            $this->toXML($item, $obj->appendChild($dom->createElement($key)), $dom);
        }
    }else {
        $obj->appendChild($dom->createTextNode($data));
    }

    if($is_first_level) {
        $obj->formatOutput = true;
        return $obj->saveXML();
    }
    return $obj;
}
Andrey
fonte
Esta é uma excelente opção para criar xml DOMDocument. Obrigado @Andrey
altsyset
1
function array2xml(array $data, SimpleXMLElement $object = null, $oldNodeName = 'item')
{
    if (is_null($object)) $object = new SimpleXMLElement('<root/>');
    $isNumbered = true;
    $idx = 0;
    foreach ($data as $key => $x)
        if (is_string($key) || ($idx++ != $key + 0))
            $isNumbered = false;
    foreach ($data as $key => $value)
    {   
        $attribute = preg_match('/^[0-9]/', $key . '') ? $key : null;
        $key = (is_string($key) && !preg_match('/^[0-9]/', $key . '')) ? $key : preg_replace('/s$/', '', $oldNodeName);
        if (is_array($value))
        {
            $new_object = $object->addChild($key);
            if (!$isNumbered && !is_null($attribute)) $new_object->addAttribute('id', $attribute);
            array2xml($value, $new_object, $key);
        }
        else
        {
            if (is_bool($value)) $value = $value ? 'true' : 'false';
            $node = $object->addChild($key, htmlspecialchars($value));
            if (!$isNumbered && !is_null($attribute) && !isset($node->attributes()->id))
                $node->addAttribute('id', $attribute);
        }
    }
    return $object;
}

Esta função retorna, por exemplo, uma lista de tags XML <obj>...</obj> <obj> ... </obj> para índices numéricos.

Entrada:

    array(
    'people' => array(
        'dog',
        'cat',
        'life' => array(
            'gum',
            'shoe',
        ),
        'fish',
    ),
    array('yeah'),
)

Resultado:

<root>
    <people>
        <people>dog</people>
        <people>cat</people>
        <life>
            <life>gum</life>
            <life>shoe</life>
        </life>
        <people>fish</people>
        <people>
            <people>yeah</people>
        </people>
    </people>
</root>

Isso deve satisfazer todas as necessidades comuns. Talvez você possa alterar a terceira linha para:

$key = is_string($key) ? $key : $oldNodeName . '_' . $key;

ou se você estiver trabalhando com plurais terminando com s:

$key = is_string($key) ? $key : preg_replace('/s$/', '', $oldNodeName);
user2381982
fonte
1

Com o FluidXML, você pode gerar, a partir de uma matriz PHP , um XML para SimpleXML com ... apenas duas linhas de código.

$fluidxml  = fluidxml($array);
$simplexml = simplexml_import_dom($fluidxml->dom());

Uma matriz de exemplo pode ser

$array = [ 'doc' => [
              'fruit' => 'orange',
              'cake'  => [
                   '@id' => '123', 
                   '@'   => 'tiramisu' ],
              [ 'pasta' => 'matriciana' ],
              [ 'pasta' => 'boscaiola'  ]
] ];

https://github.com/servo-php/fluidxml

Daniele Orlando
fonte
0

Você pode usar xmlrpc_encode para criar um xml a partir da matriz se um xml detalhado não for um problema. www.php.net/xmlrpc_encode

tenha cuidado para o xml criado diferir caso você use chaves associativas e / ou numéricas

<?php
// /params/param/value/struct/member
// there is a tag "member" for each element
// "member" contains a tag "name". its value is the associative key
$xml1 = xmlrpc_encode(array('a'=>'b','c'=>'d'));
$simplexml1 = simplexml_load_string($xml1);
print_r($xml1);
print_r($simplexml1);

// /params/param/value/array/data
// there is a tag "data" for each element
// "data" doesn't contain the tag "name"
$xml2 = xmlrpc_encode(array('a','b'));
$simplexml2 = simplexml_load_string($xml2);
print_r($xml2);
print_r($simplexml2);
?>
w35l3y
fonte
Esta função não é suportada e, de fato, não é fornecida em minhas compilações do PHP 5.2.16 ou PHP 5.3.5. (retorna “PHP Erro fatal: Chamada para xmlrpc_encode função indefinida ()”)
danorton
você tem que remover o comentário da seguinte linha no php.ini: extension = php_xmlrpc.dll
w35l3y
@ w35l3y eu verifiquei meu ini. Ele nem contém essa extensão e estou usando a versão 5.3.6.
Mike S.
0
function array2xml($array, $xml = false){

    if($xml === false){

        $xml = new SimpleXMLElement('<?xml version=\'1.0\' encoding=\'utf-8\'?><'.key($array).'/>');
        $array = $array[key($array)];

    }
    foreach($array as $key => $value){
        if(is_array($value)){
            $this->array2xml($value, $xml->addChild($key));
        }else{
            $xml->addChild($key, $value);
        }
    }
    return $xml->asXML();
}
Kamil Dąbrowski
fonte
0

Minha resposta, juntando as respostas dos outros. Isso deve corrigir a falha em compensar as teclas numéricas:

function array_to_xml($array, $root, $element) {
    $xml = new SimpleXMLElement("<{$root}/>");
    foreach ($array as $value) {
        $elem = $xml->addChild($element);
        xml_recurse_child($elem, $value);
    }
    return $xml;
}

function xml_recurse_child(&$node, $child) {
    foreach ($child as $key=>$value) {
        if(is_array($value)) {
            foreach ($value as $k => $v) {
                if(is_numeric($k)){
                    xml_recurse_child($node, array($key => $v));
                }
                else {
                    $subnode = $node->addChild($key);
                    xml_recurse_child($subnode, $value);
                }
            }
        }
        else {
            $node->addChild($key, $value);
        }
    }   
}

A array_to_xml()função presume que a matriz seja composta primeiro por teclas numéricas. Se sua matriz tivesse um elemento inicial, você soltaria as instruções foreach()e $elemda array_to_xml()função e passaria $xml.

refeyd
fonte
0

Eu teria comentado a segunda resposta mais votada, porque ela não preserva a estrutura e gera xml incorreto se houver matrizes internas indexadas numericamente.

Desenvolvi minha própria versão com base nela, porque precisava de um conversor simples entre json e xml, independentemente da estrutura dos dados. Minha versão preserva as informações de chave numérica e a estrutura da matriz original. Ele cria elementos para os valores indexados numericamente, agrupando valores em elementos nomeados como valor com atributo-chave que contém chave numérica.

Por exemplo

array('test' => array(0 => 'some value', 1 => 'other'))

converte para

<test><value key="0">some value</value><value key="1">other</value></test>

Minha versão do array_to_xml -function (espero que ajude alguém :)

function array_to_xml($arr, &$xml) {
    foreach($arr as $key => $value) {
        if(is_array($value)) {
            if(!is_numeric($key)){
                $subnode = $xml->addChild("$key");
            } else {
                $subnode = $xml->addChild("value");
                $subnode->addAttribute('key', $key);                    
            }
            array_to_xml($value, $subnode);
        }
        else {
            if (is_numeric($key)) {
                $xml->addChild("value", $value)->addAttribute('key', $key);
            } else {
                $xml->addChild("$key",$value);
            }
        }
    }
}   
Jouni Mäkeläinen
fonte
0

Toda a estrutura XML é definida em $ data Array:

function array2Xml($data, $xml = null)
{
    if (is_null($xml)) {
        $xml = simplexml_load_string('<' . key($data) . '/>');
        $data = current($data);
        $return = true;
    }
    if (is_array($data)) {
        foreach ($data as $name => $value) {
            array2Xml($value, is_numeric($name) ? $xml : $xml->addChild($name));
        }
    } else {
        $xml->{0} = $data;
    }
    if (!empty($return)) {
        return $xml->asXML();
    }
}
ás
fonte
0

Se você trabalha no magento e tem esse tipo de array associativo

$test_array = array (
    '0' => array (
            'category_id' => '582',
            'name' => 'Surat',
            'parent_id' => '565',
            'child_id' => '567',
            'active' => '1',
            'level' => '6',
            'position' => '17'
    ),

    '1' => array (
            'category_id' => '567', 
            'name' => 'test',
            'parent_id' => '0',
            'child_id' => '576',
            'active' => '0',
            'level' => '0',
            'position' => '18'
    ),
);

é melhor converter a matriz associativa para o formato xml.Use este código no arquivo do controlador.

$this->loadLayout(false);
//header ("content-type: text/xml");
$this->getResponse()->setHeader('Content-Type','text/xml');
$this->renderLayout();

$clArr2xml = new arr2xml($test_array, 'utf-8', 'listdata');
$output = $clArr2xml->get_xml();
print $output; 

class arr2xml
{
var $array = array();
var $xml = '';
var $root_name = '';
var $charset = '';

public function __construct($array, $charset = 'utf-8', $root_name = 'root')
{
    header ("content-type: text/xml");
    $this->array = $array;
    $this->root_name = $root_name;
    $this->charset = $charset;

    if (is_array($array) && count($array) > 0) {
        $this->struct_xml($array);

    } else {
        $this->xml .= "no data";
    }
}

public function struct_xml($array)
{
    foreach ($array as $k => $v) {
        if (is_array($v)) {
            $tag = ereg_replace('^[0-9]{1,}', 'item', $k); // replace numeric key in array to 'data'
            $this->xml .= "<$tag>";
            $this->struct_xml($v);
            $this->xml .= "</$tag>";
        } else {
            $tag = ereg_replace('^[0-9]{1,}', 'item', $k); // replace numeric key in array to 'data'
            $this->xml .= "<$tag><![CDATA[$v]]></$tag>";
        }
    }
}

public function get_xml()
{

    $header = "<?xml version=\"1.0\" encoding=\"" . $this->charset . "\"?><" . $this->root_name . ">";
    $footer = "</" . $this->root_name . ">";

    return $header . $this->xml . $footer;
}
}

Espero que ajude a todos.

Bharat Chodvadiya
fonte
0

// Structered array for XML convertion.
$data_array = array(
  array(
    '#xml_tag' => 'a',
    '#xml_value' => '',
    '#tag_attributes' => array(
      array(
        'name' => 'a_attr_name',
        'value' => 'a_attr_value',
      ),
    ),
    '#subnode' => array(
      array(
        '#xml_tag' => 'aa',
        '#xml_value' => 'aa_value',
        '#tag_attributes' => array(
          array(
            'name' => 'aa_attr_name',
            'value' => 'aa_attr_value',
          ),
        ),
        '#subnode' => FALSE,
      ),
    ),
  ),
  array(
    '#xml_tag' => 'b',
    '#xml_value' => 'b_value',
    '#tag_attributes' => FALSE,
    '#subnode' => FALSE,
  ),
  array(
    '#xml_tag' => 'c',
    '#xml_value' => 'c_value',
    '#tag_attributes' => array(
      array(
        'name' => 'c_attr_name',
        'value' => 'c_attr_value',
      ),
      array(
        'name' => 'c_attr_name_1',
        'value' => 'c_attr_value_1',
      ),
    ),
    '#subnode' => array(
      array(
        '#xml_tag' => 'ca',  
        '#xml_value' => 'ca_value',
        '#tag_attributes' => FALSE,
        '#subnode' => array(
          array(
            '#xml_tag' => 'caa',
            '#xml_value' => 'caa_value',
            '#tag_attributes' => array(
              array(
                'name' => 'caa_attr_name',
                'value' => 'caa_attr_value',
              ),
            ),
            '#subnode' => FALSE,
          ),
        ),
      ),
    ),
  ),
);


// creating object of SimpleXMLElement
$xml_object = new SimpleXMLElement('<?xml version=\"1.0\"?><student_info></student_info>');


// function call to convert array to xml
array_to_xml($data_array, $xml_object);

// saving generated xml file
$xml_object->asXML('/tmp/test.xml');

/**
 * Converts an structured PHP array to XML.
 *
 * @param Array $data_array
 *   The array data for converting into XML.
 * @param Object $xml_object
 *   The SimpleXMLElement Object
 *
 * @see https://gist.github.com/drupalista-br/9230016
 * 
 */
function array_to_xml($data_array, &$xml_object) {
  foreach($data_array as $node) {
    $subnode = $xml_object->addChild($node['#xml_tag'], $node['#xml_value']);

    if ($node['#tag_attributes']) {
      foreach ($node['#tag_attributes'] as $tag_attributes) {
        $subnode->addAttribute($tag_attributes['name'], $tag_attributes['value']); 
      }
    }

    if ($node['#subnode']) {
      array_to_xml($node['#subnode'], $subnode);
    }
  }
}
Francisco Luz
fonte