PHP:如何最有效地将XML解析为Array?

时间:2019-06-07 09:25:23

标签: php arrays xml

我需要更快的方法来将XML解析为数组(没有空值)。

到目前为止,我正在使用Array2XML(由Lalit Patel开发)库将XML解析为数组,但这是脚本的瓶颈。我当时想加快速度,发现速度提高了大约15倍:

class SimpleXmlDecoder
{

    public function decode(string $xml): array
    {
        try {
            $decoded = json_decode(json_encode(
                simplexml_load_string($xml, "SimpleXMLElement", LIBXML_NOCDATA)
            ),TRUE);

            if (empty($decoded)) {
                return [];
            }

            return self::mapEmptyArraysElementsToEmptyString($decoded);
        } catch (\Exception $exception) {
            return [];
        }
    }

    private static function mapEmptyArraysElementsToEmptyString($array): array
    {
        return array_map(
            static function($value) {
                if (!is_array($value)) {
                    return $value;
                }

                if (empty($value)) {
                    return '';
                }

                return self::mapEmptyArraysElementsToEmptyString($value);
            },
            $array
        );
    }

}

现在足够了,但将来可能成为瓶颈。您知道更快的方法吗?

@编辑 每个XML的大小:100kB-1MB 需要具有名称和值的所有NON-EMPTY元素的返回值。

3 个答案:

答案 0 :(得分:0)

您可以使用simplexml_load_string()函数来解析xml。请参阅“ https://www.w3schools.com/php/php_xml_simplexml_read.asp”以了解更多信息。

答案 1 :(得分:0)

我只是快速地将下面的xmlparser类拼凑在一起,该类使用RecursiveDOMIterator类来处理xml文件。我不知道这是否比您的原始代码要快-在本地处理文件时看起来很活跃-它可以在2.4秒内处理非常复杂的8Mb xml文件,但可以压缩较小的文件。我很想知道它在比较中的表现

<?php

    class RecursiveDOMIterator implements RecursiveIterator {
        /*
            https://github.com/salathe/spl-examples/wiki/RecursiveDOMIterator
        */
        private $index;
        private $list;

        public function __construct(DOMNode $domNode){
            $this->index = 0;
            $this->list = $domNode->childNodes;
        }
        public function current(){
            return $this->list->item($this->index);
        }
        public function getChildren(){
            return new self( $this->current() );
        }
        public function hasChildren(){
            return $this->current()->hasChildNodes();
        }
        public function key(){
            return $this->index;
        }
        public function next(){
            $this->index++;
        }
        public function rewind(){
            $this->index = 0;
        }
        public function valid(){
            return $this->index < $this->list->length;
        }
    }//end class


    class xmlparser{
        private static $instance=false;
        private $start;
        private $dom;

        private function __construct( $xml ){
            $this->start=microtime( true );
            libxml_use_internal_errors( true );
            $this->dom=new DOMDocument;
            $this->dom->validateOnParse=true;
            $this->dom->recover=true;
            $this->dom->strictErrorChecking=true;

            if( is_file( $xml ) && file_exists( $xml ) ) $this->dom->load( $xml );
            else $this->dom->loadXML( $xml );

            libxml_clear_errors();
        }

        private function __clone(){}
        public function __wakeup(){}
        public static function initialise( $xml ){
            if( !self::$instance ) self::$instance=new xmlparser( $xml );
            return self::$instance;
        }

        public function parse(){
            $itr = new RecursiveIteratorIterator( new RecursiveDOMIterator( $this->dom ), RecursiveIteratorIterator::SELF_FIRST );
            $tmp=[];
            foreach( $itr as $node) {
                if( $node->nodeType === XML_ELEMENT_NODE ) {

                    $tag=$node->tagName;
                    $value=$node->nodeValue;

                    if( !empty( $value ) ){
                        $element=[
                            'tag'   =>  $tag,
                            'value' =>  $value
                        ];
                        if( $node->hasAttributes() ){
                            $attributes=[];
                            foreach( $node->attributes as $index => $attr ){
                                $attributes[ $attr->nodeName ]=$attr->nodeValue;
                            }
                            $element['attributes']=$attributes;
                        }
                        $tmp[]=$element;
                    }
                }
            }
            $this->duration=microtime( true ) - $this->start;
            return $tmp;
        }
        public function __get( $name ){
            return $this->$name;
        }
    }//end class



    $file = 'bbc_rss.xml';
    $obj = xmlparser::initialise( $file );
    $data = $obj->parse();
    $time = $obj->duration;
    $size = round( $obj->filesize/pow( 1024, 2 ),2 );



    printf( "Time: %s\nSize:%sMb", $time, $size );

?>

答案 2 :(得分:0)

您可以使用SAX parser,使用它可以解析大文件。

  

SAX解析器用于解析XML文件,并且比示例XML解析器和DOM更好地用于内存管理。它不会在内存中保留任何数据,因此可以用于非常大的文件。以下示例将展示如何使用SAX API从XML获取数据。

Link