解析大型XML数据

时间:2014-04-29 10:36:35

标签: php python xml perl

我正在尝试解析xml文件以将数据存储到数据库中。我用PHP编写了一个代码(如下所示),我可以成功运行代码。

但问题是,它需要大约8分钟来读取一个完整的文件(大约30 MB),而且每小时我必须解析大约100个文件。

所以,显然我现在的代码对我没用。有人可以建议更好的解决方案吗?或者我应该切换到其他编码语言?

我从网上获得的是,我可以使用Perl / Python或者称为XSLT的东西(坦白说我不太确定)。

$xml = new XMLReader();
$xml->open($file);  
while ($xml->name === 'node1'){
    $node = new SimpleXMLElement($xml->readOuterXML());
    foreach($node->node2 as $node2){
        //READ
    }
    $xml->next('node1');
}
$xml->close();

4 个答案:

答案 0 :(得分:1)

以下是我用于解析WURFL XML数据库found here的脚本示例。

我使用了ElementTree模块用于Python并编写了一个JavaScript数组 - 虽然您可以轻松修改我的脚本以编写相同的CSV(只需更改最后3行)。

import xml.etree.ElementTree as ET

tree = ET.parse('C:/Users/Me/Documents/wurfl.xml')

root = tree.getroot()

dicto = {} #to store the data

for device in root.iter("device"): #parse out the device objects

    dicto[device.get("id")] = [0, 0, 0, 0] #set up a list to store the needed variables
    for child in device: #iterate through each device

        if child.get("id") == "product_info": #find the product_info id
            for grand in child:

                if grand.get("name") == "model_name": #and the model_name id
                    dicto[device.get("id")][0] = grand.get("value")
                    dicto[device.get("id")][3] +=1

        elif child.get("id") == "display": #and the display id
            for grand in child:

                if grand.get("name") == "physical_screen_height":
                    dicto[device.get("id")][1] = grand.get("value")
                    dicto[device.get("id")][3] +=1

                elif grand.get("name") == "physical_screen_width":
                    dicto[device.get("id")][2] = grand.get("value")
                    dicto[device.get("id")][3] +=1

    if not dicto[device.get("id")][3] == 3: #make sure I had enough 
                                            #otherwise it's an incomplete dataset
        del dicto[device.get("id")]

arrays = []

for key in dicto.keys(): #sort this all into another list

    arrays.append(key)

arrays.sort() #and sort it alphabetically


with open('C:/Users/Me/Documents/wurfl1.js', 'w') as new: #now to write it out

    for item in arrays:

        new.write('{\n    id:"'+item+'",\n    Product_Info:"'+dicto[item][0]+'",\n    Height:"'+dicto[item][1]+'",\n    Width:"'+dicto[item][2]+'"\n},\n')

当我再次跑步时算上这个 - 花了大约3秒钟。

答案 1 :(得分:1)

在Perl中,您可以使用XML::Twig,它旨在处理大型XML文件(大于内存中的文件)

#!/usr/bin/perl

use strict;
use warnings;

use XML::Twig;

my $file= shift @ARGV;

XML::Twig->new( twig_handlers => { 'node1/node2' => \&read_node })
         ->parsefile( $file);

sub read_node
  { my( $twig, $node2)= @_;
    # your code, the whole node2 string is $node2->sprint

    $twig->purge; # if you want to reduce memory footprint

  }

您可以在xmltwig.org

找到有关XML :: Twig的更多信息

答案 2 :(得分:0)

如果是Python,我建议使用lxml

由于遇到性能问题,我建议逐步遍历XML并逐个处理,这样可以节省大量内存并且可能更快。

我在3秒钟内阅读旧服务器10 MB XML,您的情况可能会有所不同。

关于使用lxml进行迭代:http://lxml.de/tutorial.html#tree-iteration

答案 3 :(得分:0)

查看以下代码:

$node = new SimpleXMLElement($xml->readOuterXML());

readOuterXML的文档有一条评论,有时候它正试图寻找名称空间等等。无论如何,在这里我会怀疑性能问题。

如果可以,请考虑使用readInnerXML()