Last active
November 24, 2023 03:06
-
-
Save treywelsh/5486bc3af9ee12e415ee82f1ec1997dc to your computer and use it in GitHub Desktop.
golang dynamic xml unmarshalling mixed with fixed tags
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"encoding/xml" | |
"fmt" | |
pkg "xml_unparsed/xmlmap" | |
//pkg "xml_unparsed/xmlslice" | |
) | |
type xmlTest struct { | |
Tag4 string `xml:"tag4"` | |
Unparsed pkg.UnparsedTags `xml:",any"` | |
} | |
func main() { | |
xmlstr := `<foo><tag1>toto</tag1> <tag2>tutu</tag2> <foo2><tag3>titi</tag3></foo2> <tag4>parsed</tag4> <tag5>blabla</tag5></foo>` | |
var xmlstruct xmlTest | |
err := xml.Unmarshal([]byte(xmlstr), &xmlstruct) | |
if err != nil { | |
fmt.Println(err) | |
return | |
} | |
fmt.Println(xmlstr) | |
fmt.Printf("resp: %+v\n", xmlstruct) | |
fetched := xmlstruct.Unparsed.GetContentByName("tag5") | |
if len(fetched) > 0 { | |
fmt.Printf("Getted by name: %+v\n", fetched) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package xmlmap | |
import ( | |
"encoding/xml" | |
//"fmt" | |
) | |
// Store unparsed tags in a map (useful with flat dynamic xml). | |
// Inspired from: https://stackoverflow.com/questions/30928770/marshall-map-to-xml-in-go/33110881 | |
// The main difference is that it can be mixed with defined tags in a struct. For each unparsed element UnmarshalXML is called once. | |
// NOTE: to be used in flat xml part with distinct tag names | |
// If it's not flat: the hash will contains key with empty values | |
// If there is several tags with the same name : only the last value will be stored | |
// UnparsedTag contains the tag informations | |
type UnparsedTag struct { | |
XMLName xml.Name | |
Content string `xml:",chardata"` | |
//FullContent string `xml:",innerxml"` // for debug purpose, allow to see what's inside some tags | |
} | |
// UnparsedTags store tags not handled by Unmarshal in a map, it should be labelled with `xml",any"` | |
type UnparsedTags map[string]string | |
func (m *UnparsedTags) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { | |
if *m == nil { | |
*m = UnparsedTags{} | |
} | |
e := UnparsedTag{} | |
err := d.DecodeElement(&e, &start) | |
if err != nil { | |
return err | |
} | |
//if _, ok := (*m)[e.XMLName.Local]; ok { | |
// return fmt.Errorf("UnparsedTags: UnmarshalXML: Tag %s: multiple entries with the same name", e.XMLName.Local) | |
//} | |
(*m)[e.XMLName.Local] = e.Content | |
return nil | |
} | |
func (u *UnparsedTags) GetContentByName(name string) string { | |
return ((map[string]string)(*u))[name] | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package xmlslice | |
import "encoding/xml" | |
// Store unparsed tags in a map | |
// Difference with xmlmap: there is no unicity required on the tag name anymore | |
// UnparsedTags contains a list of tags not handled by unmarshall, it should be marked with `xml",any"` | |
type UnparsedTags struct { | |
Tags []UnparsedTag | |
} | |
// UnparsedTag contains the tag informations | |
type UnparsedTag struct { | |
XMLName xml.Name | |
Content string `xml:",chardata"` | |
//FullContent string `xml:",innerxml"` // for debug purpose, allow to what's inside some tags | |
} | |
func (u *UnparsedTags) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { | |
var e UnparsedTag | |
err := d.DecodeElement(&e, &start) | |
if err != nil { | |
return err | |
} | |
u.Tags = append(u.Tags, e) | |
return nil | |
} | |
func (u *UnparsedTags) GetContentByName(name string) []string { | |
content := make([]string, 0, 1) | |
for _, t := range u.Tags { | |
if t.XMLName.Local != name { | |
continue | |
} | |
content = append(content, t.Content) | |
} | |
return content | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment