0. iterparse到终极理解,按文件流顺序解析,需要设置一些信号变量,用来只获取自己想要到数据,剔除不要的数据。
context=ET.iterparse(xm, events=(‘start’, ‘end’))
# context=iter(context)
# root=context.next()
for event, elem in context:
try:
if event == 'start' and elem.tag == 'fileHeader':
sqltimestamp=elem.get('startTime').replace('T','').replace('-','').replace(':','')
elif event == 'end' and elem.tag == 'smr' :
if 'MR.LteScPlr' in elem.text:
meas_sign=1
else:
meas_sign=0
elem.clear()
elif event == 'start' and elem.tag == 'object':
if meas_sign==1:
cellid=elem.get('id')
elif event == 'end' and elem.tag == 'v':
if meas_sign==1:
text_plr = elem.text
if text_plr:
text_plr_list = text_plr.split(' ')
if len(text_plr_list)>10:
LteScPlrULQci1 = text_plr_list[0]
LteScPlrDLQci1 = text_plr_list[9]
if LteScPlrULQci1!='NIL':
tempindex=plr_interval(int(LteScPlrULQci1))
if cellid not in cell_dict.keys():
cell_dict[cellid]=mro_values[:]
cell_dict[cellid][tempindex]+=1
if LteScPlrDLQci1!='NIL':
tempindex=plr_interval(int(LteScPlrDLQci1))
if cellid not in cell_dict.keys():
cell_dict[cellid]=mro_values[:]
cell_dict[cellid][tempindex+28]+=1
elem.clear()
elif event == 'end' and elem.tag == 'object':
elem.clear()
elif event == 'end' and elem.tag == 'bulkPmMrDataFile':
elem.clear()
# else:
# elem.clear()
except Exception as e:
print(str(e),'mro elem do error'+gz)
elem.clear()
1、elementTree的iterparse()使用event、elem IN 遍历,当事件是start时,很多教材说此时解析到了elem的TAG而后面没有开始解析,这种说法容易迷惑人。此时开始了elem的start,想获得elem的text等内容都是可以的,因为已经定位了该elem,只要继续往下读就能获得其他内容,没有必要等到end才去获取TEXT、属性等内容,很多时候在start的时候就要获得属性内容(实时写入数据库),判断属性是否是所需elem,不需要的内容直接在start时就可以clear,不需要再解析缓存一遍,至少能快一些。
以上理解有误,实践起来结果并不准确,直到看到一篇文章,才明白原理:
http://effbot.org/zone/element-iterparse.htm
http://www.51testing.com/html/69/610069-3646742.html
events选项指定您要查看的事件(此版本中的可用事件是“start”,“end”,“start-ns”和“end-ns”,其中“ns”事件用于获取详细的命名空间 信息)。 如果省略该选项,则仅返回“end”事件。
注意:树构建器和事件生成器不一定是同步的; 后者通常落后一点。 这意味着当您获得元素的“开始”事件时,构建器可能已经使用内容填充了该元素。 但是,您不能依赖于此 - “开始”事件只能用于检查属性,而不是元素内容。 有关更多详细信息,请参阅此消息。https://mail.python.org/pipermail/xml-sig/2005-January/010838.html
“Jimmy Retzlaff写道:
我正在使用cElementTree.iterparse迭代XML文件。我认为
iterparse是一个很棒的主意 - 我发现它更方便
比SAX用于迭代处理。我遇到了一个问题
虽然…对于我的大多数元素,start和end事件都包含
元素的文本(即element.text)。少数几个
元素,文本仅在结束事件中(即,element.text为None
在开始事件中但在结束事件中不是无)。文字是
在文件上使用cElementTree.parse时发现没有任何问题
相反。
我误解了什么,或者这可能是一个错误?
它需要更多文档;-)
以下是CHANGES文件中的评论:
elem对象是当前元素;对于“开始”事件,
元素本身已经创建(包括属性),但它
内容可能不完整;对于“结束”事件,所有子元素
已被处理。您可以使用“开始”标记进行计数
元素,检查属性,并检查是否存在某些标记
在树上。出于所有其他目的,请改用“end”处理程序。
在该文中,“可能不”实际上意味着“可能或不可能”。就是内容
可能是完整的,但这不是你可以或应该依赖的。
这样做的原因是事件不会与构建完美锁定
处理;在当前版本中,解析器可能会提前16k。
这意味着当你得到一个“开始”事件时,解析器经常被处理
事件内部的一切(特别是如果它足够小),但你不能
靠那个。
或者换句话说,对于开始事件,以下属性是有效的:
elem.tag
elem.attrib
父元素的标签和属性(如果你使用堆栈)
需要跟踪他们)
(不是elem.text)
(不是elem.tail)
(不是elem [:])
您可以修改标记和属性
你可能会停止解析
对于最终活动,以下内容适用:
elem.tag
elem.attrib
elem.text
elem [:](即孩子们)
所有孩子的完整内容(包括尾巴)
(不是elem.tail)(但是所有的孩子尾巴)
您可以修改除elem.tail之外的所有属性
你可以重新排序/更新孩子
你可以删除孩子(例如,调用elem.clear()来标记它
你完成了这个水平)
你可能会停止解析”
for event, elem in iterparse(source):
if elem.tag ==“record”:
… process record elements …
elem.clear(
上述模式有一个缺点; 它不会清除根元素,因此您最终会得到一个包含许多空子元素的元素。 如果您的文件很大,而不是很大,这可能是个问题。 要解决这个问题,您需要掌握根元素。 最简单的方法是启用启动事件,并保存对变量中第一个元素的引用
# get an iterable
context = iterparse(source, events=(“start”, “end”))
# turn it into an iterator
context = iter(context)
# get the root element
event, root = context.next()
for event, elem in context:
if event == “end” and elem.tag == “record”:
… process record elements …
root.clear()
2、elementTree在写XML时,属性是无序字典,一般按升序写入属性,重写序列化方法可以达到顺序写入目的,但比较麻烦。lxml可以解决属性顺序写入问题。只要将前者替换成from lxml import etree as ET 就行了。但后者缓存了父节点和框架,内存占用大些/解析慢些,但写入序列化速度很快,是优势。纯解析就用et,解析加写入就用lxml。
3、关于XML schema及命名空间
https://wenku.baidu.com/view/6733739d3086bceb19e8b8f67c1cfad6185fe913.html
https://www.cnblogs.com/ljzforever/archive/2009/05/20/1467792.html
XML schema是W3规范的内容,规范规定了schema内包含固定标签-element/attribute/text及内部数据类型,是个人和规范的接口。可以使用schema文件在其中自定义标签及自定义数据类型 simpletype/complextype.
使用targetnamespace属性,可以将自定义的标签、属性、数据类型等加载到自定义命名空间中,要使用该自定义命名空间,可以加载自定义命名空间所在xsd文件即可。
<xs:schema xmlns="" xmlns:xs=“http://www.w3.org/2001/XMLSchema” xmlns:msdata=“urn:schemas-microsoft-com:xml-msdata” id=“bulkPmMrDataFile”>
<xs:element name=“bulkPmMrDataFile” msdata:IsDataSet=“true” msdata:Locale=“en-US”>
xs:complexType
xs:sequence
<xs:element name=“fileHeader”>
xs:complexType
<xs:attribute name=“fileFormatVersion” type=“xs:string” use=“required”/>
<xs:attribute name=“reportTime” type=“xs:dateTime” use=“required”/>
<xs:attribute name=“startTime” type=“xs:dateTime” use=“required”/>
<xs:attribute name=“endTime” type=“xs:dateTime” use=“required”/>
<xs:attribute name=“period” type=“xs:int” use=“optional”/>
<xs:attribute name=“jobid” type=“xs:int” use=“optional”/>
</xs:complexType>
</xs:element>
(1)schema的作用就是定义xml的架构、元素定义。使用命名空间一般是xmlns:xs=“http://www.w3.org/2001/XMLSchema”,如果xmlns:xs 替换成xmlns,那该空间就是默认命名空间,元素不用带命名空间名称xs。schema规定使用"http://www.w3.org/2001/XMLSchema"命名空间,包含schema/element /attribite/text等基本标签。其它命名空间有自有的命名空间,可以自己定义自己的命名空间-xmlns:xx,凡事非默认命名空间的标签、属性等都要在标签名称前面加所属命名空间,如xx:tag。
(2)可以看到xmlns有的是网址,有的是其它URI,但是对于网址开头的命名空间有可能就有点疑惑了,它究竟代表的是什么?xaml文件被解析的时候会访问这个网址吗?如果这个网址那天不能get了,那我们的程序是不是就不能正常运行了。实际是所有URI只是命名空间的别名而已,它实际代表是命名空间集合:
以xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation这个为例,其实它就是System.Windows,System.Windows.Automation,System.Winjdows.Controls…等一系列命名空间的集合,是这个集合的【别名】,在浏览器输入这个网址有时候是不可访问的。如果自己定义类库的话,我把这个【别名】叫做张三也是可以的。微软建议,这个一般定义为公司网址,或者个人网址。
详见引用:https://blog.csdn.net/catshitone/article/details/71213371
(3)命名空间的作用是避免元素定义混淆、重复。也就是说xml中所有节点、属性名称在全网都是唯一的。
见:https://blog.csdn.net/yi412/article/details/70158876
(4)命名空间保存在xsd文件中,本身也是xml规范文件。自定义命名空间保存在本地,可供外使用,只要和需生成的xml文件在同一目录就行,需要在文件中加入文件名引用(Xxxx.xsd)。