Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
0d7d89b
Reproduce issue #65
droyo Feb 8, 2018
a1014c2
Correctly convert XML QNames when resolving references across documents
droyo Mar 3, 2018
d48ea63
Merge pull request #66 from droyo/import-type-from-otherns
droyo Mar 3, 2018
0072708
all: clarify import locations
kortschak Oct 9, 2018
76083a7
gentests: make package name match import path
kortschak Oct 13, 2018
7579737
Merge pull request #70 from kortschak/location-location-location
droyo Oct 13, 2018
3f3f9b4
xsdgen: make debug logging happen after state change
kortschak Oct 13, 2018
841f47b
Merge pull request #71 from kortschak/log-after-event
droyo Oct 13, 2018
7d3d792
Extend build to more go versions
leth Dec 12, 2018
5d7025d
Fix missing arg to Errorf
leth Dec 12, 2018
e4614d1
Fix format string type mismatch
leth Dec 12, 2018
5679372
Merge pull request #73 from leth/compat
droyo Jan 3, 2019
48de467
Remove support for Go versions before 1.9
droyo Jan 3, 2019
e3007ec
Merge pull request #75 from droyo/drop-18
droyo Jan 3, 2019
30b6a87
Factor out some portions of gentests/_testgen for re-use
droyo Jan 3, 2019
0880b4c
Split generated code and generated tests into separate files
droyo Jan 3, 2019
e2cf087
WSDL Request/Response hooks should now return their result
marcuscobden-nbs Jan 10, 2019
8112196
Pass a context through to HTTP requests
marcuscobden-nbs Jan 10, 2019
7b612f7
Make HTTPClient a reference to ensure reuse
marcuscobden-nbs Jan 10, 2019
8f75b59
Add CI check to ensure generated files are up to date
marcuscobden-nbs Jan 10, 2019
404ca93
Regenerate code
marcuscobden-nbs Jan 10, 2019
82fa0a2
Merge pull request #78 from leth/check-generated-files
droyo Jan 12, 2019
38a3e78
Merge pull request #77 from leth/wsdl-client-improvements
droyo Jan 12, 2019
ac020f3
Pass namespace through to attribute metadata
marcuscobden-nbs Mar 1, 2019
07ae29c
Update tests and generated files to include namespace
marcuscobden-nbs Mar 1, 2019
ce25feb
Only qualify attributes when needed
marcuscobden-nbs Mar 4, 2019
137d4f7
Add test case to cover qualified attributes
marcuscobden-nbs Mar 4, 2019
bea67d1
Merge pull request #81 from leth/attr-namespaces
droyo Mar 12, 2019
ecfbaa7
Remove unwanted whitespaces from MarshalIndent output.
bombsimon Apr 11, 2019
9e2dd5e
Merge pull request #84 from bombsimon/fix-marshal-indent
droyo Apr 11, 2019
75a099a
Merge branch 'master' of github.com:droyo/go-xml
droyo May 22, 2019
b2525a5
Update generated tests
droyo May 26, 2019
7d0756c
Update stringer output
droyo May 26, 2019
a9a46cf
Fix travis tests from stringer breakage
droyo May 26, 2019
22e0fe0
Install deps in the correct Go version
droyo May 26, 2019
8dd125f
Merge pull request #87 from droyo/travis
droyo May 26, 2019
c04baf4
Merge branch 'master' into omitempty-structs
makon-ks Jul 30, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,22 @@
language: go
go_import_path: aqwari.net/xml
go:
- 1.7
- "1.9"
- "1.10"
- "1.11"

install:
- go get -t -v ./...
# While this package supports Go 1.9+, stringer does not. We need newer
# versions of Go to check generated files.
- gimme 1.11
- source ~/.gimme/envs/go1.11.env
- go get -v golang.org/x/tools/cmd/stringer

before_script:
- source ~/.gimme/envs/go1.11.env
- go generate ./...
- if [[ -n $(git status -s) ]]; then echo "Unclean working tree"; git diff; exit 1; fi

notifications:
email:
Expand Down
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
[![GoDoc](https://godoc.org/aqwari.net/xml?status.svg)](https://godoc.org/aqwari.net/xml) [![Build Status](https://travis-ci.org/droyo/go-xml.svg?branch=master)](https://travis-ci.org/droyo/go-xml)

## Installation

Requires go 1.9 or greater for golang.org/x/html dependency.

```
go get aqwari.net/xml/...
```

This repository contains a collection of Go packages for working
with XML, with the ultimate goal of enabling code generation based
on XML documents.
Expand Down
2 changes: 1 addition & 1 deletion cmd/wsdlgen/wsdlgen.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package main
package main // import "aqwari.net/xml/cmd/wsdlgen"

import (
"log"
Expand Down
2 changes: 1 addition & 1 deletion cmd/xsdgen/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,4 @@ embed a comment in your go source like so:

//go:generate xsdgen -ns "http://example.net/ws/" schemafile.xml
*/
package main
package main // import "aqwari.net/xml/cmd/xsdgen"
2 changes: 1 addition & 1 deletion cmd/xsdparse/xsdparse.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package main
package main // import "aqwari.net/xml/cmd/xsdparse"

import (
"flag"
Expand Down
121 changes: 75 additions & 46 deletions gentests/_testgen/testgen.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"go/ast"
"io/ioutil"
"log"
"os"
"path/filepath"
"strings"

Expand All @@ -29,39 +30,51 @@ func glob(pat string) string {
}

func main() {
var errorsEncountered bool
cfg := new(xsdgen.Config)
cases := findTestCases()

xsdTestCases, err := findXSDTestCases()
if err != nil {
log.Fatal(err)
}

cfg.Option(xsdgen.DefaultOptions...)
for _, dir := range cases {
data, err := ioutil.ReadFile(glob(filepath.Join(dir, "*.xsd")))
for _, testCase := range xsdTestCases {
code, tests, err := genXSDTests(*cfg, testCase.doc, testCase.pkg)
if err != nil {
log.Print(err)
continue
}
tests, err := genTests(*cfg, data, dir)
if err != nil {
log.Print(dir, ":", err)
errorsEncountered = true
log.Print(testCase.pkg)
continue
} else {
log.Printf("generated tests for %s", dir)
log.Printf("generated xsd tests for %s", testCase.pkg)
}
filename := filepath.Join(dir, dir+"_test.go")
source, err := gen.FormattedSource(tests, filename)
if err != nil {
log.Print(dir, ":", err)
continue
}
if err := ioutil.WriteFile(filename, source, 0666); err != nil {
log.Print(dir, ":", err)
if err := writeTestFiles(code, tests, testCase.pkg); err != nil {
errorsEncountered = true
log.Print(testCase.pkg, ":", err)
}
}

// This is needed so 'go build' works and automated CI doesn't complain.
err = ioutil.WriteFile(filepath.Join(dir, dir+".go"), []byte("package "+dir+"\n"), 0666)
if err != nil {
log.Print(err)
}
if errorsEncountered {
os.Exit(1)
}
}

func writeTestFiles(code, tests *ast.File, pkg string) error {
testFilename := filepath.Join(pkg, pkg+"_test.go")
testSrc, err := gen.FormattedSource(tests, testFilename)
if err != nil {
return err
}
if err := ioutil.WriteFile(testFilename, testSrc, 0666); err != nil {
return err
}

codeFilename := filepath.Join(pkg, pkg+".go")
codeSrc, err := gen.FormattedSource(code, codeFilename)
if err != nil {
return err
}
return ioutil.WriteFile(codeFilename, codeSrc, 0666)
}

// Generates unit tests for xml marshal unmarshalling of
Expand All @@ -72,25 +85,30 @@ func main() {
// the document described in the XML schema.
// - Marshal the resulting file back into an XML document.
// - Compare the two documents for equality.
func genTests(cfg xsdgen.Config, data []byte, dir string) (*ast.File, error) {
cfg.Option(xsdgen.PackageName(dir))
code, err := cfg.GenCode(data)
//
// Returns type definitions and unit tests as separate files.
func genXSDTests(cfg xsdgen.Config, data []byte, pkg string) (code, tests *ast.File, err error) {
cfg.Option(xsdgen.PackageName(pkg))
main, err := cfg.GenCode(data)
if err != nil {
return nil, err
return nil, nil, err
}
file, err := code.GenAST()
code, err = main.GenAST()
if err != nil {
return nil, err
return nil, nil, err
}

tests = new(ast.File)
tests.Name = ast.NewIdent(pkg)

// We look for top-level elements in the schema to determine what
// the example document looks like.
roots, err := xsd.Normalize(data)
if err != nil {
return nil, err
return nil, nil, err
}
if len(roots) < 1 {
return nil, fmt.Errorf("no schema in %s", dir)
return nil, nil, fmt.Errorf("no schema in %s", pkg)
}
root := roots[0]
doc := topLevelElements(root)
Expand All @@ -99,21 +117,21 @@ func genTests(cfg xsdgen.Config, data []byte, dir string) (*ast.File, error) {
for _, elem := range doc {
fields = append(fields,
gen.Public(elem.Name.Local),
ast.NewIdent(code.NameOf(elem.Type)),
ast.NewIdent(main.NameOf(elem.Type)),
gen.String(fmt.Sprintf(`xml:"%s %s"`, elem.Name.Space, elem.Name.Local)))
}
expr, err := gen.ToString(gen.Struct(fields...))
if err != nil {
return nil, err
return nil, nil, err
}

var params struct {
DocStruct string
Dir string
Pkg string
}
params.DocStruct = expr
params.Dir = dir
fn, err := gen.Func("Test"+strings.Title(dir)).
params.Pkg = pkg
fn, err := gen.Func("Test"+strings.Title(pkg)).
Args("t *testing.T").
BodyTmpl(`
type Document {{.DocStruct}}
Expand Down Expand Up @@ -142,7 +160,7 @@ func genTests(cfg xsdgen.Config, data []byte, dir string) (*ast.File, error) {

inputTree, err := xmltree.Parse(input)
if err != nil {
t.Fatal("{{.Dir}}: ", err)
t.Fatal("{{.Pkg}}: ", err)
}

outputTree, err := xmltree.Parse(output)
Expand All @@ -158,11 +176,10 @@ func genTests(cfg xsdgen.Config, data []byte, dir string) (*ast.File, error) {
`, params).Decl()

if err != nil {
return nil, err
return nil, nil, err
}
// Test goes at the top
file.Decls = append([]ast.Decl{fn}, file.Decls...)
return file, nil
tests.Decls = append(tests.Decls, fn)
return code, tests, nil
}

type Element struct {
Expand All @@ -188,17 +205,29 @@ func topLevelElements(root *xmltree.Element) []Element {
return result
}

type testCase struct {
pkg string
doc []byte
}

// Looks for subdirectories containing pairs of (xml, xsd) files
// that should contain an xml document and the schema it conforms to,
// respectively. Returns slice of the directory names
func findTestCases() []string {
func findXSDTestCases() ([]testCase, error) {
filenames, err := filepath.Glob("*/*.xsd")
if err != nil {
return nil
return nil, err
}
result := make([]string, 0, len(filenames))
result := make([]testCase, 0, len(filenames))
for _, xsdfile := range filenames {
result = append(result, filepath.Base(filepath.Dir(xsdfile)))
if data, err := ioutil.ReadFile(xsdfile); err != nil {
return nil, err
} else {
result = append(result, testCase{
pkg: filepath.Base(filepath.Dir(xsdfile)),
doc: data,
})
}
}
return result
return result, nil
}
65 changes: 65 additions & 0 deletions gentests/bindata/bindata.go
Original file line number Diff line number Diff line change
@@ -1 +1,66 @@
package bindata

import (
"bytes"
"encoding/base64"
"encoding/hex"
"encoding/xml"
)

type Bindata struct {
HexData []byte `xml:"tns hexData"`
B64Data []byte `xml:"tns b64Data"`
Filename string `xml:"tns filename"`
}

func (t *Bindata) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
type T Bindata
var layout struct {
*T
HexData *xsdHexBinary `xml:"tns hexData"`
B64Data *xsdBase64Binary `xml:"tns b64Data"`
}
layout.T = (*T)(t)
layout.HexData = (*xsdHexBinary)(&layout.T.HexData)
layout.B64Data = (*xsdBase64Binary)(&layout.T.B64Data)
return e.EncodeElement(layout, start)
}
func (t *Bindata) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
type T Bindata
var overlay struct {
*T
HexData *xsdHexBinary `xml:"tns hexData"`
B64Data *xsdBase64Binary `xml:"tns b64Data"`
}
overlay.T = (*T)(t)
overlay.HexData = (*xsdHexBinary)(&overlay.T.HexData)
overlay.B64Data = (*xsdBase64Binary)(&overlay.T.B64Data)
return d.DecodeElement(&overlay, &start)
}

type xsdBase64Binary []byte

func (b *xsdBase64Binary) UnmarshalText(text []byte) (err error) {
*b, err = base64.StdEncoding.DecodeString(string(text))
return
}
func (b xsdBase64Binary) MarshalText() ([]byte, error) {
var buf bytes.Buffer
enc := base64.NewEncoder(base64.StdEncoding, &buf)
enc.Write([]byte(b))
enc.Close()
return buf.Bytes(), nil
}

type xsdHexBinary []byte

func (b *xsdHexBinary) UnmarshalText(text []byte) (err error) {
*b, err = hex.DecodeString(string(text))
return
}
func (b xsdHexBinary) MarshalText() ([]byte, error) {
n := hex.EncodedLen(len(b))
buf := make([]byte, n)
hex.Encode(buf, []byte(b))
return buf, nil
}
Loading