使用 xpath 将 XML 文件解析为字典
parse an XML file into a dictionary with xpath
前提是我有一个 XML 响应:
from lxml import etree
XML_string= '''<div type="description" xml:base="elpais.es" xml:lang="es" xml:id="f0910b98">
<p xml:id="_657a490035" n="0001">blabla1</p>
<p xml:id="_657a490036" n="0002">blabla2. bla bla 2.</p>
<p xml:id="_657a490037" n="0003">blabla3.blabla3</p>
<p xml:id="_657a490038" n="0004">bla4</p></div>'''
我解析如下:
parser = etree.XMLParser(resolve_entities=False, strip_cdata=False, recover=True, ns_clean=True)
XML_tree = etree.fromstring(XML_string.encode() , parser=parser)
我在将 XML 转换成字典后如下:
result_list = [{'id':"_657a490035", 'n':'001', 'text':'blabla1'},
{'id':"_657a490036", 'n':'002', 'text':'blabla2'}
etc
我非常接近看到这个:
all_paras = XML_tree.xpath('.//p[@xml:id]')
result_list = []
for para in all_paras:
result_list.append({'text':para.text,'id':'id?','n':'n??'})
我不知道如何访问节点参数中的属性内容。
有帮助吗?
编辑:
如果你这样做,请注意:
for para in all_paras:
print(para.attrib)
我得到了奇怪的字典:
'{http://www.w3.org/XML/1998/namespace}id': '_657a490035', 'n': '0001'}
出于某种原因 xml:id 进入这个:{http://www.w3.org/XML/1998/namespace}id'
不幸的是,您正在与命名空间纠缠在一起。处理该问题的一种方法是使用 local-name()
:
for para in all_paras:
#I simplified the id attribute value a bit, for simplicity
result_list.append({'id':para.xpath('./@*[local-name()="id"]')[0],'n':para.xpath('./@*[local-name()="n"]')[0],'text':para.text})
result_list
输出:
[{'id': '1', 'n': '0001', 'text': 'blabla1'},
{'id': '2', 'n': '0002', 'text': 'blabla2. bla bla 2.'},
{'id': '3', 'n': '0003', 'text': 'blabla3.blabla3'},
{'id': '4', 'n': '0004', 'text': 'bla4'}]
xml:lang
、xml:id
和 xml:base
中的 xml:
是 a special namespace prefix,绑定到 http://www.w3.org/XML/1998/namespace
命名空间 URI。与任何其他前缀不同,它不需要在 XML 文档中声明。
您可以通过 xpath()
获取 xml:id
属性的值,如下所示:
for para in all_paras:
result_list.append({'text': para.text, 'id': para.xpath('@xml:id')[0]})
您也可以使用 get()
方法,但是您必须提供用大括号括起来的完整命名空间 URI:
for para in all_paras:
result_list.append({'text': para.text, 'id': para.get("{http://www.w3.org/XML/1998/namespace}id")})
前提是我有一个 XML 响应:
from lxml import etree
XML_string= '''<div type="description" xml:base="elpais.es" xml:lang="es" xml:id="f0910b98">
<p xml:id="_657a490035" n="0001">blabla1</p>
<p xml:id="_657a490036" n="0002">blabla2. bla bla 2.</p>
<p xml:id="_657a490037" n="0003">blabla3.blabla3</p>
<p xml:id="_657a490038" n="0004">bla4</p></div>'''
我解析如下:
parser = etree.XMLParser(resolve_entities=False, strip_cdata=False, recover=True, ns_clean=True)
XML_tree = etree.fromstring(XML_string.encode() , parser=parser)
我在将 XML 转换成字典后如下:
result_list = [{'id':"_657a490035", 'n':'001', 'text':'blabla1'},
{'id':"_657a490036", 'n':'002', 'text':'blabla2'}
etc
我非常接近看到这个:
all_paras = XML_tree.xpath('.//p[@xml:id]')
result_list = []
for para in all_paras:
result_list.append({'text':para.text,'id':'id?','n':'n??'})
我不知道如何访问节点参数中的属性内容。
有帮助吗?
编辑: 如果你这样做,请注意:
for para in all_paras:
print(para.attrib)
我得到了奇怪的字典:
'{http://www.w3.org/XML/1998/namespace}id': '_657a490035', 'n': '0001'}
出于某种原因 xml:id 进入这个:{http://www.w3.org/XML/1998/namespace}id'
不幸的是,您正在与命名空间纠缠在一起。处理该问题的一种方法是使用 local-name()
:
for para in all_paras:
#I simplified the id attribute value a bit, for simplicity
result_list.append({'id':para.xpath('./@*[local-name()="id"]')[0],'n':para.xpath('./@*[local-name()="n"]')[0],'text':para.text})
result_list
输出:
[{'id': '1', 'n': '0001', 'text': 'blabla1'},
{'id': '2', 'n': '0002', 'text': 'blabla2. bla bla 2.'},
{'id': '3', 'n': '0003', 'text': 'blabla3.blabla3'},
{'id': '4', 'n': '0004', 'text': 'bla4'}]
xml:lang
、xml:id
和 xml:base
中的 xml:
是 a special namespace prefix,绑定到 http://www.w3.org/XML/1998/namespace
命名空间 URI。与任何其他前缀不同,它不需要在 XML 文档中声明。
您可以通过 xpath()
获取 xml:id
属性的值,如下所示:
for para in all_paras:
result_list.append({'text': para.text, 'id': para.xpath('@xml:id')[0]})
您也可以使用 get()
方法,但是您必须提供用大括号括起来的完整命名空间 URI:
for para in all_paras:
result_list.append({'text': para.text, 'id': para.get("{http://www.w3.org/XML/1998/namespace}id")})