php解析xml,并将xml转换为层级数组
更新:HHH   时间:2023-1-7


1)xml_parser_create([ string $encoding ] ):建立一个新的xml解析器并返回可被其他xml函数使用的资源句柄,

参数$encoding:

php4,中用来只指定要被解析的xml输入的字符编码方式;

php5,自动侦测输入xml的编码,encoding仅用来指定解析后输出数据的编码

默认:输入编码=输出编码

php5.0.2+默认编码utf-8;之前版本,ISO-8859-1

2)bool xml_parser_set_option(resource $parser,int $option,mixed $value):为指定的的xml解析进行选项设置

parser:指向要设置选项信息的xml解析器指针

option:要设置选项的名称

value:要设置选项的值

设置成功返回true,失败返回false

选项数据类型描述

XML_OPTION_CASE_FOLDINGint 控制在该xml解析器中大小写是否有效。默认有效,0原样输出,1转换为大写,只控制输出样式

XML_OPTION_SKIP_TAGSTARTint 指明在一个标记名前应略过几个字符

XML_OPTION_SKIP_WHITEint 是否略过由空白字符组成的值

XML_OPTION_TARGET_ENCODINGstring

3)int xml_parse_into_struct(resource $parser,string $data,array &$values [,array &$index]):将xml

文件解析到两个对应的数组中,index参数含有指向values数组中对应值的指针,该函数返回的是一级数组,不想dom树那样有层级关系

失败返回0,成功返回1

4)eg:

源文件:

<?xml version="1.0" encoding="utf-8"?>

<newdata>

   <version a="xxx">aaaa</version>

   <sample><![CDATA[0]]></sample>

   <all><![CDATA[https]]></all>

</newdata>

value结果:

Array

(

   [0] => Array

       (

       //标签名

           [tag] => newdata

           //节点状态,open:含有子标签,起始标签;close:open的闭合部分;complete:无子标签

           [type] => open

           //层级

           [level] => 1

       )


   [1] => Array

       (

           [tag] => version

           [type] => complete

           [level] => 2

           //节点属性数组

           [attributes] => Array

               (

                   [a] => xxx

               )

           //节点值

           [value] => aaaa

       )


   [2] => Array

       (

           [tag] => sample

           [type] => complete

           [level] => 2

           [value] => 0

       )


   [3] => Array

       (

           [tag] => all

           [type] => complete

           [level] => 2

           [value] => https

       )


   [4] => Array

       (

           [tag] => newdata

           [type] => close

           [level] => 1

       )


)

索引结果:

Array

(

//节点名称

   [newdata] => Array

       (

           [0] => 0//节点起始索引

           [1] => 4//节点结束索引

       )


   [version] => Array

       (

           [0] => 1

       )


   [sample] => Array

       (

           [0] => 2

       )


   [all] => Array

       (

           [0] => 3

       )


)

5)将xml转换为array的函数:

    

    /**

     * 将xml字符串转换为数组

     * @param string $contents

     * @param string $encoding

     * @param int $get_attrbutes

     * @param string $priority

     * @param array

     */

    public static function xml2Array($contents = NULL, $encoding = 'UTF-8', $get_attributes = 1, $priority = 'tag') {

        if(!$contents) {

            return array();

        }

        if(!function_exists('xml_parser_create')) {

            return array();

        }

        //xml解析器

        $parser = xml_parser_create('');

        xml_parser_set_option($parser,XML_OPTION_TARGET_ENCODING,$encoding);

        //将标签原样输出,不转换成大写

        xml_parser_set_option($parser,XML_OPTION_CASE_FOLDING,0);

        //是否忽略空白字符

        xml_parser_set_option($parser,XML_OPTION_SKIP_WHITE,1);

        //$xml_values,$index引用类型,将文本解析到指定的数组变量中

        xml_parse_into_struct($parser, trim($contents), $xml_values/*,$index*/);

        //释放解析器

        xml_parser_free($parser);

        if(!$xml_values)

            return array();

        $xml_array = array();

        $parents = array();

        $opened_tags = array();

        $arr = array();

        //当前操作结构的指针

        $current = & $xml_array;

        //同级结构下重复标签的计数

        $repeated_tag_index = array();

        foreach ($xml_values as $data) {

            //删除属性和值,确保每次用到的是新的

            unset($attributes, $value);

            //将标签结构数组,释放到当前的变量域中

            extract($data);

            //存当前标签的结果

            $result = array();

            //存属性

            $attributes_data = array();

            //标签有value

            if(isset($value)) {

                if($priority == 'tag'){

                   $result = trim($value); 

                }else{

                    $result['value'] = trim($value);

                }

            }

            //标签有属性,且不忽略

            if($get_attributes && isset($attributes)) {

                foreach ($attributes as $attr => $val) {

                    if ($priority == 'tag'){//放入单独记录属性的数组中

                        $attributes_data[$attr] = $val;

                    }else{//统一放入$result中

                        $result['attr'][$attr] = $val;

                    }

                }

            }

            //处理节点关系

            if ($type == "open") {//有子节点标签

                $parent[$level - 1] = & $current; //$parent[$level - 1],指向复合标签的起始处

                if (!is_array($current) || (!in_array($tag, array_keys($current)))) {//xml复合标签的第一个

                    $current[$tag] = $result;//属性独立

                    /*处理结果

                        [tag] => Array

                        (

                            [value] => aaaa,

                            [attr] => Array

                                (

                                    [a] => xxx

                                )


                        )

                    */

                    if ($attributes_data){

                        $current[$tag . '_attr'] = $attributes_data;

                        /*处理结果

                            [tag] => xxxx,

                            [tag_attr] => Array

                                (

                                    [a] => xxx

                                )

                        */

                    }

                    $repeated_tag_index[$tag . '_' . $level] = 1;//记录同级中该标签重复的个数

                    //指针重新指向符合标签的子标签

                    $current = & $current[$tag];

                }else {

                    if (isset($current[$tag][0])) {//第3+个同级复合标签

                        $current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;

                        $repeated_tag_index[$tag . '_' . $level] ++;

                    } else {//第2个同级复合标签

                        //在关联数组外包一层索引数组

                        $current[$tag] = array(

                            $current[$tag],

                            $result

                        );

                        $repeated_tag_index[$tag . '_' . $level] = 2;

                        //此处只记录第一个重复标签的属性,可能有bug,需注意!

                        //要想区别各子标签的属性,需要将$priority设成非'tag'

                        if (isset($current[$tag . '_attr'])) {

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

                //第一个complete类型的标签

                if (!isset($current[$tag])) {

                    $current[$tag] = $result;

                    $repeated_tag_index[$tag . '_' . $level] = 1;

                    if ($priority == 'tag' && $attributes_data)

                        $current[$tag . '_attr'] = $attributes_data;

                }

                else {

                    //第3+个同级子标签

                    //此处只有$current[$tag][0],不行,因为可能索引到字符串的第一个字符

                    if(isset($current[$tag][0]) && !is_array($current[$tag])){

                        print_r($current);exit();

                    }

                    if(isset($current[$tag][0]) && is_array($current[$tag])) {

                        $current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;

                        //子标签的属性不忽略

                        if ($get_attributes &&  $priority == 'tag' && $attributes_data) {

                            $current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;

                        }

                        $repeated_tag_index[$tag . '_' . $level] ++;

                    }else{//第2个同级子标签

                        $current[$tag] = array(

                            $current[$tag],

                            $result

                        );

                        $repeated_tag_index[$tag . '_' . $level] = 1;

                        if ($priority == 'tag' && $get_attributes) {

                            if (isset($current[$tag . '_attr'])) {

                                $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] ++;

                    }

                }

            }elseif($type == 'close'){

                //闭合标签和起始标签level相同,因此进入complete类型的子标签后,可以通过父节点的close标签,可以指回到父节点

                $current = & $parent[$level - 1];

            }

        }

        return $xml_array;

    }

6)关于xml中的CDATA:

    在XML文档中的所有文本都会被解析器解析。只有在CDATA部件之内的文本会被解析器忽略

    一个 CDATA 部件以"< ![CDATA[" 标记开始,以"]]>"标记结束:

    < script>
    < ![CDATA[
    function matchwo(a,b)
    {
        if (a < b && a < 0) then
        {
            return 1
        }
        else
        {
            return 0
        }
      }
     ]]>
    < /script>

    在前面的例子中,所有在CDATA部件之间的文本都会被解析器忽略。

    CDATA注意事项:
    CDATA部件之间不能再包含CDATA部件(不能嵌套)。如果CDATA部件包含了字符"]]>" 或者"< !        [CDATA[" ,将很有可能出错哦。

    同样要注意在字符串"]]>"之间没有空格或者换行符

参考地址:http://www.cnblogs.com/chenqingwei/archive/2010/04/21/1717237.html

返回web开发教程...