标题:在PHP中使用SPL库中的对象方法进行XML与数组的转换

文章目录
    分类:PHP 标签:PHP基础,PHP SPL

    在PHP中使用SPL库中的对象方法进行XML与数组的转换

    虽说现在很多的服务提供商都会提供 JSON 接口供我们使用,但是,还是有不少的服务依然必须使用 XML 作为接口格式,这就需要我们来对 XML 格式的数据进行解析转换。而 PHP 中并没有像 json_encode() 、 json_decode() 这样的函数能够让我们方便地进行转换,所以在操作 XML 数据时,大家往往都需要自己写代码来实现。


    今天,我们介绍的是使用 SPL 扩展库中的一些对象方法来处理 XML 数据格式的转换。首先,我们定义一个类,就相当于封装一个操作 XML 数据转换的类,方便我们将来使用。如果只是测试效果的话,直接写下面的函数也是可以的。

    class ConvertXml{
        // ....
    }

    XML 转换为 PHP 数组

    class ConvertXml{
        public function xmlToArray(SimpleXMLIterator $xml): array
        {
            $res = [];
    
            for ($xml->rewind(); $xml->valid(); $xml->next()) {
                $a = [];
                if (!array_key_exists($xml->key(), $a)) {
                    $a[$xml->key()] = [];
                }
                if ($xml->hasChildren()) {
                    $a[$xml->key()][] = $this->xmlToArray($xml->current());
                } else {
                    $a[$xml->key()] = (array) $xml->current()->attributes();
                    $a[$xml->key()]['value'] = strval($xml->current());
                }
                $res[] = $a;
            }
    
            return $res;
        }
    
        // .....
    }
    
    $wsdl = 'http://flash.weather.com.cn/wmaps/xml/china.xml';
    
    $xml = new SimpleXMLIterator($wsdl, 0, true);
    $convert = new ConvertXml();
    // var_dump($convert->xmlToArray($xml));
    // array(37) {
    //     [0]=>
    //     array(1) {
    //       ["city"]=>
    //       array(2) {
    //         ["@attributes"]=>
    //         array(9) {
    //           ["quName"]=>
    //           string(9) "黑龙江"
    //           ["pyName"]=>
    //           string(12) "heilongjiang"
    //           ["cityname"]=>
    //           string(9) "哈尔滨"
    //           ["state1"]=>
    //           string(1) "7"
    //           ["state2"]=>
    //           string(1) "3"
    //           ["stateDetailed"]=>
    //           string(15) "小雨转阵雨"
    //           ["tem1"]=>
    //           string(2) "21"
    //           ["tem2"]=>
    //           string(2) "16"
    //           ["windState"]=>
    //           string(21) "南风6-7级转4-5级"
    //         }
    //         ["value"]=>
    //         string(0) ""
    //       }
    //     }
    //     [1]=>
    //     array(1) {
    //       ["city"]=>
    //       array(2) {

    在这里,我们使用的是 SimpleXMLIterator 对象。从名称中就可以看出,它的作用是生成可以遍历的 SimpleXMLElement 对象。第一个参数是格式正确的 XML 文本或者链接地址。第二个参数是一些选项参数,这里我们直接给 0 就可以了。第三个参数则是指明第一个参数是否是链接地址,这里我们给 true 。


    我们在客户端生成了 SimpleXMLIterator 对象,并传递到 xmlToArray() 方法中。这样 SimpleXMLIterator 对象就能让我们遍历各个结点了,接下来的事情就很简单了,我们只需要判断一下结点是否还有子结点,如果有子结点则递归调用当前这个方法。如果没有子结点了,就获取结点的属性和内容。


    这个测试链接是获取天气信息的,返回的内容中每个结点都只有属性没有内容,体现在转换后的数组中就是 value 字段都是空的。

    PHP 数组或对象转换为 XML

    class ConvertXml{
    
        // ......
    
        const UNKNOWN_KEY = 'unknow';
        
        public function arrayToXml(array $a)
        {
            $xml = new SimpleXMLElement('<?xml version="1.0" standalone="yes"?><root></root>');
            $this->phpToXml($a, $xml);
            return $xml->asXML();
        }
        
        protected function phpToXml($value, &$xml)
        {
            $node = $value;
            if (is_object($node)) {
                $node = get_object_vars($node);
            }
            if (is_array($node)) {
                foreach ($node as $k => $v) {
                    if (is_numeric($k)) {
                        $k = 'number' . $k;
                    }
                    if (!is_array($v) && !is_object($v)) {
                        $xml->addChild($k, $v);
                    } else {
                        $newNode = $xml->addChild($k);
                        $this->phpToXml($v, $newNode);
                    }
                }
            } else {
                $xml->addChild(self::UNKNOWN_KEY, $node);
            }
        }
    }
    
    var_dump($convert->arrayToXml($data));
    // string(84454) "<?xml version="1.0" standalone="yes"?>
    // <root><unlikely-outliner><subject><mongo-db><outline><chapter><getting-started><number0>  ...........
    // "

    我们在 arrayToXml() 中,先使用 SimpleXMLElement 对象创建了一个基本的根结点结构。然后使用 phpToXml() 方法来创建所有结点。为什么要拆成两个方法呢?因为 phpToXml() 方法是需要递归调用的,在每次递归的时候我们不需要重新的去创建根结点,只需要在根结点下面使用 addChild() 添加子结点就可以了。


    在 phpToXml() 的代码中,我们还使用了 get_object_vars() 函数。就是当传递进来的数组项内容是对象时,通过这个函数可以获取对象的所有属性。如果将对象看做是一个数组的话,每个属性值就是它的键值对。


    在对每个键值遍历时,我们判断当前的键对应的内容是否是数组或者是对象。如果不是这两种形式的内容的话,就直接将当前的内容添加为当前结点的子结点。如果是数组或对象的话,就继续递归地添加直到数组内容全部遍历完成。


    测试的 $data 内容非常长,大家可以直接通过测试代码的链接去 Github 上查阅。

    总结

    这篇文章的内容是简单的学习了一个 SPL 扩展库中对于 XML 操作的两个对象的使用。通过它们,我们可以方便的转换 XML 数据格式。当然,对于 XML 的格式转换来说,我们还有其它的方法,以后学到了再说!


    测试代码:


    https://github.com/zhangyue0503/dev-blog/blob/master/php/202009/source/在PHP中使用SPL库中的对象方法进行XML与数组的转换.php


    参考文档:


    《PHP7编程实战》

    视频链接

    B站视频地址:https://www.bilibili.com/video/BV1sf4y157Gz

    微信视频地址:http://mp.weixin.qq.com/s?__biz=MzIxODQyNTU1MA==&amp;mid=2247485703&amp;idx=1&amp;sn=c9eb898a990ca142249f68bca8ca4f35&amp;chksm=97ebf8a6a09c71b054a3a27079b6649a331c67f9353e417ff285d6736a8e3ddc201c69007e08&amp;scene=27#wechat_redirect

    微信文章地址:http://mp.weixin.qq.com/s?__biz=MzIxODQyNTU1MA==&amp;mid=2247485091&amp;idx=1&amp;sn=db0ecbf5dc6cedd2d142473162926565&amp;chksm=97ebf702a09c7e14d1fce8d65888522efddc2f55995712b10929e427b2b14a8b8159720e738f&amp;scene=27#wechat_redirect

    搜索
    关注