How do I parse XML in Python?
我在一个包含XML的数据库中有许多行,我正在尝试编写一个python脚本,该脚本将遍历这些行,并计算特定节点属性的实例数。例如,我的树看起来像:
1 2 3 4 5 6 | <foo> <bar> <type foobar="1"/> <type foobar="2"/> </bar> </foo> |
如何使用python访问XML中的属性1和2?
我建议用
首先从XML构建元素实例
1 2 | import xml.etree.ElementTree as ET root = ET.parse('thefile.xml').getroot() |
或者在
1 2 3 | for type_tag in root.findall('bar/type'): value = type_tag.get('foobar') print(value) |
以及类似的,通常非常简单的代码模式。
XML:
1 2 3 4 5 6 7 8 | <data> <items> <item name="item1"></item> <item name="item2"></item> <item name="item3"></item> <item name="item4"></item> </items> </data> |
Python:
1 2 3 4 5 6 7 | from xml.dom import minidom xmldoc = minidom.parse('items.xml') itemlist = xmldoc.getElementsByTagName('item') print(len(itemlist)) print(itemlist[0].attributes['name'].value) for s in itemlist: print(s.attributes['name'].value) |
产量
1 2 3 4 5 6 | 4 item1 item1 item2 item3 item4 |
你可以用漂亮的汤
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | from bs4 import BeautifulSoup x="""<foo> <bar> <type foobar="1"/> <type foobar="2"/> </bar> </foo>""" y=BeautifulSoup(x) >>> y.foo.bar.type["foobar"] u'1' >>> y.foo.bar.findAll("type") [<type foobar="1"></type>, <type foobar="2"></type>] >>> y.foo.bar.findAll("type")[0]["foobar"] u'1' >>> y.foo.bar.findAll("type")[1]["foobar"] u'2' |
有很多选择。如果速度和内存使用是一个问题,CelementTree看起来很好。与使用
相关指标见下表,从CelementTree网站复制:
1 2 3 4 5 6 7 8 9 10 11 12 | library time space xml.dom.minidom (Python 2.1) 6.3 s 80000K gnosis.objectify 2.0 s 22000k xml.dom.minidom (Python 2.4) 1.4 s 53000k ElementTree 1.2 1.6 s 14500k ElementTree 1.2.4/1.3 1.1 s 14500k cDomlette (C extension) 0.540 s 20500k PyRXPU (C extension) 0.175 s 10850k libxml2 (C extension) 0.098 s 16000k readlines (read as utf-8) 0.093 s 8850k cElementTree (C extension) --> 0.047 s 4900K <-- readlines (read as ascii) 0.032 s 5050k |
正如@jfs所指出的,
- python 2:
from xml.etree import cElementTree as ElementTree 。 - python 3:
from xml.etree import ElementTree (自动使用加速的C版本)。
为了简单起见,我建议使用xmltodict。
它将XML解析为ordereddict;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | >>> e = '<foo> <bar> <type foobar="1"/> <type foobar="2"/> </bar> </foo> ' >>> import xmltodict >>> result = xmltodict.parse(e) >>> result OrderedDict([(u'foo', OrderedDict([(u'bar', OrderedDict([(u'type', [OrderedDict([(u'@foobar', u'1')]), OrderedDict([(u'@foobar', u'2')])])]))]))]) >>> result['foo'] OrderedDict([(u'bar', OrderedDict([(u'type', [OrderedDict([(u'@foobar', u'1')]), OrderedDict([(u'@foobar', u'2')])])]))]) >>> result['foo']['bar'] OrderedDict([(u'type', [OrderedDict([(u'@foobar', u'1')]), OrderedDict([(u'@foobar', u'2')])])]) |
lxml.objectify非常简单。
提取示例文本:
1 2 3 4 5 6 7 8 9 10 11 | from lxml import objectify from collections import defaultdict count = defaultdict(int) root = objectify.fromstring(text) for item in root.bar.type: count[item.attrib.get("foobar")] += 1 print dict(count) |
输出:
1 | {'1': 1, '2': 1} |
python有一个到expat XML解析器的接口。
1 | xml.parsers.expat |
它是一个未验证的解析器,因此不会捕获坏的XML。但是如果你知道你的文件是正确的,那么这是非常好的,你可能会得到你想要的确切信息,你可以在飞行中丢弃其余的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | stringofxml ="""<foo> <bar> <type arg="value" /> <type arg="value" /> <type arg="value" /> </bar> <bar> <type arg="value" /> </bar> </foo>""" count = 0 def start(name, attr): global count if name == 'type': count += 1 p = expat.ParserCreate() p.StartElementHandler = start p.Parse(stringofxml) print count # prints 4 |
我建议使用declxml。
完全公开:我编写这个库是因为我在寻找一种在XML和Python数据结构之间转换的方法,而不需要用elementtree编写几十行必需的解析/序列化代码。
使用declXML,可以使用处理器声明性地定义XML文档的结构以及如何在XML和Python数据结构之间进行映射。处理器用于序列化和解析以及基本的验证级别。
解析为python数据结构非常简单:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | import declxml as xml xml_string =""" <foo> <bar> <type foobar="1"/> <type foobar="2"/> </bar> </foo> """ processor = xml.dictionary('foo', [ xml.dictionary('bar', [ xml.array(xml.integer('type', attribute='foobar')) ]) ]) xml.parse_from_string(processor, xml_string) |
产生输出:
1 | {'bar': {'foobar': [1, 2]}} |
也可以使用同一个处理器将数据序列化为XML
1 2 3 4 5 | data = {'bar': { 'foobar': [7, 3, 21, 16, 11] }} xml.serialize_to_string(processor, data, indent=' ') |
产生以下输出
1 2 3 4 5 6 7 8 9 10 | <?xml version="1.0" ?> <foo> <bar> <type foobar="7"/> <type foobar="3"/> <type foobar="21"/> <type foobar="16"/> <type foobar="11"/> </bar> </foo> |
如果您想使用对象而不是字典,那么您也可以定义处理器来在对象之间转换数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | import declxml as xml class Bar: def __init__(self): self.foobars = [] def __repr__(self): return 'Bar(foobars={})'.format(self.foobars) xml_string =""" <foo> <bar> <type foobar="1"/> <type foobar="2"/> </bar> </foo> """ processor = xml.dictionary('foo', [ xml.user_object('bar', Bar, [ xml.array(xml.integer('type', attribute='foobar'), alias='foobars') ]) ]) xml.parse_from_string(processor, xml_string) |
产生以下输出
1 | {'bar': Bar(foobars=[1, 2])} |
为了增加另一种可能性,您可以使用untangle,因为它是一个简单的XML到Python对象库。这里有一个例子:
安装
1 | pip install untangle |
用法
您的XML文件(有点更改):
1 2 3 4 5 | <foo> <bar name="bar_name"> <type foobar="1"/> </bar> </foo> |
使用untangle访问属性:
1 2 3 4 5 6 | import untangle obj = untangle.parse('/path_to_xml_file/file.xml') print obj.foo.bar['name'] print obj.foo.bar.type['foobar'] |
输出将是:
1 2 | bar_name 1 |
有关untangle的更多信息可以在这里找到。另外(如果您好奇的话),您可以在这里找到一个用于XML和Python的工具列表(您还会看到前面的答案提到了最常见的工具)。
这里有一个使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | try: import cElementTree as ET except ImportError: try: # Python 2.5 need to import a different module import xml.etree.cElementTree as ET except ImportError: exit_err("Failed to import cElementTree from any known place") def find_in_tree(tree, node): found = tree.find(node) if found == None: print"No %s in file" % node found = [] return found # Parse a xml file (specify the path) def_file ="xml_file_name.xml" try: dom = ET.parse(open(def_file,"r")) root = dom.getroot() except: exit_err("Unable to open and parse input definition file:" + def_file) # Parse to find the child nodes list of node 'myNode' fwdefs = find_in_tree(root,"myNode") |
来源:
http://www.snip2code.com/snippet/991/python-xml-parse?来自1页
我发现python xml.dom和xml.dom.minidom非常简单。请记住,DOM不适合于大量的XML,但是如果您的输入相当小,那么这将很好地工作。
1 2 3 4 5 6 7 8 9 10 11 | import xml.etree.ElementTree as ET data = '''<foo> <bar> <type foobar="1"/> <type foobar="2"/> </bar> </foo>''' tree = ET.fromstring(data) lst = tree.findall('bar/type') for item in lst: print item.get('foobar') |
这将打印foobar属性的值。
XML
1 2 3 4 5 6 | <foo> <bar> <type foobar="1"/> <type foobar="2"/> </bar> </foo> |
Python码
1 2 3 4 5 6 7 8 9 10 11 12 | import xml.etree.cElementTree as ET tree = ET.parse("foo.xml") root = tree.getroot() root_tag = root.tag print(root_tag) for form in root.findall("./bar/type"): x=(form.attrib) z=list(x) for i in z: print(x[i]) |
输出:
1 2 3 | foo 1 2 |
xml.etree.elementtree与lxml
这是两个最常用的库中的一些优点,在选择它们之前,我会先了解它们。
xml.etree.element树:LXML