Skip to content

Commit

Permalink
Handle mixed content types better.
Browse files Browse the repository at this point in the history
Many complex types wrap simple types and add attributes to them.
Code generated for *any* complex types that are derived from such types
need to provide a ",chardata" field for the mixed content. Previously
the xsdgen package only generated such a field when a type was being
extended, but a restriction is just as valid.
  • Loading branch information
droyo committed Mar 2, 2017
1 parent 6a2495f commit 219f388
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 11 deletions.
20 changes: 20 additions & 0 deletions xsdgen/testdata/mixed-complex.xsd
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ns="http://example.org" targetNamespace="http://example.org">

<xs:complexType name="Number">
<xs:simpleContent>
<xs:extension base="xs:double">
<xs:attribute name="precision" type="xs:int"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>

<xs:complexType name="PositiveNumber">
<xs:simpleContent>
<xs:restriction base="ns:Number">
<xs:minInclusive value="1"/>
</xs:restriction>
</xs:simpleContent>
</xs:complexType>

</xs:schema>

34 changes: 27 additions & 7 deletions xsdgen/xsdgen.go
Original file line number Diff line number Diff line change
Expand Up @@ -393,17 +393,27 @@ func (cfg *Config) genComplexType(t *xsd.ComplexType) ([]spec, error) {
var result []spec
var fields []ast.Expr

if t.Extends {
base, err := cfg.expr(t.Base)
if t.Mixed {
// For complex types with mixed content models, we must drill
// down to the base simple or builtin type to determine the
// ",chardata" struct field.
base := xsd.Base(t)
for xsd.Base(base) != nil {
if _, ok := base.(*xsd.SimpleType); ok {
break
}
base = xsd.Base(base)
}
expr, err := cfg.expr(base)
if err != nil {
return nil, fmt.Errorf("%s base type %s: %v",
t.Name.Local, xsd.XMLName(t.Base).Local, err)
}
switch b := t.Base.(type) {
switch b := base.(type) {
case *xsd.SimpleType:
cfg.debugf("complexType %[1]s extends simpleType %[2]s. Naming"+
" the chardata struct field after %[2]s", t.Name.Local, b.Name.Local)
fields = append(fields, base, base, gen.String(`xml:",chardata"`))
fields = append(fields, expr, expr, gen.String(`xml:",chardata"`))
case xsd.Builtin:
if b == xsd.AnyType {
// extending anyType doesn't really make sense, but
Expand All @@ -415,12 +425,22 @@ func (cfg *Config) genComplexType(t *xsd.ComplexType) ([]spec, error) {
// Name the field after the xsd type name.
cfg.debugf("complexType %[1]s extends %[2]s, naming chardata struct field %[2]s",
t.Name.Local, b)
fields = append(fields, ast.NewIdent(b.String()), base, gen.String(`xml:",chardata"`))
case *xsd.ComplexType:
fields = append(fields, ast.NewIdent("Value"), expr, gen.String(`xml:",chardata"`))
default:
panic(fmt.Sprintf("%s does not derive from a builtin type", t.Name.Local))
}
}
if t.Extends {
expr, err := cfg.expr(t.Base)
if err != nil {
return nil, fmt.Errorf("%s base type %s: %v",
t.Name.Local, xsd.XMLName(t.Base).Local, err)
}
if b, ok := t.Base.(*xsd.ComplexType); ok {
// Use struct embedding when extending a complex type
cfg.debugf("complexType %s extends %s, embedding struct",
t.Name.Local, b.Name.Local)
fields = append(fields, nil, base, nil)
fields = append(fields, nil, expr, nil)
}
} else {
// When restricting a complex type, all attributes are "inherited" from
Expand Down
26 changes: 22 additions & 4 deletions xsdgen/xsdgen_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,20 @@ package xsdgen
import (
"io/ioutil"
"os"
"regexp"
"testing"
)

type testLogger testing.T

func grep(pattern, data string) bool {
matched, err := regexp.MatchString(pattern, data)
if err != nil {
panic(err)
}
return matched
}

func (t *testLogger) Printf(format string, v ...interface{}) {
t.Logf(format, v...)
}
Expand All @@ -27,7 +36,7 @@ func TestSoap(t *testing.T) {
func TestSimpleStruct(t *testing.T) {
testGen(t, "http://example.org/ns", "testdata/simple-struct.xsd")
}
func testGen(t *testing.T, ns string, files ...string) {
func testGen(t *testing.T, ns string, files ...string) string {
file, err := ioutil.TempFile("", "xsdgen")
if err != nil {
t.Fatal(err)
Expand All @@ -43,9 +52,18 @@ func testGen(t *testing.T, ns string, files ...string) {
if err != nil {
t.Error(err)
}
if data, err := ioutil.ReadFile(file.Name()); err != nil {
t.Error(err)
data, err := ioutil.ReadFile(file.Name())
if err != nil {
t.Fatal(err)
}
return string(data)
}

func TestMixedType(t *testing.T) {
data := testGen(t, "http://example.org", "testdata/mixed-complex.xsd")
if !grep(`PositiveNumber[^}]*,chardata`, data) {
t.Errorf("type decl for PositiveNumber did not contain chardata, got \n%s", data)
} else {
t.Logf("\n%s\n", data)
t.Logf("got \n%s", data)
}
}

0 comments on commit 219f388

Please sign in to comment.