python-zeep
python-zeep copied to clipboard
Failing to parse response from ONVIF Pullmessages method
Zeep version : 4.0.0 Python: 3.9.1 OS: Linux kali 5.9.0 x86_64 GNU/Linux WSDL used: http://www.onvif.org/ver10/events/wsdl/event.wsdl
I am trying to use Zeep with ONVIF camera to get alarms via PullPointSubscription and PullMessages method (e.g. tns1:VideoSource/MotionAlarm
alarm).
XML parsing of the PullMessageResponse received from the server produces invalid output as reported below (Topic is set to None, _value_1 is set to Message at 0xXXXXXXX); nevertheless I was able to get the correct output using suds.
I don't know if it could be relevant, but the "Topic Dialect" reference in the returned XML data is not valid (404 error):
http://www.onvif.org/ver10/tev/topicExpression/ConcreteSet
Received XML:
<s:Envelope
xmlns:sc="http://www.w3.org/2003/05/soap-encoding"
xmlns:s="http://www.w3.org/2003/05/soap-envelope"
xmlns:tt="http://www.onvif.org/ver10/schema"
xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2"
xmlns:tev="http://www.onvif.org/ver10/events/wsdl"
xmlns:wsa5="http://www.w3.org/2005/08/addressing"
xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing"
xmlns:wstop="http://docs.oasis-open.org/wsn/t-1"
xmlns:tns1="http://www.onvif.org/ver10/topics">
<s:Header>
<wsa5:Action>
http://www.onvif.org/ver10/events/wsdl/PullPointSubscription/PullMessagesResponse
</wsa5:Action>
<wsa5:To>
http://192.168.1.242/onvif/Subscription?Idx=206
</wsa5:To>
</s:Header>
<s:Body>
<tev:PullMessagesResponse>
<tev:CurrentTime>
2021-01-09T17:44:23Z
</tev:CurrentTime>
<tev:TerminationTime>
2021-01-09T17:45:15Z
</tev:TerminationTime>
<wsnt:NotificationMessage>
<wsnt:Topic
Dialect="http://www.onvif.org/ver10/tev/topicExpression/ConcreteSet">
tns1:RuleEngine/CellMotionDetector/Motion
</wsnt:Topic>
<wsnt:Message>
<tt:Message
UtcTime="2021-01-09T17:44:21Z"
PropertyOperation="Changed">
<tt:Source>
<tt:SimpleItem
Name="VideoSourceConfigurationToken"
Value="00000"/>
<tt:SimpleItem
Name="VideoAnalyticsConfigurationToken"
Value="00000"/>
<tt:SimpleItem
Name="Rule"
Value="00000"/>
</tt:Source>
<tt:Data>
<tt:SimpleItem
Name="IsMotion"
Value="true"/>
</tt:Data>
</tt:Message>
</wsnt:Message>
</wsnt:NotificationMessage>
<wsnt:NotificationMessage>
<wsnt:Topic
Dialect="http://www.onvif.org/ver10/tev/topicExpression/ConcreteSet">
tns1:VideoSource/MotionAlarm
</wsnt:Topic>
<wsnt:Message>
<tt:Message
UtcTime="2021-01-09T17:44:21Z"
PropertyOperation="Changed">
<tt:Source>
<tt:SimpleItem
Name="Source"
Value="00000"/>
</tt:Source>
<tt:Data>
<tt:SimpleItem
Name="State"
Value="true"/>
</tt:Data>
</tt:Message>
</wsnt:Message>
</wsnt:NotificationMessage>
</tev:PullMessagesResponse>
</s:Body>
</s:Envelope>
Parsed output:
{
'CurrentTime': datetime.datetime(2021, 1, 9, 17, 44, 23, tzinfo=<isodate.tzinfo.Utc object at 0x7f0219d73b50>),
'TerminationTime': datetime.datetime(2021, 1, 9, 17, 45, 15, tzinfo=<isodate.tzinfo.Utc object at 0x7f0219d73b50>),
'NotificationMessage': [
{
'SubscriptionReference': None,
'Topic': {
'_value_1': None,
'Dialect': 'http://www.onvif.org/ver10/tev/topicExpression/ConcreteSet',
'_attr_1': {
}
},
'ProducerReference': None,
'Message': {
'_value_1': <Element {http://www.onvif.org/ver10/schema}Message at 0x7f0219b4d980>
}
},
{
'SubscriptionReference': None,
'Topic': {
'_value_1': None,
'Dialect': 'http://www.onvif.org/ver10/tev/topicExpression/ConcreteSet',
'_attr_1': {
}
},
'ProducerReference': None,
'Message': {
'_value_1': <Element {http://www.onvif.org/ver10/schema}Message at 0x7f0219b4dbc0>
}
}
]
}
Runnable debug script to reproduce the issue:
import pretend # pip install pretend
from zeep import Client
from zeep.transports import Transport
wdsl = 'http://www.onvif.org/ver10/events/wsdl/event.wsdl'
client = Client(wdsl)
response = pretend.stub(
status_code=200,
headers={},
#The response from the server (onvif camera)
content="""<s:Envelope xmlns:sc="http://www.w3.org/2003/05/soap-encoding" xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:tt="http://www.onvif.org/ver10/schema" xmlns:wsnt="http://docs.oasis-open.org/wsn/b-2" xmlns:tev="http://www.onvif.org/ver10/events/wsdl" xmlns:wsa5="http://www.w3.org/2005/08/addressing" xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:wstop="http://docs.oasis-open.org/wsn/t-1" xmlns:tns1="http://www.onvif.org/ver10/topics"><s:Header><wsa5:Action> http://www.onvif.org/ver10/events/wsdl/PullPointSubscription/PullMessagesResponse </wsa5:Action><wsa5:To> http://192.168.1.242/onvif/Subscription?Idx=206 </wsa5:To></s:Header><s:Body><tev:PullMessagesResponse><tev:CurrentTime> 2021-01-09T17:44:23Z </tev:CurrentTime><tev:TerminationTime> 2021-01-09T17:45:15Z </tev:TerminationTime><wsnt:NotificationMessage><wsnt:Topic Dialect="http://www.onvif.org/ver10/tev/topicExpression/ConcreteSet"> tns1:RuleEngine/CellMotionDetector/Motion </wsnt:Topic><wsnt:Message><tt:Message UtcTime="2021-01-09T17:44:21Z" PropertyOperation="Changed"><tt:Source><tt:SimpleItem Name="VideoSourceConfigurationToken" Value="00000"/><tt:SimpleItem Name="VideoAnalyticsConfigurationToken" Value="00000"/><tt:SimpleItem Name="Rule" Value="00000"/></tt:Source><tt:Data><tt:SimpleItem Name="IsMotion" Value="true"/></tt:Data></tt:Message></wsnt:Message></wsnt:NotificationMessage><wsnt:NotificationMessage><wsnt:Topic Dialect="http://www.onvif.org/ver10/tev/topicExpression/ConcreteSet">tns1:VideoSource/MotionAlarm</wsnt:Topic><wsnt:Message><tt:Message UtcTime="2021-01-09T17:44:21Z" PropertyOperation="Changed"><tt:Source><tt:SimpleItem Name="Source" Value="00000"/></tt:Source><tt:Data><tt:SimpleItem Name="State" Value="true"/></tt:Data></tt:Message></wsnt:Message></wsnt:NotificationMessage></tev:PullMessagesResponse></s:Body></s:Envelope>""")
operation_name = 'PullMessages'
service = client.create_service(
'{http://www.onvif.org/ver10/events/wsdl}PullPointSubscriptionBinding',
'http://my-endpoint.com/acceptance/')
operation = service._binding._operations[operation_name]
result = service._binding.process_reply(client, operation, response)
#xml parsing is error free but fields from NotificationMessage are invalid
print(result)
@barban-dev Maybe a bit late, but i struggled with the same issue. But i finally found what the problem is. The 'Message' field is defined as type 'any'. That basically means it can be anything. Because it is not defined and there is no schema for it, zeep cannot decode it. But what the documentation does not tell you (or at least i could not find it) is that it returns a 'lxml.etree._element'. Zeep uses the 'lxml' package for parsing the xml. It basically contains the complete XML node. I wrote a bit of demo code to shows how to decode the result:
from lxml import etree
-- your debug script ---
for msg in result.NotificationMessage:
if isinstance(msg.Message._value_1, etree._Element):
etree.dump(msg.Message._value_1)
source = msg.Message._value_1.find('./{*}Source')
for child in source.getchildren():
print(child.tag, child.attrib)
data = msg.Message._value_1.find('./{*}Data')
for child in data.getchildren():
print(child.tag, child.attrib)