metaleap / go-xsd

[stable since 2013] a lib for loading XML Schema Definition (XSD) files ➜ plus, a tool `makepkg` to code-generate from any *.xsd your Go package with all needed `struct`s to readily `xml.Unmarshal()` documents into, based on the XSD's schema definitions. NOT REALLY MAINTAINED FOR YEARS NOW: try the forks if running into issues.
http://www.reddit.com/r/golang/comments/12g6sl/is_there_a_tool_that_generates_go_source_code_for/
MIT License
216 stars 66 forks source link
go golang xml-schema xsd

go-xsd

A Go package for loading ( xml.Unmarshal()-ing ) an XML Schema Definition (XSD) document into an xsd.Schema structure.

With this, you could probably write an XML validator, or otherwise utilize or further process the loaded XSD --- but the main use-case here was:

go-xsd/xsd-makepkg

A command-line tool to generate Go "XML wrapper" package sources for specified XSD schema URIs.

If no arguments are specified, this tool proceeds to (re)generate all Go packages for various common XML formats in your local $GOPATH-relative directory corresponding to the http://github.com/metaleap/go-xsd-pkg repository. For more details on command-line arguments for xsd-makepkg: scroll down to the bottom of this readme.

Each generated wrapper package contains the type structures required to easily xml.Unmarshal() an XML document based on that XSD.

XSD simple-types are represented by the corresponding native Go scalar data type, augmented by utility methods where applicable:

XSD complex-types, attribute-groups, element-groups, elements etc. are ultimately represented by corresponding generated Go struct types.

XSD includes are all loaded and processed together into a single output .go source file.

XSD imports are rewritten as Go imports but not otherwise auto-magically processed. If you see the generated .go package importing another "some-xsd-xml-whatever-name-_go" package that will cause a "package not found" compiler error, then to make that import work, you'll first need to also auto-generate that package with xsd-makepkg yourself as well.

XSD documentation annotation is rewritten as Go // code comments. Yeah, that's rather neat.

Regarding the auto-generated code:

go-xsd/types

A tiny package automatically imported by all go-xsd auto-generated packages. Maps all XSD built-in simple-types to Go types, which affords us easy mapping of any XSD type references in the schema to Go imports: every xs:string and xs:boolean automatically becomes xsdt.String and xsdt.Boolean etc. Types are mapped to Go types depending on how encoding/xml.Unmarshal() can handle them: ie. it parses bools and numbers, but dates/durations have too many format mismatches and thus are just declared string types. Same for base64- and hex-encoded binary data: since Unmarshal() won't decode them, we leave them as strings. If you need their binary data, your code needs to import Go's base64/hex codec packages and use them as necessary.

How to use auto-generated packages:

Take a look at the "test progs" under xsd-makepkg/tests, they're basically simple usage examples. For unmarshal you need to define just one small custom struct like this --- using the rss package as a simple example, as demonstrated in xsd-makepkg/tests/xsd-test-rss/main.go:

type MyRssDoc struct {
    XMLName xml.Name `xml:"rss"`
    rss.TxsdRss
}

So your custom struct specifies two things:

The second part is the only tricky part. XML Schema Definition has no real concept of "root element", partly because they're designed to support use-cases where you embed a full document defined in one XSD deep inside a full document defined in another XSD. So a Collada document may contain a full or partial MathML document somewhere inside it. Some well-designed XSDs define a single top-level element, so we could infer "this is the root element" and generate a "XyzDoc" struct (like the MyRssDoc above) for you. But many don't. Some formats may legally have one of two or more possible "root" elements, ie. Atom allegedly may have either a "feed" root element or an "entry" root element. So go-xsd does not magically infer which of the XSD's top-level elements might be the root element, you define this by writing a small struct as shown above. The naming of the root element Go type to be embedded is not consistent across different packages, because their naming is directly based on the XSD that was used to generate the package. So for example...

Seems like Collada and RSS share a certain naming pattern, and yet Atom/SVG share another one? Mere coincidence, the naming is completely arbitrary and up to the XSD author. Ultimately, to find out the proper Go type name to embed, you'll have to dig a bit inside the generated package. That's actually pretty straightforward, here's how you do it:

A) Suppose you have an XML format where the root element (and only that one) is known to be named:

<gopher>

B) Open the generated Go package source files under *$GOPATH/src/github.com/metaleap/go-xsd-pkg/yourdomain.org/xsd/gopher.xsd_go/.go (unless you used custom paths when you ran the go-xsd/xsd-makepkg** tool)

C) Search for an occurence of either:

"gopher"`

( quote, gopher, quote, backtick ), or:

 gopher"`

( whitespace, gopher, quote, backtick )

D) The found occurence is likely the tag for a field in a type named something like XsdGoPkgHasElem_Gopher or XsdGoPkgHasElems_Gopher. Ignore that type, instead focus on the type of the field itself. That's the one you're looking for, the one to embed in your tiny custom doc struct.

Command-line flags for go-xsd/xsd-makepkg tool: