如何用 Python 解析 SOAP XML?
How to parse SOAP XML with Python?
目标:
获取 <Name>
标签内的值并打印出来。 下面简化了 XML。
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soap:Body>
<GetStartEndPointResponse xmlns="http://www.etis.fskab.se/v1.0/ETISws">
<GetStartEndPointResult>
<Code>0</Code>
<Message />
<StartPoints>
<Point>
<Id>545</Id>
<Name>Get Me</Name>
<Type>sometype</Type>
<X>333</X>
<Y>222</Y>
</Point>
<Point>
<Id>634</Id>
<Name>Get me too</Name>
<Type>sometype</Type>
<X>555</X>
<Y>777</Y>
</Point>
</StartPoints>
</GetStartEndPointResult>
</GetStartEndPointResponse>
</soap:Body>
</soap:Envelope>
尝试:
import requests
from xml.etree import ElementTree
response = requests.get('http://www.labs.skanetrafiken.se/v2.2/querystation.asp?inpPointfr=yst')
# XML parsing here
dom = ElementTree.fromstring(response.text)
names = dom.findall('*/Name')
for name in names:
print(name.text)
我读过其他人推荐 zeep
解析 soap xml 但我发现很难理解。
这里的问题是处理 XML 命名空间:
import requests
from xml.etree import ElementTree
response = requests.get('http://www.labs.skanetrafiken.se/v2.2/querystation.asp?inpPointfr=yst')
# define namespace mappings to use as shorthand below
namespaces = {
'soap': 'http://schemas.xmlsoap.org/soap/envelope/',
'a': 'http://www.etis.fskab.se/v1.0/ETISws',
}
dom = ElementTree.fromstring(response.content)
# reference the namespace mappings here by `<name>:`
names = dom.findall(
'./soap:Body'
'/a:GetStartEndPointResponse'
'/a:GetStartEndPointResult'
'/a:StartPoints'
'/a:Point'
'/a:Name',
namespaces,
)
for name in names:
print(name.text)
命名空间分别来自 Envelope
和 GetStartEndPointResponse
节点上的 xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
和 xmlns="http://www.etis.fskab.se/v1.0/ETISws"
属性。
请记住,命名空间由父节点的所有子节点继承,即使命名空间未在子节点的标记上明确指定为 <namespace:tag>
。
注意:我必须使用 response.content
而不是 response.body
。
一个老问题,但值得一提的是此任务的另一个选项。
我喜欢使用 xmltodict
(Github) XML
到 python 字典的轻量级转换器。
将您的 soap 响应放入名为 stack
的变量中
用xmltodict.parse
解析
In [48]: stack_d = xmltodict.parse(stack)
查看结果:
In [49]: stack_d
Out[49]:
OrderedDict([('soap:Envelope',
OrderedDict([('@xmlns:soap',
'http://schemas.xmlsoap.org/soap/envelope/'),
('@xmlns:xsd', 'http://www.w3.org/2001/XMLSchema'),
('@xmlns:xsi',
'http://www.w3.org/2001/XMLSchema-instance'),
('soap:Body',
OrderedDict([('GetStartEndPointResponse',
OrderedDict([('@xmlns',
'http://www.etis.fskab.se/v1.0/ETISws'),
('GetStartEndPointResult',
OrderedDict([('Code',
'0'),
('Message',
None),
('StartPoints',
OrderedDict([('Point',
[OrderedDict([('Id',
'545'),
('Name',
'Get Me'),
('Type',
'sometype'),
('X',
'333'),
('Y',
'222')]),
OrderedDict([('Id',
'634'),
('Name',
'Get me too'),
('Type',
'sometype'),
('X',
'555'),
('Y',
'777')])])]))]))]))]))]))])
此时就变得像浏览python字典一样简单
In [50]: stack_d['soap:Envelope']['soap:Body']['GetStartEndPointResponse']['GetStartEndPointResult']['StartPoints']['Point']
Out[50]:
[OrderedDict([('Id', '545'),
('Name', 'Get Me'),
('Type', 'sometype'),
('X', '333'),
('Y', '222')]),
OrderedDict([('Id', '634'),
('Name', 'Get me too'),
('Type', 'sometype'),
('X', '555'),
('Y', '777')])]
再次回答一个老问题,但我认为这个解决方案值得分享。
使用 BeautifulSoup 对我来说是小菜一碟。您可以安装 BeautifulSoup 形式 here.
from bs4 import BeautifulSoup
xml = BeautifulSoup(xml_string, 'xml')
xml.find('soap:Body') # to get the soup:Body tag.
xml.find('X') # for X tag
只需将所有 'soap:' 和其他名称空间前缀(例如 'a:' 替换为 ''(只需删除它们并使其成为 non-SOAP xml 文件)
new_response = response.text.replace('soap:', '').replace('a:', '')
那你就可以正常进行了。
目标:
获取 <Name>
标签内的值并打印出来。 下面简化了 XML。
<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soap:Body>
<GetStartEndPointResponse xmlns="http://www.etis.fskab.se/v1.0/ETISws">
<GetStartEndPointResult>
<Code>0</Code>
<Message />
<StartPoints>
<Point>
<Id>545</Id>
<Name>Get Me</Name>
<Type>sometype</Type>
<X>333</X>
<Y>222</Y>
</Point>
<Point>
<Id>634</Id>
<Name>Get me too</Name>
<Type>sometype</Type>
<X>555</X>
<Y>777</Y>
</Point>
</StartPoints>
</GetStartEndPointResult>
</GetStartEndPointResponse>
</soap:Body>
</soap:Envelope>
尝试:
import requests
from xml.etree import ElementTree
response = requests.get('http://www.labs.skanetrafiken.se/v2.2/querystation.asp?inpPointfr=yst')
# XML parsing here
dom = ElementTree.fromstring(response.text)
names = dom.findall('*/Name')
for name in names:
print(name.text)
我读过其他人推荐 zeep
解析 soap xml 但我发现很难理解。
这里的问题是处理 XML 命名空间:
import requests
from xml.etree import ElementTree
response = requests.get('http://www.labs.skanetrafiken.se/v2.2/querystation.asp?inpPointfr=yst')
# define namespace mappings to use as shorthand below
namespaces = {
'soap': 'http://schemas.xmlsoap.org/soap/envelope/',
'a': 'http://www.etis.fskab.se/v1.0/ETISws',
}
dom = ElementTree.fromstring(response.content)
# reference the namespace mappings here by `<name>:`
names = dom.findall(
'./soap:Body'
'/a:GetStartEndPointResponse'
'/a:GetStartEndPointResult'
'/a:StartPoints'
'/a:Point'
'/a:Name',
namespaces,
)
for name in names:
print(name.text)
命名空间分别来自 Envelope
和 GetStartEndPointResponse
节点上的 xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
和 xmlns="http://www.etis.fskab.se/v1.0/ETISws"
属性。
请记住,命名空间由父节点的所有子节点继承,即使命名空间未在子节点的标记上明确指定为 <namespace:tag>
。
注意:我必须使用 response.content
而不是 response.body
。
一个老问题,但值得一提的是此任务的另一个选项。
我喜欢使用 xmltodict
(Github) XML
到 python 字典的轻量级转换器。
将您的 soap 响应放入名为 stack
用xmltodict.parse
In [48]: stack_d = xmltodict.parse(stack)
查看结果:
In [49]: stack_d
Out[49]:
OrderedDict([('soap:Envelope',
OrderedDict([('@xmlns:soap',
'http://schemas.xmlsoap.org/soap/envelope/'),
('@xmlns:xsd', 'http://www.w3.org/2001/XMLSchema'),
('@xmlns:xsi',
'http://www.w3.org/2001/XMLSchema-instance'),
('soap:Body',
OrderedDict([('GetStartEndPointResponse',
OrderedDict([('@xmlns',
'http://www.etis.fskab.se/v1.0/ETISws'),
('GetStartEndPointResult',
OrderedDict([('Code',
'0'),
('Message',
None),
('StartPoints',
OrderedDict([('Point',
[OrderedDict([('Id',
'545'),
('Name',
'Get Me'),
('Type',
'sometype'),
('X',
'333'),
('Y',
'222')]),
OrderedDict([('Id',
'634'),
('Name',
'Get me too'),
('Type',
'sometype'),
('X',
'555'),
('Y',
'777')])])]))]))]))]))]))])
此时就变得像浏览python字典一样简单
In [50]: stack_d['soap:Envelope']['soap:Body']['GetStartEndPointResponse']['GetStartEndPointResult']['StartPoints']['Point']
Out[50]:
[OrderedDict([('Id', '545'),
('Name', 'Get Me'),
('Type', 'sometype'),
('X', '333'),
('Y', '222')]),
OrderedDict([('Id', '634'),
('Name', 'Get me too'),
('Type', 'sometype'),
('X', '555'),
('Y', '777')])]
再次回答一个老问题,但我认为这个解决方案值得分享。 使用 BeautifulSoup 对我来说是小菜一碟。您可以安装 BeautifulSoup 形式 here.
from bs4 import BeautifulSoup
xml = BeautifulSoup(xml_string, 'xml')
xml.find('soap:Body') # to get the soup:Body tag.
xml.find('X') # for X tag
只需将所有 'soap:' 和其他名称空间前缀(例如 'a:' 替换为 ''(只需删除它们并使其成为 non-SOAP xml 文件)
new_response = response.text.replace('soap:', '').replace('a:', '')
那你就可以正常进行了。