Skip to content

Commit

Permalink
address issue #3 and #4
Browse files Browse the repository at this point in the history
  • Loading branch information
clbanning committed Jul 26, 2018
1 parent 49825d7 commit c68e01f
Show file tree
Hide file tree
Showing 4 changed files with 187 additions and 24 deletions.
53 changes: 31 additions & 22 deletions anyxml.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// anyxml - marshal an XML document from almost any Go variable.
// Marshal XML from map[string]interface{}, arrays, slices, alpha/numeric, etc.
//
// Marshal XML from map[string]interface{}, arrays, slices, alpha/numeric, etc.
//
// Wraps xml.Marshal with functionality in github.com/clbanning/mxj to create
// a more genericized XML marshaling capability. Note: unmarshaling the resultant
// XML may not return the original value, since tag labels may have been injected
Expand All @@ -11,13 +11,13 @@
/*
Encode an arbitrary JSON object.
package main
import (
"encoding/json"
"fmt"
"github.com/clbanning/anyxml"
)
func main() {
jsondata := []byte(`[
{ "somekey":"somevalue" },
Expand All @@ -36,7 +36,7 @@
}
fmt.Println(string(x))
}
output:
<mydoc>
<somekey>somevalue</somekey>
Expand All @@ -54,6 +54,18 @@ import (

// Encode arbitrary value as XML. Note: there are no guarantees.
func Xml(v interface{}, rootTag ...string) ([]byte, error) {
var rt string
if len(rootTag) == 1 {
rt = rootTag[0]
} else {
rt = DefaultRootTag
}
if v == nil {
if UseGoEmptyElementSyntax {
return []byte("<" + rt + "></" + rt + ">"), nil
}
return []byte("<" + rt + "/>"), nil
}
if reflect.TypeOf(v).Kind() == reflect.Struct {
return xml.Marshal(v)
}
Expand All @@ -62,13 +74,6 @@ func Xml(v interface{}, rootTag ...string) ([]byte, error) {
s := new(string)
p := new(pretty)

var rt string
if len(rootTag) == 1 {
rt = rootTag[0]
} else {
rt = DefaultRootTag
}

var ss string
var b []byte
switch v.(type) {
Expand All @@ -95,7 +100,7 @@ func Xml(v interface{}, rootTag ...string) ([]byte, error) {
ss += *s + "</" + rt + ">"
b = []byte(ss)
case map[string]interface{}:
b, err = anyxml(v.(map[string]interface{}),rootTag...)
b, err = anyxml(v.(map[string]interface{}), rootTag...)
default:
err = mapToXmlIndent(false, s, rt, v, p)
b = []byte(*s)
Expand All @@ -104,9 +109,20 @@ func Xml(v interface{}, rootTag ...string) ([]byte, error) {
return b, err
}


// Encode an arbitrary value as a pretty XML string. Note: there are no guarantees.
func XmlIndent(v interface{}, prefix, indent string, rootTag ...string) ([]byte, error) {
var rt string
if len(rootTag) == 1 {
rt = rootTag[0]
} else {
rt = DefaultRootTag
}
if v == nil {
if UseGoEmptyElementSyntax {
return []byte(prefix + "<" + rt + ">\n" + prefix + "</" + rt + ">"), nil
}
return []byte(prefix + "<" + rt + "/>"), nil
}
if reflect.TypeOf(v).Kind() == reflect.Struct {
return xml.MarshalIndent(v, prefix, indent)
}
Expand All @@ -117,13 +133,6 @@ func XmlIndent(v interface{}, prefix, indent string, rootTag ...string) ([]byte,
p.indent = indent
p.padding = prefix

var rt string
if len(rootTag) == 1 {
rt = rootTag[0]
} else {
rt = DefaultRootTag
}

var ss string
var b []byte
switch v.(type) {
Expand Down Expand Up @@ -154,7 +163,7 @@ func XmlIndent(v interface{}, prefix, indent string, rootTag ...string) ([]byte,
ss += *s + "</" + rt + ">"
b = []byte(ss)
case map[string]interface{}:
b, err = anyxmlIndent(v.(map[string]interface{}),prefix, indent, rootTag...)
b, err = anyxmlIndent(v.(map[string]interface{}), prefix, indent, rootTag...)
default:
err = mapToXmlIndent(true, s, rt, v, p)
b = []byte(*s)
Expand Down
105 changes: 105 additions & 0 deletions nil_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package anyxml

import (
"fmt"
"testing"
)

func TestNilHeader2(t *testing.T) {
fmt.Println("\n---------------- nil_test.go ...")
}

func TestNilMap(t *testing.T) {
checkval := "<root/>"
xmlout, err := Xml(nil, "root")
if err != nil {
t.Fatal(err)
}
if string(xmlout) != checkval {
fmt.Println(string(xmlout), "!=", checkval)
t.Fatal()
}

checkval = " <root/>"
xmlout, err = XmlIndent(nil, " ", " ", "root")
if err != nil {
t.Fatal(err)
}
if string(xmlout) != checkval {
fmt.Println(string(xmlout), "!=", checkval)
t.Fatal()
}

// use Go XML marshal syntax for empty element"
UseGoEmptyElementSyntax = true
checkval = "<root></root>"
xmlout, err = Xml(nil, "root")
if err != nil {
t.Fatal(err)
}
if string(xmlout) != checkval {
fmt.Println(string(xmlout), "!=", checkval)
t.Fatal()
}

checkval = ` <root>
</root>`
xmlout, err = XmlIndent(nil, " ", " ", "root")
if err != nil {
t.Fatal(err)
}
if string(xmlout) != checkval {
fmt.Println(string(xmlout), "!=", checkval)
t.Fatal()
}
}

func TestNilValue(t *testing.T) {
val := map[string]interface{}{"toplevel": nil}
checkval := "<root><toplevel/></root>"

UseGoEmptyElementSyntax = false
xmlout, err := Xml(val, "root")
if err != nil {
t.Fatal(err)
}
if string(xmlout) != checkval {
fmt.Println(string(xmlout), "!=", checkval)
t.Fatal()
}

checkval = ` <root>
<toplevel/>
</root>`
xmlout, err = XmlIndent(val, " ", " ", "root")
if err != nil {
t.Fatal(err)
}
if string(xmlout) != checkval {
fmt.Println(string(xmlout), "!=", checkval)
t.Fatal()
}

UseGoEmptyElementSyntax = true
checkval = "<root><toplevel></toplevel></root>"
xmlout, err = Xml(val, "root")
if err != nil {
t.Fatal(err)
}
if string(xmlout) != checkval {
fmt.Println(string(xmlout), "!=", checkval)
t.Fatal()
}

checkval = ` <root>
<toplevel></toplevel>
</root>`
xmlout, err = XmlIndent(val, " ", " ", "root")
if err != nil {
t.Fatal(err)
}
if string(xmlout) != checkval {
fmt.Println(string(xmlout), "!=", checkval)
t.Fatal()
}
}
4 changes: 2 additions & 2 deletions xml.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (

// --------------------------------- Xml, XmlIndent - from mxj -------------------------------

const (
var (
DefaultRootTag = "doc"
UseGoEmptyElementSyntax = false // if 'true' encode empty element as "<tag></tag>" instead of "<tag/>
)
Expand Down Expand Up @@ -363,7 +363,7 @@ func mapToXmlIndent(doIndent bool, s *string, key string, value interface{}, pp
}
}
switch value.(type) {
case map[string]interface{}, []byte, string, float64, bool, int, int32, int64, float32:
case map[string]interface{}, []byte, string, float64, bool, int, int32, int64, float32, nil:
if elen > 0 || UseGoEmptyElementSyntax {
if elen == 0 {
*s += ">"
Expand Down
49 changes: 49 additions & 0 deletions xml_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package anyxml

import (
"encoding/json"
"fmt"
"testing"
)

func TestAnyXmlHeader2(t *testing.T) {
fmt.Println("\n---------------- xml_test.go ...")
}

var anydata2 = []byte(`{ "element":[
{
"somekey": "somevalue"
},
{
"somekey": "somevalue"
},
{
"somekey": "somevalue",
"someotherkey": "someothervalue"
},
"a string",
3.14159625,
true
]}`)

func TestXml2(t *testing.T) {
var i interface{}
err := json.Unmarshal(anydata2, &i)
x, err := Xml(i)
if err != nil {
t.Fatal(err)
}
fmt.Println("[]->x:", string(x))

}

func TestXmlIndent2(t *testing.T) {
var i interface{}
err := json.Unmarshal(anydata2, &i)
x, err := XmlIndent(i, "", " ")
if err != nil {
t.Fatal(err)
}
fmt.Println("[]->x:\n", string(x))

}

0 comments on commit c68e01f

Please sign in to comment.