Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

unmarshal support for onvif soap response #2

Open
ilia373 opened this issue Jun 22, 2020 · 10 comments
Open

unmarshal support for onvif soap response #2

ilia373 opened this issue Jun 22, 2020 · 10 comments

Comments

@ilia373
Copy link

ilia373 commented Jun 22, 2020

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?

@YoshieraHuang
Copy link

I agree. large xml file is too tedious to handle.

@crazybber
Copy link
Contributor

a little busy ,but PRs are always welcomed.😊

@Miracle-doctor
Copy link

Miracle-doctor commented Jul 28, 2021

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

@AkshayPS12
Copy link

AkshayPS12 commented Aug 24, 2021

if anybody has figured out the unmarshalling of XML responses please let me know , or if someone has started working , we can collaborate...

@unm4sk1g
Copy link

Any progress on this?

@AkshayPS12
Copy link

AkshayPS12 commented Aug 31, 2021

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)
   }

@unm4sk1g
Copy link

unm4sk1g commented Sep 1, 2021

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 👍

@cedricve
Copy link

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>

@AkshayPS12
Copy link

@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

@Pawan-ky
Copy link

Pawan-ky commented Aug 8, 2023

Hi, do we have concrete solution on this issue (other than the solution mentioned above) or anybody working on this and planning to release in near future.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants