使用 Python 中的 ElementTree 解析 XML 中的 xsi:type
Parse xsi:type in XML with ElementTree in Python
我正在尝试连接到 RESTful API,但在构建 XML 请求时遇到问题,因为我正在使用 Elementree 库。
我有一个 XML 我必须在请求中发送的示例。从该示例构建模型,然后通过代码编写不同的属性。但是输出 XML 与我给出的示例并不完全相同,我无法连接到 API.
这是我的例子:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetLoc xmlns="http://abc/Getloc">
<request>
<Access>
<string xmlns="http://bcd/Arrays"></string>
</Access>
<Details xsi:type="Request">
<Postcode ></Postcode >
</Details>
<UserConsent>Yes</UserConsent>
</request>
</GetLoc>
</soap:Body>
</soap:Envelope>
这是我的代码:
tree = ET.parse('model.xml')
root = tree.getroot()
ns = {'loc':'http://abc/Getloc',\
'arr':http://bcd/Arrays',\
'soapenv':'http://schemas.xmlsoap.org/soap/envelope/', \
'xsi':"http://www.w3.org/2001/XMLSchema-instance", \
xsd': "http://www.w3.org/2001/XMLSchema"}
tree.find('.//arr:string', ns).text = 'THC'
tree.find('.//Postcode ', ns).text = '15478'
这是输出 XML (SOAP):
<ns0:Envelope xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://abc/Getloc" xmlns:ns2="http://bcd/Arrays" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ns0:Body>
<ns1:GetLoc >
<ns1:request>
<ns1:Access>
<ns2:string>THC</ns2:string>
</ns1:Access>
<ns1:Details xsi:type="Request">
<ns1:Postcode >15478</ns1:Postcode >
</ns1:Details>
<ns1:UserConsent>Yes</ns1:UserConsent>
</ns1:request>
</ns1:GetLoc >
</ns0:Body>
</ns0:Envelope>
使用示例(上面第一个)连接到 API 时没有问题。但是对于第二个我得到了错误:
" status="Service Not Found. The request may have been sent to an invalid URL, or intended for an unsupported operation." xmlns:l7="http://www.layer7tech.com/ws/policy/fault"/>"
两个 XML 都发送到相同的 URL,具有相同的 headers 和身份验证。我看到两个 XML 等价,所以我期待相同的行为。我不明白为什么它不起作用。
编辑:输出 XML 需要像
<ns0:Envelope xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://abc/Getloc" xmlns:ns2="http://bcd/Arrays" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ns0:Body>
<ns1:GetLoc >
<ns1:request>
<ns1:Access>
<ns2:string>THC</ns2:string>
</ns1:Access>
<ns1:Details xsi:type="ns1:Request">
<ns1:Postcode >15478</ns1:Postcode >
</ns1:Details>
<ns1:UserConsent>Yes</ns1:UserConsent>
</ns1:request>
</ns1:GetLoc >
</ns0:Body>
</ns0:Envelope>
但是我不知道怎么改代码得到:xsi:type="ns1:Request"
最后我自己找到了解决方案。
解决方案在 here (an incredibly complete article), since I was already using ElementTree. You may find other solutions like using lxml 库中。
因此,对于 ElementTree,我只需要使用我自己的解析器而不是标准 ElementTree.parse('file.xml')。
xsi 属性名称由解析器处理,但解析器不知道该属性恰好也包含限定名称,因此保持原样。为了能够处理这种格式,您可以使用知道如何处理特定属性和元素的自定义解析器,或者跟踪每个元素的前缀映射。
要执行后者,您可以使用 iterparse 解析器,并要求它报告“start-ns”和“end-ns”事件。以下代码段将 ns_map 属性添加到每个元素,其中包含适用于该特定元素的 prefix/URI 映射:
def parse_map(file):
events = "start", "start-ns", "end-ns"
root = None
ns_map = []
for event, elem in ET.iterparse(file, events):
if event == "start-ns":
ns_map.append(elem)
elif event == "end-ns":
ns_map.pop()
elif event == "start":
if root is None:
root = elem
elem.ns_map = dict(ns_map)
return ET.ElementTree(root)
我正在尝试连接到 RESTful API,但在构建 XML 请求时遇到问题,因为我正在使用 Elementree 库。
我有一个 XML 我必须在请求中发送的示例。从该示例构建模型,然后通过代码编写不同的属性。但是输出 XML 与我给出的示例并不完全相同,我无法连接到 API.
这是我的例子:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetLoc xmlns="http://abc/Getloc">
<request>
<Access>
<string xmlns="http://bcd/Arrays"></string>
</Access>
<Details xsi:type="Request">
<Postcode ></Postcode >
</Details>
<UserConsent>Yes</UserConsent>
</request>
</GetLoc>
</soap:Body>
</soap:Envelope>
这是我的代码:
tree = ET.parse('model.xml')
root = tree.getroot()
ns = {'loc':'http://abc/Getloc',\
'arr':http://bcd/Arrays',\
'soapenv':'http://schemas.xmlsoap.org/soap/envelope/', \
'xsi':"http://www.w3.org/2001/XMLSchema-instance", \
xsd': "http://www.w3.org/2001/XMLSchema"}
tree.find('.//arr:string', ns).text = 'THC'
tree.find('.//Postcode ', ns).text = '15478'
这是输出 XML (SOAP):
<ns0:Envelope xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://abc/Getloc" xmlns:ns2="http://bcd/Arrays" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ns0:Body>
<ns1:GetLoc >
<ns1:request>
<ns1:Access>
<ns2:string>THC</ns2:string>
</ns1:Access>
<ns1:Details xsi:type="Request">
<ns1:Postcode >15478</ns1:Postcode >
</ns1:Details>
<ns1:UserConsent>Yes</ns1:UserConsent>
</ns1:request>
</ns1:GetLoc >
</ns0:Body>
</ns0:Envelope>
使用示例(上面第一个)连接到 API 时没有问题。但是对于第二个我得到了错误:
" status="Service Not Found. The request may have been sent to an invalid URL, or intended for an unsupported operation." xmlns:l7="http://www.layer7tech.com/ws/policy/fault"/>"
两个 XML 都发送到相同的 URL,具有相同的 headers 和身份验证。我看到两个 XML 等价,所以我期待相同的行为。我不明白为什么它不起作用。
编辑:输出 XML 需要像
<ns0:Envelope xmlns:ns0="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="http://abc/Getloc" xmlns:ns2="http://bcd/Arrays" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ns0:Body>
<ns1:GetLoc >
<ns1:request>
<ns1:Access>
<ns2:string>THC</ns2:string>
</ns1:Access>
<ns1:Details xsi:type="ns1:Request">
<ns1:Postcode >15478</ns1:Postcode >
</ns1:Details>
<ns1:UserConsent>Yes</ns1:UserConsent>
</ns1:request>
</ns1:GetLoc >
</ns0:Body>
</ns0:Envelope>
但是我不知道怎么改代码得到:xsi:type="ns1:Request"
最后我自己找到了解决方案。
解决方案在 here (an incredibly complete article), since I was already using ElementTree. You may find other solutions like using lxml 库中。
因此,对于 ElementTree,我只需要使用我自己的解析器而不是标准 ElementTree.parse('file.xml')。
xsi 属性名称由解析器处理,但解析器不知道该属性恰好也包含限定名称,因此保持原样。为了能够处理这种格式,您可以使用知道如何处理特定属性和元素的自定义解析器,或者跟踪每个元素的前缀映射。 要执行后者,您可以使用 iterparse 解析器,并要求它报告“start-ns”和“end-ns”事件。以下代码段将 ns_map 属性添加到每个元素,其中包含适用于该特定元素的 prefix/URI 映射:
def parse_map(file):
events = "start", "start-ns", "end-ns"
root = None
ns_map = []
for event, elem in ET.iterparse(file, events):
if event == "start-ns":
ns_map.append(elem)
elif event == "end-ns":
ns_map.pop()
elif event == "start":
if root is None:
root = elem
elem.ns_map = dict(ns_map)
return ET.ElementTree(root)