onvif
onvif copied to clipboard
unmarshal support for onvif soap response
currently there is soap xml marshaling tags only for the request structs. for response structs there are no xml unmarshal capabilities. planning to add that support? there is any technical limitation to have that implemented or its only a matter of mapping each struct?
I agree. large xml file is too tedious to handle.
a little busy ,but PRs are always welcomed.😊
Hi! I used this code for unmarshalling
type ProfileResponse struct {
XMLName xml.Name
Profiles []onvif.Profile
}
type Body struct {
XMLName xml.Name
GetProfilesResponse ProfileResponse //xml:"GetProfilesResponse"
}
type MyGetProfiles struct {
XMLName xml.Name
Body Body
}
profiles := &MyGetProfiles{}
err = xml.Unmarshal([]byte(resp), profiles)
And for getting profiles:
profiles.Body.GetProfilesResponse.Profiles
if anybody has figured out the unmarshalling of XML responses please let me know , or if someone has started working , we can collaborate...
Any progress on this?
Any progress on this?
I have done this in a kind of hacky way : This function will query the node from the xml body you want to extract the info from For example , you do getStreamUri call from dev.CallMethod() and you get a xml resp which contains GetStreamUriResponse
func getXMLNode(xmlBody string, nodeName string) (*xml.Decoder, *xml.StartElement, string) {
xmlBytes := bytes.NewBufferString(xmlBody)
decodedXML := xml.NewDecoder(xmlBytes)
for {
token, err := decodedXML.Token()
if err != nil {
break
}
switch et := token.(type) {
case xml.StartElement:
if et.Name.Local == nodeName {
return decodedXML, &et, ""
}
}
}
return nil, nil, "error in NodeName"
}
and then you just unmarshal into the Response struct
var mGetUsersResp device.GetUsersResponse
bs, _ := ioutil.ReadAll(res.Body)
stringBody := string(bs)
decodedXML, et, errorFunc := getXMLNode(stringBody, "GetStreamUriResponse")
if errorFunc != "" {
log.Printf("%s", errorFunc)
}
if err := decodedXML.DecodeElement(&mStreamUriResp, et); err != nil {
panic(err)
}
Any progress on this?
I have done this in a kind of hacky way : This function will query the node from the xml body you want to extract the info from For example , you do getStreamUri call from dev.CallMethod() and you get a xml resp which contains GetStreamUriResponse
func getXMLNode(xmlBody string, nodeName string) (*xml.Decoder, *xml.StartElement, string) { xmlBytes := bytes.NewBufferString(xmlBody) decodedXML := xml.NewDecoder(xmlBytes) for { token, err := decodedXML.Token() if err != nil { break } switch et := token.(type) { case xml.StartElement: if et.Name.Local == nodeName { return decodedXML, &et, "" } } } return nil, nil, "error in NodeName" }
and then you just unmarshal into the Response struct
var mGetUsersResp device.GetUsersResponse bs, _ := ioutil.ReadAll(res.Body) stringBody := string(bs) decodedXML, et, errorFunc := getXMLNode(stringBody, "GetStreamUriResponse") if errorFunc != "" { log.Printf("%s", errorFunc) } if err := decodedXML.DecodeElement(&mStreamUriResp, et); err != nil { panic(err) }
Works flawlessly, thank you 👍
thanks this does work for string, but integers are set to 0, even if there is a valid response in the body
{{VideoEncoderToken_2 0} {0 0} 0 {0 0 0} {0 } {0 } {{ } 0 0 false} }
And the response
<tt:Name>VideoEncoder_2</tt:Name>
<tt:UseCount>1</tt:UseCount>
<tt:Encoding>H264</tt:Encoding>
<tt:Resolution><tt:Width>640</tt:Width>
<tt:Height>360</tt:Height>
</tt:Resolution>
@cedricve make sure your struct is correct for which you are unmarshalling. You will need to understand the types. My VideoEncoderConfiguration Struct looks like this :
type VideoEncoderConfiguration struct {
*ConfigurationEntity `json:"ConfigurationEntity"`
Encoding *string `xml:"Encoding" json:",omitempty"`
Resolution *Resolution `xml:"Resolution" json:",omitempty"`
Quality *float64 `xml:"Quality" json:",omitempty"`
RateControl *RateControl `xml:"RateControl" json:",omitempty"`
MPEG4 *MPEG4 `xml:"MPEG4" json:",omitempty"`
H264 *H264 `xml:"H264" json:",omitempty"`
Multicast *Multicast `xml:"Multicast" json:",omitempty"`
SessionTimeout *string `xml:"SessionTimeout" json:",omitempty"`
}
also fields like Resolution point to another struct which is like this:
type Resolution struct {
Width *xsd.Int `xml:"Width"`
Height *xsd.Int `xml:"Height"`
}
xsd Int is basically type Int int32
these structs are autogenerated from ONVIF's xsd