使用 xml 树解析大型 python xml
Parse large python xml using xmltree
我有一个 python 脚本可以解析巨大的 xml 文件(最大的一个是 446 MB)
try:
parser = etree.XMLParser(encoding='utf-8')
tree = etree.parse(os.path.join(srcDir, fileName), parser)
root = tree.getroot()
except Exception, e:
print "Error parsing file "+str(fileName) + " Reason "+str(e.message)
for child in root:
if "PersonName" in child.tag:
personName = child.text
这就是我的 xml 的样子 :
<?xml version="1.0" encoding="utf-8"?>
<MyRoot xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" uuid="ertr" xmlns="http://www.example.org/yml/data/litsmlv2">
<Aliases authority="OPP" xmlns="http://www.example.org/yml/data/commonv2">
<Description>myData</Description>
<Identifier>43hhjh87n4nm</Identifier>
</Aliases>
<RollNo uom="kPa">39979172.201167159</RollNo>
<PersonName>Miracle Smith</PersonName>
<Date>2017-06-02T01:10:32-05:00</Date>
....
我只想获取 PersonName 标签内容,仅此而已。其他标签我不关心。
遗憾的是我的文件很大,当我使用上面的代码时我总是收到这个错误:
Error parsing file 2eb6d894-0775-e611.xml Reason unknown error, line 1, column 310915857
Error parsing file 2ecc18b5-ef41-e711-80f.xml Reason Extra content at the end of the document, line 1, column 3428182
Error parsing file 2f0d6926-b602-e711-80f4-005.xml Reason Extra content at the end of the document, line 1, column 6162118
Error parsing file 2f12636b-b2f5-e611-80f3-00.xml Reason Extra content at the end of the document, line 1, column 8014679
Error parsing file 2f14e35a-d22b-4504-8866-.xml Reason Extra content at the end of the document, line 1, column 8411238
Error parsing file 2f50c2eb-55c6-e611-80f0-005056a.xml Reason Extra content at the end of the document, line 1, column 7636614
Error parsing file 3a1a3806-b6af-e611-80ef-00505.xml Reason Extra content at the end of the document, line 1, column 11032486
我的XML完全没问题,没有多余的内容。看来是大文件解析出错了。
我看过 iterparse() 但它似乎对我想要实现的目标来说很复杂,因为它提供了对整个 DOM 的解析,而我只想要根目录下的那个标签。另外,没有给我一个很好的样本来通过标签名称获得正确的值吗?
我应该使用正则表达式解析还是 grep /awk 方式来执行此操作?或者对我的代码进行任何调整都可以让我在这些大文件中获取人名?
更新:
试过这个示例,它似乎从 xml 打印整个世界,除了我的标签 ?
iterparse 是否从文件的底部到顶部读取?在那种情况下,需要很长时间才能到达顶部,即我的 PersonName 标签?我尝试更改下面的行以读取 end to start events=("end", "start") 并且它做了同样的事情 !!!
path = []
for event, elem in ET.iterparse('D:\mystage\2-80ea-005056.xml', events=("start", "end")):
if event == 'start':
path.append(elem.tag)
elif event == 'end':
# process the tag
print elem.text // prints whole world
if elem.tag == 'PersonName':
print elem.text
path.pop()
在这种情况下,Iterparse 并不难用。
temp.xml
是您问题中显示的文件,最后有一个 </MyRoot>
作为一行。
将 source =
视为样板,如果你愿意的话,它会逐个元素地解析 xml 文件和它的 returns 块,表明该块是否是'start' 元素或 'end' 并提供有关元素的信息。
在这种情况下,我们只需要考虑 'start' 个事件。我们观察 'PersonName' 标签并获取它们的文本。在 xml 文件中找到唯一的此类项目后,我们放弃处理。
>>> from xml.etree import ElementTree
>>> source = iter(ElementTree.iterparse('temp.xml', events=('start', 'end')))
>>> for an_event, an_element in source:
... if an_event=='start' and an_element.tag.endswith('PersonName'):
... an_element.text
... break
...
'Miracle Smith'
编辑,回复评论中的问题:
通常您不会这样做,因为 iterparse
旨在与大块 xml 一起使用。但是,通过将字符串包装在 StringIO
对象中,可以使用 iterparse
.
对其进行处理
>>> from xml.etree import ElementTree
>>> from io import StringIO
>>> xml = StringIO('''\
... <?xml version="1.0" encoding="utf-8"?>
... <MyRoot xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" uuid="ertr" xmlns="http://www.example.org/yml/data/litsmlv2">
... <Aliases authority="OPP" xmlns="http://www.example.org/yml/data/commonv2">
... <Description>myData</Description>
... <Identifier>43hhjh87n4nm</Identifier>
... </Aliases>
... <RollNo uom="kPa">39979172.201167159</RollNo>
... <PersonName>Miracle Smith</PersonName>
... <Date>2017-06-02T01:10:32-05:00</Date>
... </MyRoot>''')
>>> source = iter(ElementTree.iterparse(xml, events=('start', 'end')))
>>> for an_event, an_element in source:
... if an_event=='start' and an_element.tag.endswith('PersonName'):
... an_element.text
... break
...
'Miracle Smith'
我有一个 python 脚本可以解析巨大的 xml 文件(最大的一个是 446 MB)
try:
parser = etree.XMLParser(encoding='utf-8')
tree = etree.parse(os.path.join(srcDir, fileName), parser)
root = tree.getroot()
except Exception, e:
print "Error parsing file "+str(fileName) + " Reason "+str(e.message)
for child in root:
if "PersonName" in child.tag:
personName = child.text
这就是我的 xml 的样子 :
<?xml version="1.0" encoding="utf-8"?>
<MyRoot xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" uuid="ertr" xmlns="http://www.example.org/yml/data/litsmlv2">
<Aliases authority="OPP" xmlns="http://www.example.org/yml/data/commonv2">
<Description>myData</Description>
<Identifier>43hhjh87n4nm</Identifier>
</Aliases>
<RollNo uom="kPa">39979172.201167159</RollNo>
<PersonName>Miracle Smith</PersonName>
<Date>2017-06-02T01:10:32-05:00</Date>
....
我只想获取 PersonName 标签内容,仅此而已。其他标签我不关心。
遗憾的是我的文件很大,当我使用上面的代码时我总是收到这个错误:
Error parsing file 2eb6d894-0775-e611.xml Reason unknown error, line 1, column 310915857
Error parsing file 2ecc18b5-ef41-e711-80f.xml Reason Extra content at the end of the document, line 1, column 3428182
Error parsing file 2f0d6926-b602-e711-80f4-005.xml Reason Extra content at the end of the document, line 1, column 6162118
Error parsing file 2f12636b-b2f5-e611-80f3-00.xml Reason Extra content at the end of the document, line 1, column 8014679
Error parsing file 2f14e35a-d22b-4504-8866-.xml Reason Extra content at the end of the document, line 1, column 8411238
Error parsing file 2f50c2eb-55c6-e611-80f0-005056a.xml Reason Extra content at the end of the document, line 1, column 7636614
Error parsing file 3a1a3806-b6af-e611-80ef-00505.xml Reason Extra content at the end of the document, line 1, column 11032486
我的XML完全没问题,没有多余的内容。看来是大文件解析出错了。 我看过 iterparse() 但它似乎对我想要实现的目标来说很复杂,因为它提供了对整个 DOM 的解析,而我只想要根目录下的那个标签。另外,没有给我一个很好的样本来通过标签名称获得正确的值吗?
我应该使用正则表达式解析还是 grep /awk 方式来执行此操作?或者对我的代码进行任何调整都可以让我在这些大文件中获取人名?
更新: 试过这个示例,它似乎从 xml 打印整个世界,除了我的标签 ?
iterparse 是否从文件的底部到顶部读取?在那种情况下,需要很长时间才能到达顶部,即我的 PersonName 标签?我尝试更改下面的行以读取 end to start events=("end", "start") 并且它做了同样的事情 !!!
path = []
for event, elem in ET.iterparse('D:\mystage\2-80ea-005056.xml', events=("start", "end")):
if event == 'start':
path.append(elem.tag)
elif event == 'end':
# process the tag
print elem.text // prints whole world
if elem.tag == 'PersonName':
print elem.text
path.pop()
在这种情况下,Iterparse 并不难用。
temp.xml
是您问题中显示的文件,最后有一个 </MyRoot>
作为一行。
将 source =
视为样板,如果你愿意的话,它会逐个元素地解析 xml 文件和它的 returns 块,表明该块是否是'start' 元素或 'end' 并提供有关元素的信息。
在这种情况下,我们只需要考虑 'start' 个事件。我们观察 'PersonName' 标签并获取它们的文本。在 xml 文件中找到唯一的此类项目后,我们放弃处理。
>>> from xml.etree import ElementTree
>>> source = iter(ElementTree.iterparse('temp.xml', events=('start', 'end')))
>>> for an_event, an_element in source:
... if an_event=='start' and an_element.tag.endswith('PersonName'):
... an_element.text
... break
...
'Miracle Smith'
编辑,回复评论中的问题:
通常您不会这样做,因为 iterparse
旨在与大块 xml 一起使用。但是,通过将字符串包装在 StringIO
对象中,可以使用 iterparse
.
>>> from xml.etree import ElementTree
>>> from io import StringIO
>>> xml = StringIO('''\
... <?xml version="1.0" encoding="utf-8"?>
... <MyRoot xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" uuid="ertr" xmlns="http://www.example.org/yml/data/litsmlv2">
... <Aliases authority="OPP" xmlns="http://www.example.org/yml/data/commonv2">
... <Description>myData</Description>
... <Identifier>43hhjh87n4nm</Identifier>
... </Aliases>
... <RollNo uom="kPa">39979172.201167159</RollNo>
... <PersonName>Miracle Smith</PersonName>
... <Date>2017-06-02T01:10:32-05:00</Date>
... </MyRoot>''')
>>> source = iter(ElementTree.iterparse(xml, events=('start', 'end')))
>>> for an_event, an_element in source:
... if an_event=='start' and an_element.tag.endswith('PersonName'):
... an_element.text
... break
...
'Miracle Smith'