diff --git a/README.md b/README.md
index ae95aa0..41d64ed 100644
--- a/README.md
+++ b/README.md
@@ -95,7 +95,7 @@ func main() {
### Implementation details ###
-The main objective was to use standard encoding/xml package for XML marshalling/unmarshalling. Unfortunately, in current implementation there is no graceful way to implement common structre for marshal and unmarshal functions - marshalling doesn't handle interface{} types so far (though, it could be changed in the future).
+The main objective was to use standard encoding/xml package for XML marshalling/unmarshalling. Unfortunately, in current implementation there is no graceful way to implement common structure for marshal and unmarshal functions - marshalling doesn't handle interface{} types so far (though, it could be changed in the future).
So, marshalling is implemented manually.
Unmarshalling code first creates temporary structure for unmarshalling XML into, then converts it into the passed variable using *reflect* package.
@@ -122,4 +122,3 @@ For the better understanding, I use terms 'rpc2xml' and 'xml2rpc' instead of 'ma
### TODO ###
* Add more corner cases tests
-
diff --git a/xml/rpc2xml.go b/xml/rpc2xml.go
index f073847..9930f61 100644
--- a/xml/rpc2xml.go
+++ b/xml/rpc2xml.go
@@ -101,12 +101,48 @@ func struct2XML(value interface{}) (out string) {
field := reflect.ValueOf(value).Field(i)
field_type := reflect.TypeOf(value).Field(i)
var name string
- if field_type.Tag.Get("xml") != "" {
- name = field_type.Tag.Get("xml")
+ tag := field_type.Tag.Get("xml")
+ omit_empty := false
+ if tag != "" {
+ if strings.Contains(tag, "omitempty") {
+ omit_empty = true
+ val := strings.Split(tag, ",")
+ if len(val) == 1 || val[0] == "" {
+ //omit if empty but no field name defined, use struct default
+ name = field_type.Name
+ } else {
+ name = val[0]
+ }
+ } else {
+ name = tag
+ }
} else {
name = field_type.Name
}
field_value, _ := rpc2XML(field.Interface())
+ if omit_empty {
+ //from encoding/xml Marshal():
+ //empty values are false, 0, any nil pointer or interface value, and any array, slice, map, or string of length zero.
+ switch field_value {
+ case "0":
+ continue
+ case "0":
+ continue
+ case "0":
+ continue
+ case "":
+ continue
+ case "":
+ continue
+ case "":
+ continue
+ case "":
+ continue
+ default:
+ //assume there's not an empty base64 string nor empty time
+ //field_value = field_value
+ }
+ }
field_name := fmt.Sprintf("%s", name)
out += fmt.Sprintf("%s%s", field_name, field_value)
}
diff --git a/xml/rpc2xml_test.go b/xml/rpc2xml_test.go
index 2904b39..2777ce2 100644
--- a/xml/rpc2xml_test.go
+++ b/xml/rpc2xml_test.go
@@ -74,3 +74,36 @@ func TestRpc2XmlNil(t *testing.T) {
t.Error("Got", xml)
}
}
+
+type TaggedStructRpc2Xml struct {
+ Actual ActualTaggedStructRpc2Xml
+}
+
+type ActualTaggedStructRpc2Xml struct {
+ Foo string `xml:"other"`
+ Bar int
+ NonEmptyUnnamed string `xml:",omitempty"`
+ NonEmptyNamed string `xml:"emptiness,omitempty"`
+ EmptyString string `xml:",omitempty"`
+ EmptyBool bool `xml:"boo,omitempty"`
+ EmptyArray []interface{} `xml:"ari,omitempty"`
+ EmptyStruct struct{} `xml:"struck,omitempty"`
+ EmptyNum int `xml:"numi,omitempty"`
+ Nilly *int `xml:"nowhere,omitempty"`
+}
+
+var emptyStruct struct{}
+
+func TestRPC2XmlTaggedStruct(t *testing.T) {
+ req := &TaggedStructRpc2Xml{ActualTaggedStructRpc2Xml{"testing", 123, "no tag name", "tag named", "", false, make([]interface{}, 0), emptyStruct, 0, nil}}
+ xml, err := rpcResponse2XML(req)
+ if err != nil {
+ t.Error("RPC2XML conversion failed", err)
+ }
+ expected := "othertestingBar123NonEmptyUnnamedno tag nameemptinesstag named"
+ if xml != expected {
+ t.Error("RPC2XML conversion of a tagged struct failed")
+ t.Error("Expected", expected)
+ t.Error("Got", xml)
+ }
+}
diff --git a/xml/xml2rpc.go b/xml/xml2rpc.go
index f22e90a..ab4276c 100644
--- a/xml/xml2rpc.go
+++ b/xml/xml2rpc.go
@@ -40,7 +40,7 @@ type value struct {
Boolean string `xml:"boolean"`
DateTime string `xml:"dateTime.iso8601"`
Base64 string `xml:"base64"`
- Raw string `xml:",innerxml"` // the value can be defualt string
+ Raw string `xml:",innerxml"` // the value can be default string
}
type member struct {
diff --git a/xml/xml2rpc_test.go b/xml/xml2rpc_test.go
index 751dad6..fd3f814 100644
--- a/xml/xml2rpc_test.go
+++ b/xml/xml2rpc_test.go
@@ -154,3 +154,36 @@ Requiredattribute'user'notfound:
}
}
}
+
+/* This set of test code returns:
+
+--- FAIL: TestXML2RPCTaggedStruct (0.00s)
+ xml2rpc_test.go:175: XML2RPC conversion to a tagged struct failed
+ xml2rpc_test.go:176: Expected &{{testing 123}}
+ xml2rpc_test.go:177: Got &{{ 123}}
+
+Can't unmarshall XML/XML-RPC data/content to go struct where XML field name differs from go struct member name, via struct tag?
+
+type TaggedStructXml2Rpc struct {
+ Actual ActualTaggedStructXml2Rpc
+}
+
+type ActualTaggedStructXml2Rpc struct {
+ Foo string `xml:"Other"`
+ Bar int
+}
+
+func TestXML2RPCTaggedStruct(t *testing.T) {
+ req := new(TaggedStructXml2Rpc)
+ err := xml2RPC("Some.MethodOthertestingBar123", req)
+ if err != nil {
+ t.Error("XML2RPC conversion failed", err)
+ }
+ expected_req := &TaggedStructXml2Rpc{ActualTaggedStructXml2Rpc{"testing", 123}}
+ if !reflect.DeepEqual(req, expected_req) {
+ t.Error("XML2RPC conversion to a tagged struct failed")
+ t.Error("Expected", expected_req)
+ t.Error("Got", req)
+ }
+}
+*/