【问题标题】:XML into Associative Array using PHP使用 PHP 将 XML 转换为关联数组
【发布时间】:2011-09-25 21:38:57
【问题描述】:

任何人都可以帮助将数据从 XML 文档转换为关联数组吗?鉴于 XML 结构有点像 3D,而数组更像是 2D 结构,我遇到了问题(请原谅我在整个过程中缺乏正确的术语)。 XML 元素具有属性、子元素和孙子元素(但我从不知道他们的名字),所以我想我会尝试让数组中的键成为每个子/属性名称的串联,并且值等于,嗯,价值。问题是我需要属性名称和值作为连接数组键的一部分以使其唯一...

例如:

<Computer id="1">   
    <OS>
        <Name>Linux</Name>
        <Age>Older than me</Age>
    </OS>
</Computer>
<Computer id="2">
    <OS>
        <Name>Windows</Name>
        <Age>Not so much</Age>
    </OS>
</Computer>

理想情况下应该给出:

[Computer-id-1-OS-Name] = 'Linux'
[Computer-id-1-OS-Age] = 'Older than me'
[Computer-id-2-OS-Name] = 'Windows'
[Computer-id-2-OS-Age] = 'Not so much'

但是我得到了这个结果:

[Computer-id] = '1'
[Computer-OS-Name] = 'Linux'
[Computer-OS-Age] = 'Older than me'
[Computer-id] = '2'
[Computer-OS-Name] = 'Windows'
[Computer-OS-Age] = 'Not so much'

因此 [Computer-id] 键不是唯一的。我正在使用递归函数来读取值,但我不知道如何将属性名称和属性值获取到从属键的名称中......(顺便说一下,这样做是有充分理由的看似不合逻辑的任务!) 任何帮助将不胜感激...

这是在将 XML 数据读入多维数组后“展平”该数据的函数。我不确定我是否以正确的方式进行此操作!

function flattenArray ($array, $baseName = NULL)
{
    reset($array);
    while (list ($key, $value) = each($array)) {
        $outKey = $key . "-";
        if (is_array($value)) {
            flattenArray($value, $baseName . $outKey);
        } else {
            $finalKey = $baseName . rtrim($outKey, '-');
            $finalValue = $value;
            echo "$finalKey = $finalValue\n";
        }
    }
}

【问题讨论】:

  • 你能贴出给出错误输出的代码吗?
  • 使用 XML 库会有所帮助。 php.net/manual/en/refs.xml.php
  • 您能解释一下您为什么要这样做吗?为什么不能使用 DOM 或 SimpleXml 提供的树结构?

标签: php xml arrays


【解决方案1】:

这对我很有效,而且很简单。

$ob = simplexml_load_file('test.xml');
$json = json_encode($ob);
$array = json_decode($json, true);

【讨论】:

【解决方案2】:

一个例子可能是:

$dom = new DOMDocument;
$dom->loadXML(
    '<root>
        <Computer id="1">   
            <OS>
                <Name>Linux</Name>
                <Age>Older than me</Age>
            </OS>
        </Computer>

        <Computer id="2">
            <OS>
                <Name>Windows</Name>
                <Age>Not so much</Age>
            </OS>
        </Computer>
    </root>'
);

$xpath = new DOMXPath($dom);
$result = array();

foreach ($xpath->query('//*[count(*) = 0]') as $node) {
    $path = array();
    $val = $node->nodeValue;

    do {
        if ($node->hasAttributes()) {
            foreach ($node->attributes as $attribute) {
                $path[] = sprintf('%s[%s]', $attribute->nodeName, $attribute->nodeValue);
            }
        }
        $path[] = $node->nodeName;
    }
    while ($node = $node->parentNode);

    $result[implode('/', array_reverse($path))] = $val;
}

print_r($result);

输出:

Array
(
    [#document/root/Computer/id[1]/OS/Name] => Linux
    [#document/root/Computer/id[1]/OS/Age] => Older than me
    [#document/root/Computer/id[2]/OS/Name] => Windows
    [#document/root/Computer/id[2]/OS/Age] => Not so much
)

这并不完全是您想要的,但它是一个开始,可以轻松调整以提供不同的结果。

【讨论】:

    【解决方案3】:

    这是我生成关联数组的函数,派生自

    Recursive cast from SimpleXMLObject to Array

    function xml2assoc($obj, &$arr) {
      $children = $obj->children();
      foreach ( $children as $elementName => $node ) {
    
        if (!isset($arr[$elementName])) {
          $arr[$elementName] = array();
        }
        $temp = array();
        $attributes = $node->attributes();
        foreach ( $attributes as $attributeName => $attributeValue ) {
          $attribName = strtolower(trim((string) $attributeName));
          $attribVal = trim((string) $attributeValue);
          $temp[$attribName] = $attribVal;
        }
        $text = (string) $node;
        $text = trim($text);
        if (strlen($text) > 0) {
          $temp ['text='] = $text;
        }
        $arr[$elementName][] = $temp;
        $nextIdx = count($arr[$elementName]);
        xml2assoc($node, $arr[$elementName][$nextIdx - 1]);
      }
      return;
    }
    
    $xml = '<xml>
    <ToUserName><![CDATA[toUser]]></ToUserName>
    <FromUserName><![CDATA[fromUser]]></FromUserName>
    <CreateTime>12345678</CreateTime>
    <MsgType><![CDATA[news]]></MsgType>
    <ArticleCount>2</ArticleCount>
    <Articles>
    <item>
    <Title><![CDATA[title1]]></Title> 
    <Description><![CDATA[description1]]></Description>
    <PicUrl><![CDATA[picurl]]></PicUrl>
    <Url><![CDATA[url]]></Url>
    </item>
    <item>
    <Title><![CDATA[title]]></Title>
    <Description><![CDATA[description]]></Description>
    <PicUrl><![CDATA[picurl]]></PicUrl>
    <Url><![CDATA[url]]></Url>
    </item>
    </Articles>
    </xml> ';
    
    $dom = new SimpleXMLElement($xml);
    
    $arr = array();
    
    xml2assoc($dom, $arr);
    print_r($arr);
    

    生成的数组:

    Array
    (
        [ToUserName] => Array
            (
                [0] => Array
                    (
                        [text=] => toUser
                    )
    
            )
    
        [FromUserName] => Array
            (
                [0] => Array
                    (
                        [text=] => fromUser
                    )
    
            )
    
        [CreateTime] => Array
            (
                [0] => Array
                    (
                        [text=] => 12345678
                    )
    
            )
    
        [MsgType] => Array
            (
                [0] => Array
                    (
                        [text=] => news
                    )
    
            )
    
        [ArticleCount] => Array
            (
                [0] => Array
                    (
                        [text=] => 2
                    )
    
            )
    
        [Articles] => Array
            (
                [0] => Array
                    (
                        [item] => Array
                            (
                                [0] => Array
                                    (
                                        [Title] => Array
                                            (
                                                [0] => Array
                                                    (
                                                        [text=] => title1
                                                    )
    
                                            )
    
                                        [Description] => Array
                                            (
                                                [0] => Array
                                                    (
                                                        [text=] => description1
                                                    )
    
                                            )
    
                                        [PicUrl] => Array
                                            (
                                                [0] => Array
                                                    (
                                                        [text=] => picurl
                                                    )
    
                                            )
    
                                        [Url] => Array
                                            (
                                                [0] => Array
                                                    (
                                                        [text=] => url
                                                    )
    
                                            )
    
                                    )
    
                                [1] => Array
                                    (
                                        [Title] => Array
                                            (
                                                [0] => Array
                                                    (
                                                        [text=] => title
                                                    )
    
                                            )
    
                                        [Description] => Array
                                            (
                                                [0] => Array
                                                    (
                                                        [text=] => description
                                                    )
    
                                            )
    
                                        [PicUrl] => Array
                                            (
                                                [0] => Array
                                                    (
                                                        [text=] => picurl
                                                    )
    
                                            )
    
                                        [Url] => Array
                                            (
                                                [0] => Array
                                                    (
                                                        [text=] => url
                                                    )
    
                                            )
    
                                    )
    
                            )
    
                    )
    
            )
    
    )
    

    【讨论】:

      【解决方案4】:

      将 xml 读入一个 DOM 对象,循环遍历它,将结果保存到一个数组中。就这么简单吗?

      【讨论】:

      • 相对于该页面上的其他帖子而言,这是低价值的。看起来更像是评论/提示而不是答案。
      【解决方案5】:

      简单的数组可能是二维的,但多维数组可以很容易地复制像 xml 这样的层次结构。

      Google 'associative multi-dimensional array php' 获取更多信息。

      然而,正如已经说过的,PHP 有一个内置的 xml 解析器,因此无论如何都不需要在数组中重新创建 xml,更不用说将其展平为一个简单的数组了。

      在 PHP 中,您的数组结构应如下所示:

      $computers["computers"]["computer-1"]["OS"]["Name"] = "Linux";
      $computers["computers"]["computer-1"]["OS"]["Age"] = "Older Than Me";
      
      $computers["computers"]["computer-2"]["OS"]["Name"] = "Windows";
      $computers["computers"]["computer-2"]["OS"]["Age"] = "Not so much";
      

      等等……

      【讨论】:

        【解决方案6】:

        我修改了 user655000 的答案,使其更接近 json_decode(json_encode($dom)) 格式化/返回数据的方式。我还将初始数组参数设为可选,因为无论如何它都会为空。

        我无法使用 decode(encode) 方法,因为 PHP 的 encode 函数中似乎存在错误,这导致 decode() 在某些示例数据上返回 null。我尝试了一个更安全的编码函数版本,但内存不足。

        存在细微的行为差异。如果存在 nodeText,则 decode(encode) 方法将丢弃任何属性(也可能是子属性)。我的方法不行。

        function readxml($xmlfile, $recursive = false){
            $ob = simplexml_load_file($xmlfile);
            //primary method
            $json = json_encode($ob);
            $array = json_decode($json, true);
            if(is_null($array)){//backup method
                $array = xml2assoc($ob);
            }
            return $array;
        }
        
        function xml2assoc($obj, &$arr = null) {
            $children = $obj->children();//->count(); 
            $nodes = [];
            foreach ( $children as $elementName => $node ) {
                if(!isset($nodes[$elementName])){
                    $nodes[$elementName] = 0;
                }
                $nodes[$elementName]++;
            }
            $indexes = [];
        
            if($arr === null){
                $arr = [];
            }
            foreach ( $children as $elementName => $node ) {
                $temp = array();
                $grandchildren = $node->children()->count();
                
                //attributes        
                $attributes = $node->attributes();
                foreach ( $attributes as $attributeName => $attributeValue ) {
                    $attribName = trim((string) $attributeName);
                    $attribVal = trim((string) $attributeValue);
                    $temp["@attributes"][$attribName] = $attribVal;
                }
                
                //text      
                $text = (string) $node;
                $text = trim($text);
                if (strlen($text) > 0) {
                    if(count($temp) == 0 && $grandchildren == 0){
                        $temp = $text;//discard the children/attribute data since there aren't any
                    } else {
                        $temp["NodeText"] = $text;//retain the children/attributes
                    }
                }       
                
                //grandchildren
                if($temp || is_string($temp) || $grandchildren > 0 ){
                    if( $nodes[$elementName] == 1 ){//only one of it's kind
                        $arr[$elementName] = $temp;
                        xml2assoc($node, $arr[$elementName]);
                    } else {//has multiple nodes of the same kind
                        if(isset($indexes[$elementName])){
                            $indexes[$elementName]++;
                        } else {
                            $indexes[$elementName] = 0;
                        }
                        $index = $indexes[$elementName];
                        $arr[$elementName][$index] = $temp;
                        xml2assoc($node, $arr[$elementName][$index]);
                    }
                }
            }
            return $arr;
        }
        

        【讨论】:

          猜你喜欢
          • 2010-12-04
          • 1970-01-01
          • 2011-05-08
          • 2011-05-19
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多