Python:解析 XML 自动添加所有 key/value 对
Python: Parsing XML autoadd all key/value pairs
找了很久也试了很多!但是对于这种完全简单的情况,我无法敞开心扉。我需要说我是一个 python 新手,但是一个非常好的 bash 编码器 ;o) 我已经用 python 编写了一些代码,但也许还有很多我需要学习的东西所以不要对我太苛刻 ;o) 我愿意学习,我阅读了 python 文档和许多示例,并自己尝试了很多,但现在我正处于一个我在黑暗中采摘的地步..
我将提供的内容解析为 XML。它大约有 20-50 MB 大。
我的 XML 示例:
<MAIN>
<NOSUBEL>abcd</NOSUBEL>
<NOSUBEL2>adasdasa</NOSUBEL2>
<MULTISUB>
<WHATEVER>
<ANOTHERSUBEL>
<ANOTHERONE>
(how many levels can not be said / can change)
</ANOTHERONE>
</ANOTHERSUBEL>
</WHATEVER>
</MULTISUB>..
<SUBEL2>
<FOO>abcdefg</FOO>
</SUBEL2>
<NOSUBEL3>abc</NOSUBEL3>
...
and so on
</MAIN>
这是解析的主要部分(如果您需要更多详细信息,请询问):
from lxml import etree
resp = my.request(some call args)
xml = etree.XML(resp)
for element in xml.findall(".//MAIN"):
# this works fine but is not generic enough:
my_dict = OrderedDict()
for only1sub in element.iter(tag="SUBEL2"):
for i in only1sub:
my_dict[i.tag] = i.text
这只适用于 1 个子元素,但这意味着我需要知道树中哪个有子元素,哪个没有。这可能会在将来更改或添加。
另一个问题是 MULTISUB。使用上面的代码,我只能解析到第一个标签。
目标
我想要实现的是-充其量:
A) 拥有一个能够解析整个 XML 内容的函数/代码片段,如果有子元素(例如 "if len(x)" 或其他),则解析到下一个级别,直到你达到了没有 subelement/tree 的水平。然后继续B)
B) 对于找到的每个没有子元素的 XML 标签,我想用标签名称和标签文本更新字典。
C) 我想对所有可用元素执行此操作 - 标签和直接子标签名称(例如 "NOSUBEL2" 或 "MULTISUB")将 而不是 更改(经常),因此可以将它们用作解析的起点。
到目前为止,我尝试的是链接几个循环,例如 for 和 while 以及 for again 等等,但没有完全成功。我还深入研究了 python 生成器,因为我认为我可以使用 next() 函数做一些事情,但也什么也做不了。但同样,我可能不具备正确使用它们的知识,所以我很高兴得到每一个答案..
我相信最后我需要的东西很容易。我只想从标签名称和标签内容中获取键值对,这不是那么难吗?非常感谢任何帮助..
你能帮我实现目标吗?
(感谢您阅读到这里!)
您正在寻找的是 recursion - 一种 运行 在某些过程 内部 该过程的技术,但对于子问题原来的问题。在这种情况下:对于某些元素的每个子元素 运行 此过程(如果有子元素)或使用元素的标签名称和文本更新您的字典。
我假设最后你有兴趣让字典 (OrderedDict
) 包含 "flat representation" 整个元素树的叶子'(没有子元素的节点)标签 names/text 值,这在你的情况下,打印出来,看起来像这样:
OrderedDict([('NOSUBEL', 'abcd'), ('NOSUBEL2', 'adasdasa'), ('ANOTHERONE', '(how many levels can not be said / can change)'), ('FOO', 'abcdefg'), ('NOSUBEL3', 'abc')])
通常,您会定义一个函数,该函数将使用您的部分数据(在本例中:子元素,如果有的话)调用自身或执行某些操作(在本例中:更新字典的某些实例)。
由于我不知道 my.request
调用背后的详细信息,因此我已根据您提供的内容通过解析包含有效 XML 的字符串来替换它。只需替换构建 tree
对象。
resp = """<MAIN>
<NOSUBEL>abcd</NOSUBEL>
<NOSUBEL2>adasdasa</NOSUBEL2>
<MULTISUB>
<WHATEVER>
<ANOTHERSUBEL>
<ANOTHERONE>(how many levels can not be said / can change)</ANOTHERONE>
</ANOTHERSUBEL>
</WHATEVER>
</MULTISUB>
<SUBEL2>
<FOO>abcdefg</FOO>
</SUBEL2>
<NOSUBEL3>abc</NOSUBEL3>
</MAIN>"""
from collections import OrderedDict
from lxml import etree
def update_dict(element, my_dict):
# lxml defines "length" of the element as number of its children.
if len(element): # If "length" is other than 0.
for subelement in element:
# That's where the recursion happens. We're calling the same
# function for a subelement of the element.
update_dict(subelement, my_dict)
else: # Otherwise, subtree is a leaf.
my_dict[element.tag] = element.text
if __name__ == "__main__":
# Change/amend it with your my.request call.
tree = etree.XML(resp) # That's a <MAIN> element, too.
my_dict = OrderedDict()
# That's the first invocation of the procedure. We're passing entire
# tree and instance of dictionary.
update_dict(tree, my_dict)
print(my_dict) # Just to see that dictionarty was filled with values.
如您所见,我没有在代码中使用任何标签名称(当然 XML 源代码除外)。
我还添加了 collections
缺少的导入。
找了很久也试了很多!但是对于这种完全简单的情况,我无法敞开心扉。我需要说我是一个 python 新手,但是一个非常好的 bash 编码器 ;o) 我已经用 python 编写了一些代码,但也许还有很多我需要学习的东西所以不要对我太苛刻 ;o) 我愿意学习,我阅读了 python 文档和许多示例,并自己尝试了很多,但现在我正处于一个我在黑暗中采摘的地步..
我将提供的内容解析为 XML。它大约有 20-50 MB 大。 我的 XML 示例:
<MAIN>
<NOSUBEL>abcd</NOSUBEL>
<NOSUBEL2>adasdasa</NOSUBEL2>
<MULTISUB>
<WHATEVER>
<ANOTHERSUBEL>
<ANOTHERONE>
(how many levels can not be said / can change)
</ANOTHERONE>
</ANOTHERSUBEL>
</WHATEVER>
</MULTISUB>..
<SUBEL2>
<FOO>abcdefg</FOO>
</SUBEL2>
<NOSUBEL3>abc</NOSUBEL3>
...
and so on
</MAIN>
这是解析的主要部分(如果您需要更多详细信息,请询问):
from lxml import etree
resp = my.request(some call args)
xml = etree.XML(resp)
for element in xml.findall(".//MAIN"):
# this works fine but is not generic enough:
my_dict = OrderedDict()
for only1sub in element.iter(tag="SUBEL2"):
for i in only1sub:
my_dict[i.tag] = i.text
这只适用于 1 个子元素,但这意味着我需要知道树中哪个有子元素,哪个没有。这可能会在将来更改或添加。 另一个问题是 MULTISUB。使用上面的代码,我只能解析到第一个标签。
目标
我想要实现的是-充其量:
A) 拥有一个能够解析整个 XML 内容的函数/代码片段,如果有子元素(例如 "if len(x)" 或其他),则解析到下一个级别,直到你达到了没有 subelement/tree 的水平。然后继续B)
B) 对于找到的每个没有子元素的 XML 标签,我想用标签名称和标签文本更新字典。
C) 我想对所有可用元素执行此操作 - 标签和直接子标签名称(例如 "NOSUBEL2" 或 "MULTISUB")将 而不是 更改(经常),因此可以将它们用作解析的起点。
到目前为止,我尝试的是链接几个循环,例如 for 和 while 以及 for again 等等,但没有完全成功。我还深入研究了 python 生成器,因为我认为我可以使用 next() 函数做一些事情,但也什么也做不了。但同样,我可能不具备正确使用它们的知识,所以我很高兴得到每一个答案..
我相信最后我需要的东西很容易。我只想从标签名称和标签内容中获取键值对,这不是那么难吗?非常感谢任何帮助..
你能帮我实现目标吗?
(感谢您阅读到这里!)
您正在寻找的是 recursion - 一种 运行 在某些过程 内部 该过程的技术,但对于子问题原来的问题。在这种情况下:对于某些元素的每个子元素 运行 此过程(如果有子元素)或使用元素的标签名称和文本更新您的字典。
我假设最后你有兴趣让字典 (OrderedDict
) 包含 "flat representation" 整个元素树的叶子'(没有子元素的节点)标签 names/text 值,这在你的情况下,打印出来,看起来像这样:
OrderedDict([('NOSUBEL', 'abcd'), ('NOSUBEL2', 'adasdasa'), ('ANOTHERONE', '(how many levels can not be said / can change)'), ('FOO', 'abcdefg'), ('NOSUBEL3', 'abc')])
通常,您会定义一个函数,该函数将使用您的部分数据(在本例中:子元素,如果有的话)调用自身或执行某些操作(在本例中:更新字典的某些实例)。
由于我不知道 my.request
调用背后的详细信息,因此我已根据您提供的内容通过解析包含有效 XML 的字符串来替换它。只需替换构建 tree
对象。
resp = """<MAIN>
<NOSUBEL>abcd</NOSUBEL>
<NOSUBEL2>adasdasa</NOSUBEL2>
<MULTISUB>
<WHATEVER>
<ANOTHERSUBEL>
<ANOTHERONE>(how many levels can not be said / can change)</ANOTHERONE>
</ANOTHERSUBEL>
</WHATEVER>
</MULTISUB>
<SUBEL2>
<FOO>abcdefg</FOO>
</SUBEL2>
<NOSUBEL3>abc</NOSUBEL3>
</MAIN>"""
from collections import OrderedDict
from lxml import etree
def update_dict(element, my_dict):
# lxml defines "length" of the element as number of its children.
if len(element): # If "length" is other than 0.
for subelement in element:
# That's where the recursion happens. We're calling the same
# function for a subelement of the element.
update_dict(subelement, my_dict)
else: # Otherwise, subtree is a leaf.
my_dict[element.tag] = element.text
if __name__ == "__main__":
# Change/amend it with your my.request call.
tree = etree.XML(resp) # That's a <MAIN> element, too.
my_dict = OrderedDict()
# That's the first invocation of the procedure. We're passing entire
# tree and instance of dictionary.
update_dict(tree, my_dict)
print(my_dict) # Just to see that dictionarty was filled with values.
如您所见,我没有在代码中使用任何标签名称(当然 XML 源代码除外)。
我还添加了 collections
缺少的导入。