Jak przekonwertować tablicę na SimpleXML

Odpowiedzi:

209

krótki:

<?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();

prowadzi do

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

klucze i wartości są zamieniane - można to naprawić array_flip()przed tablicą. array_walk_recursivewymaga PHP 5. możesz array_walkzamiast tego użyć , ale wtedy nie dostaniesz się 'stack' => 'overflow'do xml.

topór.
źródło
53
To nie zadziała, jeśli $ test_array ma „more_another_array” jak „another_array”, ponieważ klucz „another_array” nie jest konwertowany. Dlatego będziesz mieć wiele „<overflow> stos </overflow>”.
understack
11
array_flipNie działa, ponieważ może nie klapki tablicami (podobnie jak another_arrayw głównej tablicy).
Lode
14
Gdzie jest element xml „another_array”? Wszystko jest spłaszczone :(
FMaz008
2
Działa świetnie, gdy dodałem array_flip przed array_walk_recursive. dzięki.
Mike Purcell
12
Głosowanie w dół, ponieważ array_flipdziała tylko wtedy, gdy tablica nie zawiera identycznych wartości.
Martijn
386

Oto kod php 5.2, który przekonwertuje tablicę o dowolnej głębokości do dokumentu 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
                        )   
                )

        )
)

Wygenerowany XML wyglądałby następująco:

<?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>

Fragment kodu 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');

?>

Dokumentacja SimpleXMLElement::asXMLużyta w tym fragmencie

Hanmant
źródło
40
To, IMO, jest znacznie lepszym rozwiązaniem niż przyjęta odpowiedź. Ma to jednak takie ograniczenie, że przy tablicach z kluczami numerycznymi generuje zniekształcony XML. <0> <1> <2> nie są prawidłowymi nazwami węzłów.
KOGI
2
Dzieje się tak jednak, jeśli twoja tablica z kluczami numerycznymi zawiera tylko inną tablicę, która nie jest numerowana, nie będzie.
Bryan Petty
15
@KOGI Zmodyfikowałem odpowiedź Hanmanta. Teraz obsługuje wielopoziomowe tablice. pastebin.com/pYuXQWee
Mifas
1
W tym przykładzie jawnie ucieka się do znaków specjalnych w danych tekstowych elementu za pomocą htmlspecialchars, ale SimpleXMLElement :: addChild tłumaczy znaki specjalne xml na ich jednostki char automatycznie, więc htmlspecialchars można pominąć. Co ciekawe, wydaje się, że nie powoduje to podwójnie uciekających danych.
mbaynton,
3
@Alex, twój Edit # 5 powoduje, że przykład się nie powiedzie. Wstawia <element $ x> przed każdym rekordem <student>, dzięki czemu wyjście XML nie jest zgodne z zamierzeniami autora. Może podaj przykład problemu, który próbujesz rozwiązać, a my możemy znaleźć inne rozwiązanie dla obu przypadków. Zajęło mi to chwilę, zanim zdałem sobie sprawę, że kod autora został zmodyfikowany.
Nicholas Blasgen
124

Podane tutaj odpowiedzi konwertują tylko tablicę na XML z węzłami, nie można ustawić atrybutów. Napisałem funkcję php, która pozwala przekonwertować tablicę na php, a także ustawić atrybuty dla poszczególnych węzłów w xml. Minusem jest to, że musisz zbudować tablicę w określony sposób z kilkoma konwencjami (tylko jeśli chcesz użyć atrybutów)

Poniższy przykład pozwoli ci również ustawić atrybuty w XML.

Źródło można znaleźć tutaj: 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
źródło
9
Dziwi mnie, że nikt na to nie zareagował. Ta klasa jest naprawdę przydatna, ponieważ robi coś przeciwnego do tego, co wygeneruje simpleXMLElement. Daje to możliwość korzystania z SimpleXMLElement na dwa sposoby.
FMaz008,
4
Oznaczę to jako odpowiedź zamiast aktualnej. Obecna odpowiedź nie buduje tablic rekurencyjnych
Oleksandr IY
2
Niezła klasa. Zmieniłem wiersz 128 if(!is_array($arr)) {na, if(!is_array($arr) && $arr !== '') {aby nie dołączał nowego węzła tekstowego dla pustych ciągów, a zatem zachowuje skrócony format pustych znaczników, tzn. 'tag'=>''Jest <tag/>zamiast<tag></tag>
użytkownik1433150
To najlepsza jak dotąd odpowiedź. Ma to również prawidłową strukturę wielu elementów z tym samym kluczem: 1. to klucz nazwy węzła, a następnie zawiera tablicę z kluczami numerycznymi. (przeciwieństwo odpowiedzi Hanmanta)
Wasil Popow
1
Znaleziono github od autora @Legionar github.com/digitickets/lalit/blob/master/src/Array2XML.php
Daryl Teo
57

Znalazłem wszystkie odpowiedzi, aby użyć zbyt dużej ilości kodu. Oto prosty sposób:

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

Następnie wystarczy wysłać tablicę do funkcji, która korzysta z rekurencji, więc będzie obsługiwać tablicę wielowymiarową:

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

Teraz $ xml zawiera piękny obiekt XML oparty na tablicy dokładnie tak, jak go napisałeś.

print $xml->asXML();
Francis Lewis
źródło
9
Najbardziej podoba mi się to rozwiązanie. Chociaż byłoby miło, aby dodać test na klawiszach numerycznych, takich jak: if ( is_numeric( $key ) ) $key = "numeric_$key"; .
wout
@wout Good catch. Dodany. Zrobiłem int cast sprawdzanie zamiast is_numeric, ponieważ is_numeric może dać pewne, choć technicznie oczekiwane, wyniki, które naprawdę by cię zrzuciły.
Francis Lewis,
Korzystam z tej funkcji, ale zmieniłem $xml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8" ?><rootTag/>');na prawidłowe kodowanie UTF-8.
Daantje
I jak to rozwiązanie najbardziej jak dobrze, proste prawda :-) Jedna uwaga: Możesz chcieć zmienić $object->addChild($key, $value);się $object->addChild($key, htmlspecialchars($value));, aby zapobiec jego braku, gdy wartość $ value zawiera znaki takie jak „i”, że potrzebują XML kodowania.
leo
38
<? php
funkcja array_to_xml (tablica $ arr, SimpleXMLElement $ xml)
{
    foreach ($ arr as $ k => $ v) {
        is_array ($ v)
            ? array_to_xml ($ v, $ xml-> addChild ($ k))
            : $ xml-> addChild ($ k, $ v);
    }
    zwróć $ xml;
}

$ test_array = array (
    „bla” => „blub”,
    „foo” => „bar”,
    'another_array' => tablica (
        „stos” => „przepełnienie”,
    ),
);

echo array_to_xml ($ test_array, nowy SimpleXMLElement ('<root />')) -> asXML ();
onokazu
źródło
1
kończy się to niepowodzeniem, jeśli tablica zawiera tablicę wewnętrzną z indeksami numerycznymi. <0> ... </0> nie jest prawidłowym plikiem XML.
Adriano Varoli Piazza
@AdrianoVaroliPiazza wystarczy dodać coś $k = (is_numeric($k)) ? 'item' : $k;w styluforeach()
AlienWebguy
Jeśli jeden z kluczy w tablicy ma nazwę „body”, nie działa - a ściślej - klucz jest ignorowany i przeglądany. Próbuję dowiedzieć się, dlaczego.
Bambax
@Bambax Jedynym powodem, dla którego mogę wymyślić, jest to, że XML jest później analizowany jako HTML.
Brilliand
16

Z 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();
}
użytkownik492589
źródło
Wygląda jak zwykła kopia z wybranej odpowiedzi, po prostu wprowadzona do funkcji.
phaberest
Dodałbym htmlspecialchars () do części addChild, w ten sposób: $ xml-> addChild ($ key, htmlspecialchars ($ value));
Tyreal
15

Kolejna poprawa:

/**
* 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();
}

Stosowanie:

$this->arrayToXML($array, new SimpleXMLElement('<root/>'), 'child_name_to_replace_numeric_integers');
Syl
źródło
Dziękuję Ci! Twoja funkcja zwraca dokładną treść dowolnej n-wymiarowej tablicy.
besciualex
12

Oto mój wpis, prosty i czysty.

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
źródło
8

W każdym razie ... Wziąłem kod onokazu (dzięki!) I dodałem możliwość powtarzania znaczników w XML, obsługuje również atrybuty, mam nadzieję, że ktoś uzna to za przydatne!

 <?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
źródło
Pomocne może być skomentowanie wprowadzonych zmian, aby kod był bardziej przejrzysty; wciąż miły dodatek
StormeHawke,
To działało dla mnie z WP All Export. Musiałem nieco zmienić część is_numeric: if (is_numeric($k)) { $i = $k + 1; $child = $xml->addChild("_$i"); array_to_xml($v, $child); }
osiągając
4

Korzystam z kilku funkcji, które napisałem jakiś czas temu, aby wygenerować xml do przekazywania tam iz powrotem z PHP i jQuery itp. Ani też nie używam żadnych dodatkowych frameworków, a jedynie generuje ciąg znaków, który może być następnie użyty w SimpleXML (lub innym frameworku ) ...

Jeśli jest to przydatne dla kogokolwiek, użyj go :)

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

Kocham wszystkich :)

Neil English
źródło
4

Chciałem kodu, który weźmie wszystkie elementy wewnątrz tablicy i potraktuje je jako atrybuty, a wszystkie tablice jako podelementy.

Więc na coś takiego

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

Dostałbym coś takiego

<?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>

Aby to osiągnąć, kod znajduje się poniżej, ale należy zachować ostrożność, ponieważ jest rekurencyjny i może spowodować przepełnienie stosu :)

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

Możesz dodać sprawdzanie długości tablicy, aby jakiś element został ustawiony wewnątrz części danych, a nie jako atrybut.

lcornea
źródło
4

W oparciu o wszystko inne tutaj obsługuje indeksy liczbowe + atrybuty poprzez prefiks @i może wstrzykiwać xml do istniejących węzłów:

Kod

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

Stosowanie

// 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

Wynik

<?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>

Bonus: Formatowanie 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
źródło
Zaktualizowana wersja, która powtarza się jako elementy potomne zamiast znaczników numerycznych: github.com/zaus/forms-3rdparty-xpost/blob/…
drzaus
3

Oto funkcja, która załatwiła sprawę:

Po prostu nazwij to czymś takim

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;
        }
    }
mikrofon
źródło
3

Możesz użyć XMLParser , nad którym pracowałem.

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

Spowodowałoby to:

<?xml version="1.0"?>
<root>
    <bla>blub</bla>
    <foo>bar</foo>
    <another_array>
        <stack>overflow</stack>
    </another_array>
</root>
jtrumbull
źródło
3

Znalazłem to rozwiązanie podobne do pierwotnego problemu

<?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();
kaiofior
źródło
3

Większość powyższych odpowiedzi jest poprawna. Jednak wymyśliłem tę odpowiedź, która rozwiązuje problem kompatybilności array_walk_recursive, a także problem klawiszy numerycznych. Przeszedł także wszystkie testy, które wykonałem:

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

Dodałem również klasę testową do tego, co może okazać się przydatne:

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
źródło
3

inne rozwiązanie:

$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);
Gajusz Baltar
źródło
Ma to nieoczekiwany efekt w postaci tworzenia kodu XML w stylu RPC za pomocą metod takich jak methodCall, methodName, skalary i wektory itp. Nie jest to tak naprawdę konwersja tablicy na XML w prostym sensie.
Volomike
3

JEŻELI tablica jest asocjacyjna i poprawnie wpisana, prawdopodobnie łatwiej byłoby ją najpierw przekształcić w xml. Coś jak:

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

Inną drogą byłoby najpierw utworzenie podstawowego xml, na przykład

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

a następnie dla każdej części tablicy użyj czegoś podobnego do mojej pętli tworzenia tekstu i zamiast tego użyj funkcji simplexml „addChild” dla każdego węzła tablicy.

Wypróbuję to później i zaktualizuję ten post w obu wersjach.

Anthony
źródło
Ten fragment, w którym wspomniałem „<array> </array>”, uświadomił mi, że wersja łańcuchowa potrzebuje czegoś podobnego. Zasadniczo tablica musi mieć jeden węzeł na samym zewnątrz. Pozwól mi spać nad wszystkim, od razu będę miał coś, co wyłapie ten początkowy błąd.
Anthony
2

Po prostu edytuj powyższą funkcję, gdy klucz jest numeryczny, dodaj przedrostek „klucz_”

// 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");
               }
          }
     }
}
francja
źródło
1

Możesz użyć poniższej funkcji bezpośrednio w swoim kodzie,

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

}

Wywołaj funkcję z pierwszym argumentem jako tablicą, a drugim argumentem musi być 1, to zostanie zwiększone dla idealnego wcięcia, a trzeci musi być prawdziwy.

na przykład, jeśli zmienną tablicową do konwersji jest $ tablica1, wówczas wywołaniem byłoby, funkcja wywołująca powinna być otoczona <pre>tagiem.

  artoxml ($ tablica 1,1, prawda);   

Sprawdź źródło strony po uruchomieniu pliku, ponieważ symbole <i> nie będą wyświetlane na stronie HTML.

JosephVasantPrakash
źródło
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
źródło
Jest to doskonała opcja do tworzenia xml DOMDocument. Dzięki @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;
}

Ta funkcja zwraca na przykład listę znaczników XML <obj>...</obj> <obj> ... </obj> dla indeksów numerycznych.

Wejście:

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

Wynik:

<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>

To powinno zaspokoić wszystkie typowe potrzeby. Może możesz zmienić trzecią linię na:

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

lub jeśli pracujesz z liczbą mnogą kończącą się na s:

$key = is_string($key) ? $key : preg_replace('/s$/', '', $oldNodeName);
użytkownik2381982
źródło
1

Dzięki FluidXML możesz generować, począwszy od tablicy PHP , XML dla SimpleXML z ... tylko dwoma liniami kodu.

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

Przykładową tablicą może być

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

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

Daniele Orlando
źródło
0

Możesz użyć xmlrpc_encode, aby utworzyć xml z tablicy, jeśli pełny xml nie stanowi problemu. www.php.net/xmlrpc_encode

bądź ostrożny, że utworzony plik XML różni się w przypadku używania kluczy asocjacyjnych i / lub numerycznych

<?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
źródło
Ta funkcja nie jest obsługiwana i w rzeczywistości nie jest dostępna w moich kompilacjach PHP 5.2.16 lub PHP 5.3.5. (zwraca „Błąd krytyczny PHP: Wywołanie niezdefiniowanej funkcji xmlrpc_encode ()”)
danorton
musisz odkomentować następujący wiersz w php.ini: extension = php_xmlrpc.dll
w35l3y
@ w35l3y Sprawdziłem mój ini. Nie zawiera nawet tego rozszerzenia i używam wersji 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
źródło
0

Moja odpowiedź, łącząc odpowiedzi innych. To powinno skorygować brak kompensacji klawiszy numerycznych:

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

array_to_xml()Funkcji zakłada, że matryca składa się z klawiszy numerycznych pierwszej. Jeśli tablica zawiera element początkowy, upuszczasz instrukcje foreach()i $elemz array_to_xml()funkcji i po prostu przekazujesz $xml.

refeyd
źródło
0

Skomentowałbym drugą najczęściej głosowaną odpowiedź, ponieważ nie zachowuje ona struktury i generuje zły xml, jeśli istnieją wewnętrznie indeksowane tablice liczbowe.

Na tej podstawie opracowałem własną wersję, ponieważ potrzebowałem prostego konwertera między json i xml, niezależnie od struktury danych. Moja wersja zachowuje kluczowe informacje liczbowe i strukturę oryginalnej tablicy. Tworzy elementy dla wartości indeksowanych numerycznie poprzez zawijanie wartości do elementów o nazwach wartości z atrybutem klucz zawierającym klucz numeryczny.

Na przykład

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

konwertuje na

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

Moja wersja array_to_xml -funkcji (mam nadzieję, że komuś to pomoże :)

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
źródło
0

Cała struktura XML jest zdefiniowana w $ 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();
    }
}
as
źródło
0

Jeśli pracujesz w Magento i masz tego typu tablicę asocjacyjną

$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'
    ),
);

najlepiej jest przekonwertować tablicę asocjacyjną na format xml. Użyj tego kodu w pliku kontrolera.

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

Mam nadzieję, że to pomoże wszystkim.

Bharat Chodvadiya
źródło
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
źródło