您的位置:首页 > 编程语言 > Python开发

Python使用XPATH解析特定结构XML文件速度提升方法

2016-04-01 18:27 1091 查看
首先

import xml.etree.cElementTree as et


来看XML格式

<?xml version="1.0" encoding="UTF-8"?>
<File xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FileFormat.xsd">
<FileHeader>
<DateTime>2016-01-06T03:30:10+08:00</DateTime>
</FileHeader>
<Objects>
<ObjectType>EutranCellTdd</ObjectType>
<FieldName>
<N i="1">a</N>
<N i="2">b</N>
<N i="3">c</N>
<N i="4">d</N>
<N i="5">f</N>
<N i="6">g</N>
<N i="7">h</N>
<N i="8">i</N>
<N i="9">j</N>
<N i="10">k</N>
</FieldName>
<FieldValue>
<Vv Label="xxx">
<V i="1">1</V>
<V i="2">汉字</V>
<V i="3">还是汉字</V>
<V i="4">一直是汉字</V>
<V i="5">1</V>
<V i="6">怎样?</V>
<V i="7"></V>
<V i="8"></V>
<V i="9"></V>
<V i="10">{0}</V>
</Vv>
</Objects>
</File>


类似这样的FieldName中的i与FieldValue中同样i值的两部分组成字段的字段名和值,这样的字段有数百个,而我们可能只需要从中提取几个。开始的解决方案是

1. 建立要获取字段字段名的列表list_n,如list_n = [‘a’, ‘b’, ‘d’]

2. 建立以i值为key,FieldName中对应的text为值的字典dict_i_name,且value为list_n中的值,如

dict_i_name = {‘1’: ‘a’, ‘2’: ‘b’, ‘4’:’d’}

3. 在Vv这个Element里遍历V,当
dict_i_name[V.attrib['i']] in list_n
的时候,就把该字段的值拿出来,存储起来

假设有300个字段,有10000个Vv标签,那么需要遍历300*10000次才完成。

中间方法:

假设我们需要提取n个字段,而最后一个字段的位置为i=’x’,那么如果加入一个计数器cnt记录已取到的当前Vv标签中值的个数,循环后面再做一个判断,如果cnt>=n,则break。遍历次数10000*x,同时还需要做10000*n次自增和10000*x次数值大小比较的判断,自增和判断先不考虑,若n=8,x=10,则只需要10000*10次遍历,减少很多很多。但其对x特别依赖,很不幸,还真有一个文件x是最后一个!这样不仅没减少遍历次数,反而增加了自增和比较……

最终方法:

所以还是需要寻找更好的方法,在网上大致一搜,没找到最需要的方法,找官方的doc,xml.etree.elementtree中19.7.2节中介绍的XPath Support可以满足要求





之前只知道find(‘tag’),而不知道其他的。原来find/findall还能有这么多不同的变换!

经过思考,使用一下方法:

def DealingSingleValue(parent_node, dict_i_name, attrib_name, list_n):
for attrib_value in dict_i_name:
condition = ".//*[@"+attrib_name+"='"+attrib_value+"']"
result = parent_node.find(condition)
df_input[dict_i_name[attrib_value]] = result.text
return df_input


其中,parent_node是V的父节点,即Vv,dict_i_name与上述相同,attrib_name是V标签中的attrib,即i,df_input是一个DataFrame,其column为list_n。

遍历dict_i_name中的key,即’1’, ‘2’, ‘4’,对应的condition为

condition = ".//*[@i='1']"
condition = ".//*[@i='2']"
condition = ".//*[@i='4']"


result = parent_node.find(condition)


的意思为寻找parent_node标签下的子标签(V)中,所有有attrib为i,且i=’1’的所有Element,注意result是Element类型的。然后再用result.text就获得到该字段的值了。

实测速度比最初的方法快太多了,与中间方法中最好的情况没什么差别。虽然不知道实现原理,但还是满足我的需要了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: