go_clientinfo/server/funcs_xmlheaders.go
2024-12-12 02:22:54 -05:00

161 lines
3.2 KiB
Go

package server
import (
`encoding/xml`
`errors`
`io`
)
/*
MarshalXML encodes an XmlHeaders as XML in the following format:
(<headers>)
<header name="SomeHeader">
<value>SomeValue</value>
</header>
<header name="SomeMultiValueHeader">
<value>Foo</value>
<value>Bar</value>
</header>
(</headers>)
For the above example, the field should be specified as `xml:"headers"`.
However, the parent element name may be whatever you wish.
*/
func (x XmlHeaders) MarshalXML(e *xml.Encoder, start xml.StartElement) (err error) {
var curKey string
var vals []string
var val string
var hdr xml.StartElement
var child xml.StartElement
// TODO: Does xml.EncodeElement properly escape?
// var escKBuf *bytes.Buffer
// var escVBuf *bytes.Buffer
// All values are []string, so we don't need any fancy parsing or switching or the like.
// We do need to make sure we escape, though.
if err = e.EncodeToken(start); err != nil {
return
}
if x != nil && len(x) > 0 {
// escKBuf = new(bytes.Buffer)
// escVBuf = new(bytes.Buffer)
for curKey, vals = range x {
// escKBuf.Reset()
// if err = xml.EscapeText(escKBuf, []byte(curKey)); err != nil {
// return
// }
hdr = xml.StartElement{
Name: xml.Name{
Local: xmlHdrElem,
},
Attr: []xml.Attr{
xml.Attr{
Name: xml.Name{
Local: xmlHdrElemName,
},
// Value: escKBuf.String(),
Value: curKey,
},
},
}
if err = e.EncodeToken(hdr); err != nil {
return
}
for _, val = range vals {
// escVBuf.Reset()
// if err = xml.EscapeText(escVBuf, []byte(val)); err != nil {
// return
// }
child = xml.StartElement{
Name: xml.Name{
Local: xmlHdrVal,
},
}
// if err = e.EncodeElement(escVBuf.String(), child); err != nil {
if err = e.EncodeElement(val, child); err != nil {
return
}
}
if err = e.EncodeToken(hdr.End()); err != nil {
return
}
}
}
if err = e.EncodeToken(start.End()); err != nil {
return
}
return
}
// UnmarshalXML populates an XMLHeaders from an XML representation. See MarshalXML for example XML.
func (x *XmlHeaders) UnmarshalXML(d *xml.Decoder, start xml.StartElement) (err error) {
var tok xml.Token
var xm XmlHeaders
var hdrNm string
var vals []string
var val *string
var nameFound bool
for {
if tok, err = d.Token(); err != nil {
if errors.Is(err, io.EOF) {
err = nil
break
} else {
return
}
}
switch elem := tok.(type) {
case xml.StartElement:
switch elem.Name.Local {
case xmlHdrElem:
nameFound = false
vals = nil
for _, a := range elem.Attr {
if a.Name.Local == xmlHdrElemName {
nameFound = true
hdrNm = a.Value
break
}
}
if !nameFound {
continue
}
case xmlHdrVal:
if !nameFound {
continue
}
if vals == nil {
vals = make([]string, 0, 1)
}
val = new(string)
if err = d.DecodeElement(val, &elem); err != nil {
return
}
vals = append(vals, *val)
}
case xml.EndElement:
if elem.Name.Local != xmlHdrElem {
continue
}
if xm == nil {
xm = make(XmlHeaders)
}
xm[hdrNm] = vals
}
}
if xm != nil {
*x = xm
}
return
}