package xmlimport ()// NodeDecoder is a XML decoder wrapper that is responsible to decoding// a single XML Node element and it's nested member elements. This wrapper decoder// takes in the start element of the top level node being decoded.typeNodeDecoderstruct {Decoder *xml.DecoderStartElxml.StartElement}// WrapNodeDecoder returns an initialized XMLNodeDecoderfunc ( *xml.Decoder, xml.StartElement) NodeDecoder {returnNodeDecoder{Decoder: ,StartEl: , }}// Token on a Node Decoder returns a xml StartElement. It returns a boolean that indicates the// a token is the node decoder's end node token; and an error which indicates any error// that occurred while retrieving the start elementfunc ( NodeDecoder) () ( xml.StartElement, bool, error) {for { , := .Decoder.Token()if != nil {return , , }// check if we reach end of the node being decodedif , := .(xml.EndElement); {return , == .StartEl.End(), }if , := .(xml.StartElement); {returnrestoreAttrNamespaces(), false, }// skip token if it is a comment or preamble or empty space value due to indentation // or if it's a value and is not expected }}// restoreAttrNamespaces update XML attributes to restore the short namespaces found within// the raw XML document.func ( xml.StartElement) xml.StartElement {iflen(.Attr) == 0 {return }// Generate a mapping of XML namespace values to their short names. := map[string]string{}for , := range .Attr {if .Name.Space == "xmlns" { [.Value] = .Name.Localbreak } }for , := range .Attr {if .Name.Space == "xmlns" {continue }// By default, xml.Decoder will fully resolve these namespaces. So if you had <foo xmlns:bar=baz bar:bin=hi/> // then by default the second attribute would have the `Name.Space` resolved to `baz`. But we need it to // continue to resolve as `bar` so we can easily identify it later on.if , := [.Attr[].Name.Space]; { .Attr[].Name.Space = } }return}// GetElement looks for the given tag name at the current level, and returns the element if found, and// skipping over non-matching elements. Returns an error if the node is not found, or if an error occurs while walking// the document.func ( NodeDecoder) ( string) ( xml.StartElement, error) {for { , , := .Token()if != nil {return , }if {return , fmt.Errorf("%s node not found", ) }switch {casestrings.EqualFold(, .Name.Local):return , nildefault: = .Decoder.Skip()if != nil {return , } } }}// Value provides an abstraction to retrieve char data value within an xml element.// The method will return an error if it encounters a nested xml element instead of char data.// This method should only be used to retrieve simple type or blob shape values as []byte.func ( NodeDecoder) () ( []byte, error) { , := .Decoder.Token()if != nil {return , } := .StartEl.End()switch ev := .(type) {casexml.CharData: = .Copy()casexml.EndElement: // end tag or self-closingif == {return []byte{}, }return , fmt.Errorf("expected value for %v element, got %T type %v instead", .StartEl.Name.Local, , )default:return , fmt.Errorf("expected value for %v element, got %T type %v instead", .StartEl.Name.Local, , ) } , = .Decoder.Token()if != nil {return , }if , := .(xml.EndElement); {if == {return , } }return , fmt.Errorf("expected end element %v, got %T type %v instead", , , )}// FetchRootElement takes in a decoder and returns the first start element within the xml body.// This function is useful in fetching the start element of an XML response and ignore the// comments and preamblefunc ( *xml.Decoder) ( xml.StartElement, error) {for { , := .Token()if != nil {return , }if , := .(xml.StartElement); {return , } }}
The pages are generated with Goldsv0.4.9. (GOOS=linux GOARCH=amd64)