简体   繁体   English

如何将XML转化为PHP中的数组?

[英]How to convert XML into array in PHP?

I want to convert below XML to PHP array.我想将下面的 XML 转换为 PHP 数组。 Any suggestions on how I can do this?关于我如何做到这一点有什么建议吗?

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

easy!简单的!

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

Another option is the SimpleXML extension (I believe it comes standard with most php installs.)另一种选择是 SimpleXML 扩展(我相信它是大多数 php 安装的标准配置。)

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

The syntax looks something like this for your example对于您的示例,语法看起来像这样

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

Converting an XML string ( $buffer ) into a simplified array ignoring attributes and grouping child-elements with the same names:将 XML 字符串 ( $buffer ) 转换为简化数组,忽略属性并将具有相同名称的子元素分组:

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

Result:结果:

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

                )

        )

)

If you also want to have the attributes, they are available via JSON encoding/decoding of SimpleXMLElement.如果您还想拥有这些属性,可以通过 SimpleXMLElement 的 JSON 编码/解码获得它们。 This is often the most easy quick'n'dirty solution:这通常是最简单的快速解决方案:

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

Result:结果:

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
                                        )

                                )

                        )

                )

        )

)

Take note that all these methods only work in the namespace of the XML document.请注意,所有这些方法仅适用于 XML 文档的命名空间。

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

The method used in the accepted answer drop attributes when encountering child elements with only a text node.当遇到只有一个文本节点的子元素时,在接受的答案 drop 属性中使用的方法。 For example:例如:

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

My solution (and I wish I could give credit here because I'm sure I adapted this from something):我的解决方案(我希望我能在这里给予信任,因为我确信我从某些东西中改编了这个):

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
                                )

                        )

                )

        )

)

See https://github.com/gaarf/XML-string-to-PHP-array/blob/master/xmlstr_to_array.phphttps://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;
}

Surprised no one mentioned xml_parse_into_struct :惊讶没有人提到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);

XML To Array XML 到阵列

More Details Visit https://github.com/sapankumarmohanty/lamp/blob/master/Crate-XML-2-Array更多详情请访问https://github.com/sapankumarmohanty/lamp/blob/master/Crate-XML-2-Array

//Convert XML to array and SOAP XML to array //将XML转换为数组,SOAP XML转换为数组

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

I liked this question and some answers was helpful to me, but i need to convert the xml to one domination array, so i will post my solution maybe someone need it later:我喜欢这个问题,一些答案对我很有帮助,但我需要将 xml 转换为一个支配数组,所以我会发布我的解决方案,也许以后有人需要它:

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

Two lines of code ( https://www.php.net/manual/en/book.simplexml.php#113485 )两行代码( https://www.php.net/manual/en/book.simplexml.php#113485

$xml = new SimpleXMLElement("<your><xml><string>ok</string></xml></your>");
$array = (array)$xml;

I know I'm 1 billion years late, but I had the same problem as you and needed a more complex solution, so here is a function ( xml_decode() ) I made to convert SimpleXMLElements into PHP arrays without losing attributes and with arguments for a more customizable use. I know I'm 1 billion years late, but I had the same problem as you and needed a more complex solution, so here is a function ( xml_decode() ) I made to convert SimpleXMLElements into PHP arrays without losing attributes and with arguments for更可定制的用途。

The val() function is meant for you to customize how element values shall be treated - in case you want to transform <elem>true</elem> into true instead of "true" for example. val() function 旨在让您自定义如何处理元素值 - 例如,如果您想将<elem>true</elem>转换为true而不是"true"

Disclaimer: I know it is easier to just use the PHP SimpleXML extension, but I needed to transform lots of XML files into JSON files for a big change in a project of mine.免责声明:我知道仅使用 PHP SimpleXML 扩展名更容易,但我需要将大量 XML 文件转换为 JSON 文件,以便在我的项目中进行重大更改。 Also, the question is about how to transform XML to PHP arrays, not how to use XML in PHP. Also, the question is about how to transform XML to PHP arrays, not how to use XML in PHP.

<?php

function val($input) {
    return strval($input);
}

/**
 * Transform an SimpleXMLElement into an associative array.
 * 
 * @param SimpleXMLElement $xml The XML element to be decoded.
 * 
 * @param bool $attributes_key If the element attributes should be grouped into a single element.
 * 
 * Example: <elem foo="true" bar="false" />
 * 
 * If true, xml_decode() will output
 * array("attributes" => array("foo" => "true", "bar" => "false"))
 * 
 * If false, xml_decode() will output
 * array("foo" => "true", "bar" => "false")
 * 
 * @param bool $reduce If unecessary keys created due to XML structure should be eliminated.
 * 
 * Example: <fruits><fruit>apple</fruit><fruit>banana</fruit></fruits>
 * 
 * If true, xml_decode() will output the element as
 * array("fruits" => array(0 => "apple", 1 => "banana"))
 * 
 * If false, xml_decode() will output the element as
 * array("fruits" => array("fruit" => array(0 => "apple", 1 => "banana")))
 * 
 * @param array $always_array List of which childs should be treated aways as an array.
 * 
 * Example: <fruits><fruit>apple</fruit></fruits>
 * 
 * If array("fruit") is passed as $aways_array, xml_decode() will output the element as
 * array("fruits" => array("fruit" => array(0 => "apple")))
 * 
 * If not, xml_decode() will output the element as
 * array("fruits" => array("fruit" => "apple"))
 * 
 * @param array $value_keys List of custom element's value names. This argument is only
 * used when values need to passed as elements because of attributes or other reasons.
 * 
 * The default value key name is "value".
 * 
 * Example: <fruits><fruit id="123">apple</fruit></fruits>
 * 
 * If array("fruit" => "name) is passed as $value_keys, xml_decode() will output the element as
 * array("fruits" => array("fruit" => array("attributes" => array("id" => "123"), "name" => "apple")))
 * 
 * If not, xml_decode() will output the element as
 * array("fruits" => array("fruit" => array("attributes" => array("id" => "123"), "value" => "apple")))
 */
function xml_decode(SimpleXMLElement $xml, bool $attributes_key = true, bool $reduce = true,
    array $always_array = array(), array $value_keys = array()): string|array {

    // Inicialize the array.
    $arr = array();

    // XML tag name.
    $xml_name = $xml->getName();

    // Turn attributes into elements.
    foreach ($xml->attributes() as $key => $value) {
        // Use a key for attributes if $attributes_key argument is true.
        if ($attributes_key) {
            $arr['attributes'][val($key)] = val($value);
        } else {
            $arr[val($key)] = val($value);
        }
    }

    // Count children.
    $children_count = $xml->children()->count();

    // No children? Value will be text.
    if ($children_count == 0) {

        // If attributes were found and turned into elements
        // the value shall be an element.
        if (count($arr) > 0) {
            // If attributes were found previosly.
            $key = $value_keys[$xml_name] ?? $value_keys['*'] ?? "value";
            $arr[$key] = val($xml);
        // Else, no need for an array.
        } else {
            $arr = val($xml);
        }

    // Children? Loop continues.
    } else {

        // Defines if there are unecessary array keys - due to the XML structure - to be cut.
        // Example: <fruits><fruit /><fruit /><fruits />
        // could be turned into arr['fruits'][0] and arr['fruits'][1] instead of
        // arr['fruits']['fruit'][0] and arr['fruits']['fruit'][1] for a
        // cleaner organization.
        $children_names = array();
        foreach ($xml->children() as $child) {
            $child_name = $child->getName();
            in_array($child_name, $children_names) or $children_names[] = $child_name;
        }
        $reducible = empty($arr) && count($children_names) === 1;

        foreach ($xml->children() as $child) {

            // Child's name shall be the element key.
            $name = $child->getName();
            
            // Children with the same name will be turned into a list.
            // Example: $arr['repeating-child'][...] = $value;
            if ($xml->$name->count() > 1 || in_array($name, $always_array)) {

                // Reduction, if possible and requested by the $reduce argument.
                if ($reduce && $reducible) {
                    $arr[] = xml_decode($child, $attributes_key, $reduce, $always_array, $value_keys);
                } else {
                    $arr[$name][] = xml_decode($child, $attributes_key, $reduce, $always_array, $value_keys);
                }

            // Normal children will be normally decoded.
            // Example: $arr['no-repeating-child] = $value;
            } else {
                
                $arr[$name] = xml_decode($child, $attributes_key, $reduce, $always_array, $value_keys);

            }
        }
    }

    return $arr;

}

Resuming all the documentation and comments, the function transforms attributes and elements values into simple array elements and uses a loop with itself to process elements which contain children.恢复所有文档和注释,function 将属性和元素值转换为简单的数组元素,并使用自身的循环来处理包含子元素的元素。

The arguments allow you to: arguments 允许您:

  • Group attributes into separate keys;将属性分组到单独的键中;
  • Cut unecessary keys generated due to the XML structure conversion (Example: fruits->fruit to $arr['fruits']['fruit'][n] );剪切由于 XML 结构转换而生成的不必要的密钥(例如: fruits->fruit$arr['fruits']['fruit'][n] );
  • Set elements which should aways be treated as lists (because sometimes it will have only one child element but you still need it to be a list);设置应该被视为列表的元素(因为有时它只有一个子元素,但您仍然需要它是一个列表);
  • Set a name for array element keys which will represent an XML element text value - which will be needed when attributes are converted to array elements.为数组元素键设置一个名称,该名称将表示 XML 元素文本值 - 将属性转换为数组元素时需要该名称。

Usage example with your XML elements (I think you already solved it after 11 years, but I'm answering it, so...):您的 XML 元素的使用示例(我认为您已经在 11 年后解决了它,但我正在回答它,所以......):

test.xml测试.xml

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

PHP PHP

$xml = simplexml_load_file("test.xml");
$decode = xml_decode($xml);
echo "<pre>" . print_r($decode,true) . "</pre>";

Output Output

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

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

                                    [value] => 
                                )

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

                                    [value] => 
                                )

                        )

                )

        )

)

 /* Creating an XML file (Optional): Create an XML file which need to convert into the array. test.xml */ <aaaa Version="1.0"> <bbb> <cccc> <dddd Id="id:pass" /> <eeee name="hearaman" age="24" /> </cccc> </bbb> </aaaa> <?php // xml file path $path = "text.xml"; // set your according path for dynamic. // Read entire file into string $xmlfile = file_get_contents($path); // Convert xml string into an object $new = simplexml_load_string($xmlfile); // Convert into json $con = json_encode($new); // Convert into associative array $newArr = json_decode($con, true); print_r($newArr); ?> Output: Result of XML conversion to PHP Array [ 'aaaa' => [ 'bbb' => [ 'cccc' => [ 'dddd' => [ '@value' => '', '@attributes' => [ 'Id' => 'id:pass', ], ], 'eeee' => [ '@value' => '', '@attributes' => [ 'name' => 'hearaman', 'age' => '24', ], ], ], ], '@attributes' => [ 'Version' => '1.0', ], ], ]

If you are getting parse error for unexpected string or getting empty array then use this:如果您遇到意外字符串的解析错误或获得空数组,请使用以下命令:

$xml= preg_replace("/(<\/?)(\w+):([^>]*>)/", "$1$2$3", $xml); // adding this worked for me
$array = json_decode(json_encode((array)simplexml_load_string($xml)),true);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM