如何通过 defusedxml 从 AWS SQS API 字节 xml 字符串响应中读取所有行,而不仅仅是第一行?
How to read all lines from AWS SQS API bytes xml string response via defusedxml, instead of just the first one?
代码:
from defusedxml import ElementTree as etree
s = b'<?xml version="1.0"?><GetQueueAttributesResponse xmlns="http://queue.amazonaws.com/doc/2012-11-05/"><GetQueueAttributesResult><Attribute><Name>ApproximateNumberOfMessages</Name><Value>2</Value></Attribute></GetQueueAttributesResult><ResponseMetadata><RequestId>xxxx</RequestId></ResponseMetadata></GetQueueAttributesResponse>'
print(etree.fromstring(s))
预期输出:
应显示完整的 xml 数据(与输入相同),以便进一步分析。
实际输出:
仅显示第一行。
<Element '{http://queue.amazonaws.com/doc/2012-11-05/}GetQueueAttributesResponse' at 0x09B50720>
这是它读取的所有数据。
因为我在这个输出上尝试了像 findall()
和 getchildren()
这样的函数,它 returns 没有进一步的。
如何解决这个问题?
要么
如果有类似方法的替代库,请提出建议。
或者,如果有任何库可以直接将此类 xml 数据转换为 json/dict
,那将非常有帮助。
但是,它应该将数据转换为可读形式,而不是像 xmltodict
这样的东西,它给出奇怪的 OrderedDicts
.
注意:
建议使用哪个库也需要安全,不像 xml 那样有漏洞。
from defusedxml import ElementTree as etree
tree = etree.parse('file.xml')
root = tree.getroot()
# gives the below output
<Element '{http://queue.amazonaws.com/doc/2012-11-05/}GetQueueAttributesResponse' at 0x1107c7b88>
root.findall('.//{http://queue.amazonaws.com/doc/2012-11-05/}Attribute')
# gives the below output
[<Element '{http://queue.amazonaws.com/doc/2012-11-05/}Attribute' at 0x1107c7c28>]
但我不得不将 xml 另存为文件。
内联更新 xml:
与文件另存为单独文件时的工作方式相同。
s = b'<?xml version="1.0"?><GetQueueAttributesResponse xmlns="http://queue.amazonaws.com/doc/2012-11-05/"><GetQueueAttributesResult><Attribute><Name>ApproximateNumberOfMessages</Name><Value>2</Value></Attribute></GetQueueAttributesResult><ResponseMetadata><RequestId>xxxx</RequestId></ResponseMetadata></GetQueueAttributesResponse>'
etree.fromstring(s).findall('.//{http://queue.amazonaws.com/doc/2012-11-05/}Attribute')
参考:
能够根据以上示例和参考形成简洁的逻辑。
from defusedxml import ElementTree as ETree
def parse_xml(xml, tag):
xml_tree = ETree.fromstring(xml)
xml_tree_str = str(xml_tree)
xpath = xml_tree_str[xml_tree_str.find("{"): xml_tree_str.find("}") + 1]
return [
{attr.tag[attr.tag.find("}") + 1 :]: attr.text for attr in element}
for element in xml_tree.findall(f".//{xpath}{tag}")
]
from unittest import TestCase
class TestParseXML(TestCase):
def test_parse_xml(self):
xml = b"""<?xml version="1.0"?>
<XResponse xmlns="http://queue.amazonaws.com/doc/2012-11-05/">
<XResult>
<XResultEntry>
<Id>1</Id>
<Name>one</Name>
</XResultEntry>
<XResultEntry>
<Id>2</Id>
<Name>two</Name>
</XResultEntry>
</XResult>
<ResponseMetadata>
<RequestId>testreqid</RequestId>
</ResponseMetadata>
</XResponse>"""
data = parse_xml(xml, "XResultEntry")
self.assertEqual(data, [{"Id": "1", "Name": "one"}, {"Id": "2", "Name": "two"}])
代码:
from defusedxml import ElementTree as etree
s = b'<?xml version="1.0"?><GetQueueAttributesResponse xmlns="http://queue.amazonaws.com/doc/2012-11-05/"><GetQueueAttributesResult><Attribute><Name>ApproximateNumberOfMessages</Name><Value>2</Value></Attribute></GetQueueAttributesResult><ResponseMetadata><RequestId>xxxx</RequestId></ResponseMetadata></GetQueueAttributesResponse>'
print(etree.fromstring(s))
预期输出:
应显示完整的 xml 数据(与输入相同),以便进一步分析。
实际输出:
仅显示第一行。
<Element '{http://queue.amazonaws.com/doc/2012-11-05/}GetQueueAttributesResponse' at 0x09B50720>
这是它读取的所有数据。
因为我在这个输出上尝试了像 findall()
和 getchildren()
这样的函数,它 returns 没有进一步的。
如何解决这个问题? 要么 如果有类似方法的替代库,请提出建议。
或者,如果有任何库可以直接将此类 xml 数据转换为 json/dict
,那将非常有帮助。
但是,它应该将数据转换为可读形式,而不是像 xmltodict
这样的东西,它给出奇怪的 OrderedDicts
.
注意: 建议使用哪个库也需要安全,不像 xml 那样有漏洞。
from defusedxml import ElementTree as etree
tree = etree.parse('file.xml')
root = tree.getroot()
# gives the below output
<Element '{http://queue.amazonaws.com/doc/2012-11-05/}GetQueueAttributesResponse' at 0x1107c7b88>
root.findall('.//{http://queue.amazonaws.com/doc/2012-11-05/}Attribute')
# gives the below output
[<Element '{http://queue.amazonaws.com/doc/2012-11-05/}Attribute' at 0x1107c7c28>]
但我不得不将 xml 另存为文件。
内联更新 xml: 与文件另存为单独文件时的工作方式相同。
s = b'<?xml version="1.0"?><GetQueueAttributesResponse xmlns="http://queue.amazonaws.com/doc/2012-11-05/"><GetQueueAttributesResult><Attribute><Name>ApproximateNumberOfMessages</Name><Value>2</Value></Attribute></GetQueueAttributesResult><ResponseMetadata><RequestId>xxxx</RequestId></ResponseMetadata></GetQueueAttributesResponse>'
etree.fromstring(s).findall('.//{http://queue.amazonaws.com/doc/2012-11-05/}Attribute')
参考:
能够根据以上示例和参考形成简洁的逻辑。
from defusedxml import ElementTree as ETree
def parse_xml(xml, tag):
xml_tree = ETree.fromstring(xml)
xml_tree_str = str(xml_tree)
xpath = xml_tree_str[xml_tree_str.find("{"): xml_tree_str.find("}") + 1]
return [
{attr.tag[attr.tag.find("}") + 1 :]: attr.text for attr in element}
for element in xml_tree.findall(f".//{xpath}{tag}")
]
from unittest import TestCase
class TestParseXML(TestCase):
def test_parse_xml(self):
xml = b"""<?xml version="1.0"?>
<XResponse xmlns="http://queue.amazonaws.com/doc/2012-11-05/">
<XResult>
<XResultEntry>
<Id>1</Id>
<Name>one</Name>
</XResultEntry>
<XResultEntry>
<Id>2</Id>
<Name>two</Name>
</XResultEntry>
</XResult>
<ResponseMetadata>
<RequestId>testreqid</RequestId>
</ResponseMetadata>
</XResponse>"""
data = parse_xml(xml, "XResultEntry")
self.assertEqual(data, [{"Id": "1", "Name": "one"}, {"Id": "2", "Name": "two"}])