Php dizi xml dönüştürmek nasıl?


167

Aşağıdaki XML PHP dizine dönüştürmek istiyorum. Bunu nasıl yapabileceğime dair herhangi bir öneriniz var mı?

<aaaa Version="1.0">
   <bbb>
     <cccc>
       <dddd Id="id:pass" />
       <eeee name="hearaman" age="24" />
     </cccc>
   </bbb>
</aaaa>

3
ayrıca, bu soru diğer sorunuzdan nasıl farklıdır? stackoverflow.com/questions/6578084/…
Gordon

3
Birkaç soru, kendi sorularına yanlış cevap kabul eden bir OP kadar iğrenç.
John

Yanıtlar:


128

Başka bir seçenek SimpleXML uzantısıdır (çoğu php yüklemesinde standart olarak geldiğine inanıyorum.)

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

Sözdizimi örneğiniz için şuna benzer

$xml = new SimpleXMLElement($xmlString);
echo $xml->bbb->cccc->dddd['Id'];
echo $xml->bbb->cccc->eeee['name'];
// or...........
foreach ($xml->bbb->cccc as $element) {
  foreach($element as $key => $val) {
   echo "{$key}: {$val}";
  }
}

82
Adil olmak gerekirse, bu bir dizi nasıl elde edileceği sorusuna tam olarak cevap vermez.
sieppl

Bu xml ayrıştırılırken SimpleXML emmek: amazon.in/rss/bestsellers/shoes?tag=dealslama-21 print_r bile nesnenin aslında içerdiğini söylemez.
ravisoni

var_dump kullanın, xml yapısını nesnenin içindeki anahtarlar olarak görürsünüz.
Magus

3
[CDATA[TEXT]]Bazı elementlerin içinde bazı var ve onlar bununla ayrışmıyorlar. Bir olarak ayrıştırır SimpleXMLElement Object. Bunun için bir çözüm var mı?
masterFly

Bu soruya cevap vermiyor
Bilaal Rashid

435

kolay!

$xml = simplexml_load_string($xmlstring, "SimpleXMLElement", LIBXML_NOCDATA);
$json = json_encode($xml);
$array = json_decode($json,TRUE);

20
CDATA bölümlerinde sorun yaşayabilirsiniz (geri dönüş her zaman null olur). Çözüm olarak $ xml = simplexml_load_string ($ xmlstring, null, LIBXML_NOCDATA); $ json = json_encode ($ xml); $ array = json_decode ($ json, TRUE); (bkz. stackoverflow.com/a/2970701/413531 ) // e lanet .. bir yoruma yeni satır eklemenin bir yolu var mı?
Hirnhamster

4
Tam olarak aynı şeyi yapıyoruz ama simplexml_load_file ile çalışıyoruz. Teşekkürler
Thermech

2
İkinci parametre (TRUE) ne içindir?
Mansour Fahad

3
@MansourFahad json_decode içinde isteğe bağlı ikinci parametreyi TRUE(normalde varsayılan olarak FALSE) JSON girişini ilişkilendirilebilir bir diziye dönüştürmek için kullanabilirsiniz.
Jake Bathman

16
@Ismael Miguel çok fazla kod mu? Tüm bu işlevleri bir satıra koymanız daha az kod kullandığınız anlamına gelmez. Daha kompakt görünebilir, ancak okunabilirlik pahasına gelir.
Jage

44

XML dizesini ( $buffer), öznitelikleri yok sayarak ve alt öğeleri aynı adlarla gruplayarak basitleştirilmiş bir diziye dönüştürme:

function XML2Array(SimpleXMLElement $parent)
{
    $array = array();

    foreach ($parent as $name => $element) {
        ($node = & $array[$name])
            && (1 === count($node) ? $node = array($node) : 1)
            && $node = & $node[];

        $node = $element->count() ? XML2Array($element) : trim($element);
    }

    return $array;
}

$xml   = simplexml_load_string($buffer);
$array = XML2Array($xml);
$array = array($xml->getName() => $array);

Sonuç:

Array
(
    [aaaa] => Array
        (
            [bbb] => Array
                (
                    [cccc] => Array
                        (
                            [dddd] => 
                            [eeee] => 
                        )

                )

        )

)

Ayrıca özniteliklere sahip olmak istiyorsanız, bunlar SimpleXMLElement öğesinin JSON kodlaması / kod çözme yoluyla kullanılabilir. Bu genellikle en kolay quick'n'dirty çözümdür:

$xml   = simplexml_load_string($buffer);
$array = json_decode(json_encode((array) $xml), true);
$array = array($xml->getName() => $array);

Sonuç:

Array
(
    [aaaa] => Array
        (
            [@attributes] => Array
                (
                    [Version] => 1.0
                )

            [bbb] => Array
                (
                    [cccc] => Array
                        (
                            [dddd] => Array
                                (
                                    [@attributes] => Array
                                        (
                                            [Id] => id:pass
                                        )

                                )

                            [eeee] => Array
                                (
                                    [@attributes] => Array
                                        (
                                            [name] => hearaman
                                            [age] => 24
                                        )

                                )

                        )

                )

        )

)

Tüm bu yöntemlerin yalnızca XML belgesinin ad alanında çalıştığını unutmayın.



PHP 7'de bu eklemek zorunda: && (is_countable($node) && 1 === count($node) ? $node = array($node) : 1)Ancak sonraki satırda bir hata var: [] operator not supported for strings.
andreshg112

@ andreshg112: Çoğaltılamıyorum (kararlı PHP 5.3.0 - 7.4.0 çalışıyor), davranışlar çağlardan beri değişmedi, lütfen yüzlerce farklı PHP sürümüyle karşılaştırın: 3v4l.org/l4nQN
hakre

belki de benim KML dosyamdan (XML'dir) kaynaklanıyor. Paylaşamıyorum. Zaten ithal ettim ama başka bir şekilde yapmak zorunda kaldım.
andreshg112

muhtemelen XML ad alanlarıyla ilgileniyorsunuzdur. Örnek yalnızca ad alanı olmayan parçalar içindir (veya varsayılan olan, bazen bunu karıştırırım).
hakre

25
$array = json_decode(json_encode((array)simplexml_load_string($xml)),true);

1
Eğer dizi döküm, gerek yoktur json_encodeve json_decode.
Ismael Miguel

11
Teoride, diziye yayın yapmak yeterli olmalıdır. Uygulamada, aynı zamanda nesne olan tüm yaprak düğümlerini de dökmemiz gerekiyor. Saf bir döküm, yaprakları SimpleXML nesneleri olarak bırakır. json_encode, çok fazla çalışmayı tekrar tekrar kaydeder.
Peter Mellett

2
$arrayDeğişkeninizde metin değerleri yoksa , bunun nedeni muhtemelen CDATA olabilir. Bunu çözmek için, ile XML yüklemek: new SimpleXMLElement($xml, LIBXML_NOCDATA).
Jonathan Petitcolas

1
ps. $ xml = str_replace (dizi ('<! [CDATA [', ']]>'), '', $ xml);
user956584

1
Böyle çalışmaz. Bu kod, bunun gibi basit bir XML'i bile dönüştürmezdi <?xml version="1.0" encoding="UTF-8"?><note a="b"><body c="d">Hello!</body></note>. Kodu çalıştırın ve <body> c özelliğinin kaybolduğunu göreceksiniz ! Kötü sürprizler istemiyorsanız lütfen tam kodu buradan kontrol edin github.com/gaarf/XML-string-to-PHP-array/blob/master/… veya aşağıdaki cevabımı aşağıya bakın stackoverflow.com/a/30234924/828366
Francesco Casula

8

Kimse bahsetmedi şaşırttı xml_parse_into_struct:

$simple = "<para><note>simple note</note></para>";
$p = xml_parser_create();
xml_parse_into_struct($p, $simple, $vals, $index);
xml_parser_free($p);
echo "Index array\n";
print_r($index);
echo "\nVals array\n";
print_r($vals);

Bazen xml_parse_into_struct tasarlandığında PHP XML uygulamasını oluşturan geliştiricinin ne düşündüğünü merak ediyorum ...
Anibal Sanchez

7

Bkz. Https://github.com/gaarf/XML-string-to-PHP-array/blob/master/xmlstr_to_array.php

<?php
/**
  * convert xml string to php array - useful to get a serializable value
  *
  * @param string $xmlstr
  * @return array
  *
  * @author Adrien aka Gaarf & contributors
  * @see http://gaarf.info/2009/08/13/xml-string-to-php-array/
*/
function xmlstr_to_array($xmlstr) {
  $doc = new DOMDocument();
  $doc->loadXML($xmlstr);
  $root = $doc->documentElement;
  $output = domnode_to_array($root);
  $output['@root'] = $root->tagName;
  return $output;
}
function domnode_to_array($node) {
  $output = array();
  switch ($node->nodeType) {
    case XML_CDATA_SECTION_NODE:
    case XML_TEXT_NODE:
      $output = trim($node->textContent);
    break;
    case XML_ELEMENT_NODE:
      for ($i=0, $m=$node->childNodes->length; $i<$m; $i++) {
        $child = $node->childNodes->item($i);
        $v = domnode_to_array($child);
        if(isset($child->tagName)) {
          $t = $child->tagName;
          if(!isset($output[$t])) {
            $output[$t] = array();
          }
          $output[$t][] = $v;
        }
        elseif($v || $v === '0') {
          $output = (string) $v;
        }
      }
      if($node->attributes->length && !is_array($output)) { //Has attributes but isn't an array
        $output = array('@content'=>$output); //Change output into an array.
      }
      if(is_array($output)) {
        if($node->attributes->length) {
          $a = array();
          foreach($node->attributes as $attrName => $attrNode) {
            $a[$attrName] = (string) $attrNode->value;
          }
          $output['@attributes'] = $a;
        }
        foreach ($output as $t => $v) {
          if(is_array($v) && count($v)==1 && $t!='@attributes') {
            $output[$t] = $v[0];
          }
        }
      }
    break;
  }
  return $output;
}

7

Yalnızca bir metin düğümü olan alt öğelerle karşılaşıldığında kabul edilen yanıt bırakma özniteliklerinde kullanılan yöntem. Örneğin:

$xml = '<container><element attribute="123">abcd</element></container>';
print_r(json_decode(json_encode(simplexml_load_string($xml, "SimpleXMLElement", LIBXML_NOCDATA)),1));

Array
(
    [element] => abcd
)

Benim çözümüm (ve keşke burada kredi verebilseydim, çünkü bunu bir şeyden uyarladığımdan eminim):

function XMLtoArray($xml) {
    $previous_value = libxml_use_internal_errors(true);
    $dom = new DOMDocument('1.0', 'UTF-8');
    $dom->preserveWhiteSpace = false; 
    $dom->loadXml($xml);
    libxml_use_internal_errors($previous_value);
    if (libxml_get_errors()) {
        return [];
    }
    return DOMtoArray($dom);
}

function DOMtoArray($root) {
    $result = array();

    if ($root->hasAttributes()) {
        $attrs = $root->attributes;
        foreach ($attrs as $attr) {
            $result['@attributes'][$attr->name] = $attr->value;
        }
    }

    if ($root->hasChildNodes()) {
        $children = $root->childNodes;
        if ($children->length == 1) {
            $child = $children->item(0);
            if (in_array($child->nodeType,[XML_TEXT_NODE,XML_CDATA_SECTION_NODE])) {
                $result['_value'] = $child->nodeValue;
                return count($result) == 1
                    ? $result['_value']
                    : $result;
            }

        }
        $groups = array();
        foreach ($children as $child) {
            if (!isset($result[$child->nodeName])) {
                $result[$child->nodeName] = DOMtoArray($child);
            } else {
                if (!isset($groups[$child->nodeName])) {
                    $result[$child->nodeName] = array($result[$child->nodeName]);
                    $groups[$child->nodeName] = 1;
                }
                $result[$child->nodeName][] = DOMtoArray($child);
            }
        }
    }
    return $result;
}

$xml = '
    <aaaa Version="1.0">
       <bbb>
         <cccc>
           <dddd id="123" />
           <eeee name="john" age="24" />
           <ffff type="employee">Supervisor</ffff>
         </cccc>
       </bbb>
    </aaaa>
';
print_r(XMLtoArray($xml));

Array
(
    [aaaa] => Array
        (
            [@attributes] => Array
                (
                    [Version] => 1.0
                )

            [bbb] => Array
                (
                    [cccc] => Array
                        (
                            [dddd] => Array
                                (
                                    [@attributes] => Array
                                        (
                                            [id] => 123
                                        )

                                )

                            [eeee] => Array
                                (
                                    [@attributes] => Array
                                        (
                                            [name] => john
                                            [age] => 24
                                        )

                                )

                            [ffff] => Array
                                (
                                    [@attributes] => Array
                                        (
                                            [type] => employee
                                        )

                                    [_value] => Supervisor
                                )

                        )

                )

        )

)

2

Diziye XML

Daha Fazla Bilgi https://github.com/sapankumarmohanty/lamp/blob/master/Crate-XML-2-Array adresini ziyaret edin

// XML'i diziye, SOAP XML'i diziye dönüştür

function xml2array($contents, $get_attributes = 1, $priority = 'tag')
    {
        if (!$contents) return array();
        if (!function_exists('xml_parser_create')) {
            // print "'xml_parser_create()' function not found!";
            return array();
        }
        // Get the XML parser of PHP - PHP must have this module for the parser to work
        $parser = xml_parser_create('');
        xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, "UTF-8"); // http://minutillo.com/steve/weblog/2004/6/17/php-xml-and-character-encodings-a-tale-of-sadness-rage-and-data-loss
        xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
        xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
        xml_parse_into_struct($parser, trim($contents) , $xml_values);
        xml_parser_free($parser);
        if (!$xml_values) return; //Hmm...
        // Initializations
        $xml_array = array();
        $parents = array();
        $opened_tags = array();
        $arr = array();
        $current = & $xml_array; //Refference
        // Go through the tags.
        $repeated_tag_index = array(); //Multiple tags with same name will be turned into an array
        foreach($xml_values as $data) {
            unset($attributes, $value); //Remove existing values, or there will be trouble
            // This command will extract these variables into the foreach scope
            // tag(string), type(string), level(int), attributes(array).
            extract($data); //We could use the array by itself, but this cooler.
            $result = array();
            $attributes_data = array();
            if (isset($value)) {
                if ($priority == 'tag') $result = $value;
                else $result['value'] = $value; //Put the value in a assoc array if we are in the 'Attribute' mode
            }
            // Set the attributes too.
            if (isset($attributes) and $get_attributes) {
                foreach($attributes as $attr => $val) {                                   
                                    if ( $attr == 'ResStatus' ) {
                                        $current[$attr][] = $val;
                                    }
                    if ($priority == 'tag') $attributes_data[$attr] = $val;
                    else $result['attr'][$attr] = $val; //Set all the attributes in a array called 'attr'
                }
            }
            // See tag status and do the needed.
                        //echo"<br/> Type:".$type;
            if ($type == "open") { //The starting of the tag '<tag>'
                $parent[$level - 1] = & $current;
                if (!is_array($current) or (!in_array($tag, array_keys($current)))) { //Insert New tag
                    $current[$tag] = $result;
                    if ($attributes_data) $current[$tag . '_attr'] = $attributes_data;
                                        //print_r($current[$tag . '_attr']);
                    $repeated_tag_index[$tag . '_' . $level] = 1;
                    $current = & $current[$tag];
                }
                else { //There was another element with the same tag name
                    if (isset($current[$tag][0])) { //If there is a 0th element it is already an array
                        $current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;
                        $repeated_tag_index[$tag . '_' . $level]++;
                    }
                    else { //This section will make the value an array if multiple tags with the same name appear together
                        $current[$tag] = array(
                            $current[$tag],
                            $result
                        ); //This will combine the existing item and the new item together to make an array
                        $repeated_tag_index[$tag . '_' . $level] = 2;
                        if (isset($current[$tag . '_attr'])) { //The attribute of the last(0th) tag must be moved as well
                            $current[$tag]['0_attr'] = $current[$tag . '_attr'];
                            unset($current[$tag . '_attr']);
                        }
                    }
                    $last_item_index = $repeated_tag_index[$tag . '_' . $level] - 1;
                    $current = & $current[$tag][$last_item_index];
                }
            }
            elseif ($type == "complete") { //Tags that ends in 1 line '<tag />'
                // See if the key is already taken.
                if (!isset($current[$tag])) { //New Key
                    $current[$tag] = $result;
                    $repeated_tag_index[$tag . '_' . $level] = 1;
                    if ($priority == 'tag' and $attributes_data) $current[$tag . '_attr'] = $attributes_data;
                }
                else { //If taken, put all things inside a list(array)
                    if (isset($current[$tag][0]) and is_array($current[$tag])) { //If it is already an array...
                        // ...push the new element into that array.
                        $current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;
                        if ($priority == 'tag' and $get_attributes and $attributes_data) {
                            $current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;
                        }
                        $repeated_tag_index[$tag . '_' . $level]++;
                    }
                    else { //If it is not an array...
                        $current[$tag] = array(
                            $current[$tag],
                            $result
                        ); //...Make it an array using using the existing value and the new value
                        $repeated_tag_index[$tag . '_' . $level] = 1;
                        if ($priority == 'tag' and $get_attributes) {
                            if (isset($current[$tag . '_attr'])) { //The attribute of the last(0th) tag must be moved as well
                                $current[$tag]['0_attr'] = $current[$tag . '_attr'];
                                unset($current[$tag . '_attr']);
                            }
                            if ($attributes_data) {
                                $current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;
                            }
                        }
                        $repeated_tag_index[$tag . '_' . $level]++; //0 and 1 index is already taken
                    }
                }
            }
            elseif ($type == 'close') { //End of tag '</tag>'
                $current = & $parent[$level - 1];
            }
        }
        return ($xml_array);
    }
    
    // Let's call the this above function xml2array
    
    xml2array($xmlContent, $get_attributes = 3, $priority = 'tag'); // it will work 100% if not ping me @skype: sapan.mohannty
    
//  Enjoy coding

0

Ben bu soruyu sevdim ve bazı cevaplar benim için yararlı oldu, ama bir egemenlik dizisine xml dönüştürmek gerekiyor, bu yüzden benim çözüm belki birileri daha sonra ihtiyaç duyacağız göndereceğiz:

<?php
$xml = json_decode(json_encode((array)simplexml_load_string($xml)),1);
$finalItem = getChild($xml);
var_dump($finalItem);

function getChild($xml, $finalItem = []){
    foreach($xml as $key=>$value){
        if(!is_array($value)){
            $finalItem[$key] = $value;
        }else{
            $finalItem = getChild($value, $finalItem);
        }
    }
    return $finalItem;
}
?>  
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.