Skip to content

Commit

Permalink
Merge pull request #107 from gdbc/master
Browse files Browse the repository at this point in the history
Support overriding default prefix, #, in Map keys  - SetGlobalKeyMapP…
  • Loading branch information
clbanning committed Nov 28, 2022
2 parents 8dc9e73 + f3c235f commit 9fb13b0
Show file tree
Hide file tree
Showing 8 changed files with 198 additions and 62 deletions.
115 changes: 115 additions & 0 deletions global_map_prefix_test.go
@@ -0,0 +1,115 @@
package mxj

import (
"testing"

"github.com/google/go-cmp/cmp"
)

var whiteSpaceDataSeqTest2 = []byte(`<books>
<book seq="1" ser="5">
<author>William T. Gaddis </author>
<title> The Recognitions </title>
<review> One of the great seminal American novels of the 20th century.</review>
</book>
<book seq="2">
<author>Austin Tappan Wright</author>
<title>Islandia</title>
<review>An example of earlier 20th century American utopian fiction.</review>
</book>
<book seq="3" ser="6">
<author> John Hawkes </author>
<title> The Beetle Leg </title>
<review> A lyrical novel about the construction of Ft. Peck Dam in Montana. </review>
</book>
</books>`)

func TestSetGlobalKeyMapPrefix(t *testing.T) {
prefixList := []struct {
name string
value string
}{
{
name: "Testing with % as Map Key Prefix",
value: "%",
},
{
name: "Testing with _ as Map Key Prefix",
value: "_",
},
{
name: "Testing with - as Map Key Prefix",
value: "-",
},
{
name: "Testing with & as Map Key Prefix",
value: "&",
},
}

for _, prefix := range prefixList {
t.Run(prefix.name, func(t *testing.T) {

// Testing MapSeq(Ordering) with whitespace and byte equivalence
DisableTrimWhiteSpace(true)
SetGlobalKeyMapPrefix(prefix.value)

m, err := NewMapFormattedXmlSeq(whiteSpaceDataSeqTest2)
if err != nil {
t.Fatal(err)
}

m1 := MapSeq(m)
x, err := m1.XmlIndent("", " ")
if err != nil {
t.Fatal(err)
}

if string(x) != string(whiteSpaceDataSeqTest2) {
t.Fatalf("expected\n'%s' \ngot \n'%s'", whiteSpaceDataSeqTest2, x)
}
DisableTrimWhiteSpace(false)

// Testing Map with whitespace and deep equivalence
DisableTrimWhiteSpace(true)
m3, err := NewMapXml(whiteSpaceDataSeqTest2)
if err != nil {
t.Fatal(err)
}

m4 := Map(m3)

if !cmp.Equal(m3, m4) {
t.Errorf("Maps unmatched using %s", prefix.value)
}
DisableTrimWhiteSpace(false)

// Testing MapSeq(Ordering) without whitespace and byte equivalence
m5, err := NewMapFormattedXmlSeq(whiteSpaceDataSeqTest2)
if err != nil {
t.Fatal(err)
}

m6 := MapSeq(m5)

if !cmp.Equal(m5, m6) {
t.Errorf("Maps unmatched using %s", prefix.value)
}

// Testing Map without whitespace and deep equivalence
m7, err := NewMapXml(whiteSpaceDataSeqTest2)
if err != nil {
t.Fatal(err)
}

m8 := Map(m7)

if !cmp.Equal(m7, m8) {
t.Errorf("Maps unmatched using %s", prefix.value)
}
})

}
SetGlobalKeyMapPrefix("#")

}
3 changes: 0 additions & 3 deletions go.mod

This file was deleted.

8 changes: 4 additions & 4 deletions keyvalues2_test.go
Expand Up @@ -27,8 +27,8 @@ func TestSetSubkeyFieldSeparator(t *testing.T) {
if len(vals) != 1 {
t.Fatal(":len(vals);", len(vals), vals)
}
if vals[0].(map[string]interface{})["#text"].(string) != "value 2" {
t.Fatal(":expecting: value 2; got:", vals[0].(map[string]interface{})["#text"])
if vals[0].(map[string]interface{})[textK].(string) != "value 2" {
t.Fatal(":expecting: value 2; got:", vals[0].(map[string]interface{})[textK])
}

SetFieldSeparator("|")
Expand All @@ -40,8 +40,8 @@ func TestSetSubkeyFieldSeparator(t *testing.T) {
if len(vals) != 1 {
t.Fatal("|len(vals);", len(vals), vals)
}
if vals[0].(map[string]interface{})["#text"].(string) != "value 2" {
t.Fatal("|expecting: value 2; got:", vals[0].(map[string]interface{})["#text"])
if vals[0].(map[string]interface{})[textK].(string) != "value 2" {
t.Fatal("|expecting: value 2; got:", vals[0].(map[string]interface{})[textK])
}
}

2 changes: 1 addition & 1 deletion leafnode.go
Expand Up @@ -44,7 +44,7 @@ func (mv Map) LeafNodes(no_attr ...bool) []LeafNode {

func getLeafNodes(path, node string, mv interface{}, l *[]LeafNode, noattr bool) {
// if stripping attributes, then also strip "#text" key
if !noattr || node != "#text" {
if !noattr || node != textK {
if path != "" && node[:1] != "[" {
path += "."
}
Expand Down
8 changes: 4 additions & 4 deletions updatevalues_test.go
Expand Up @@ -86,11 +86,11 @@ func TestUpdateValuesForPath_Author(t *testing.T) {
}
fmt.Println("\nnewDoc:", string(newDoc))
fmt.Println("m:", m)
fmt.Println("m.UpdateValuesForPath(\"#text:maybe not so simple element\", \"tag\")")
n, _ = m.UpdateValuesForPath("#text:maybe not so simple element", "tag")
fmt.Println("m.UpdateValuesForPath(\"" + textK + ":maybe not so simple element\", \"tag\")")
n, _ = m.UpdateValuesForPath(textK + ":maybe not so simple element", "tag")
fmt.Println("n:", n, "m:", m)
fmt.Println("m.UpdateValuesForPath(\"#text:simple element again\", \"*\")")
n, _ = m.UpdateValuesForPath("#text:simple element again", "*")
fmt.Println("m.UpdateValuesForPath(\"" + textK + ":simple element again\", \"*\")")
n, _ = m.UpdateValuesForPath(textK + ":simple element again", "*")
fmt.Println("n:", n, "m:", m)

/*
Expand Down
34 changes: 29 additions & 5 deletions xml.go
Expand Up @@ -22,6 +22,30 @@ import (
"time"
)

var (
textK = "#text"
seqK = "#seq"
commentK = "#comment"
attrK = "#attr"
directiveK = "#directive"
procinstK = "#procinst"
targetK = "#target"
instK = "#inst"
)

// Support overriding default Map keys prefix

func SetGlobalKeyMapPrefix(s string) {
textK = strings.ReplaceAll(textK, textK[0:1], s)
seqK = strings.ReplaceAll(seqK, seqK[0:1], s)
commentK = strings.ReplaceAll(commentK, commentK[0:1], s)
directiveK = strings.ReplaceAll(directiveK, directiveK[0:1], s)
procinstK = strings.ReplaceAll(procinstK, procinstK[0:1], s)
targetK = strings.ReplaceAll(targetK, targetK[0:1], s)
instK = strings.ReplaceAll(instK, instK[0:1], s)
attrK = strings.ReplaceAll(attrK, attrK[0:1], s)
}

// ------------------- NewMapXml & NewMapXmlReader ... -------------------------

// If XmlCharsetReader != nil, it will be used to decode the XML, if required.
Expand Down Expand Up @@ -441,7 +465,7 @@ func xmlToMapParser(skey string, a []xml.Attr, p *xml.Decoder, r bool) (map[stri
val.(map[string]interface{})["_seq"] = seq // will overwrite an "_seq" XML tag
seq++
case interface{}: // a non-nil simple element: string, float64, bool
v := map[string]interface{}{"#text": val}
v := map[string]interface{}{textK: val}
v["_seq"] = seq
seq++
val = v
Expand Down Expand Up @@ -479,7 +503,7 @@ func xmlToMapParser(skey string, a []xml.Attr, p *xml.Decoder, r bool) (map[stri
} else if len(n) == 1 && len(na) > 0 {
// it's a simple element w/ no attributes w/ subelements
for _, v := range n {
na["#text"] = v
na[textK] = v
}
n[skey] = na
}
Expand All @@ -492,7 +516,7 @@ func xmlToMapParser(skey string, a []xml.Attr, p *xml.Decoder, r bool) (map[stri
}
if len(tt) > 0 {
if len(na) > 0 || decodeSimpleValuesAsMap {
na["#text"] = cast(tt, r, "#text")
na[textK] = cast(tt, r, textK)
} else if skey != "" {
n[skey] = cast(tt, r, skey)
} else {
Expand Down Expand Up @@ -1115,7 +1139,7 @@ func marshalMapToXmlIndent(doIndent bool, b *bytes.Buffer, key string, value int

// simple element? Note: '#text" is an invalid XML tag.
isComplex := false
if v, ok := vv["#text"]; ok && n+1 == lenvv {
if v, ok := vv[textK]; ok && n+1 == lenvv {
// just the value and attributes
switch v.(type) {
case string:
Expand Down Expand Up @@ -1179,7 +1203,7 @@ func marshalMapToXmlIndent(doIndent bool, b *bytes.Buffer, key string, value int
elemlist := make([][2]interface{}, len(vv))
n = 0
for k, v := range vv {
if k == "#text" {
if k == textK {
// simple element handled above
continue
}
Expand Down
4 changes: 2 additions & 2 deletions xml_test.go
Expand Up @@ -23,7 +23,7 @@ func TestNewMapXml(t *testing.T) {
want := Map{"root2":
map[string]interface{}{
"newtag":
map[string]interface{}{"-newattr": "some_attr_value", "#text":"something more"},
map[string]interface{}{"-newattr": "some_attr_value", textK:"something more"},
"list":
map[string]interface{}{"-listattr":"val", "item":[]interface{}{"1", "2"}},
}}
Expand All @@ -48,7 +48,7 @@ func TestAttrHyphenFalse(t *testing.T) {
want := Map{"root2":
map[string]interface{}{
"newtag":
map[string]interface{}{"newattr": "some_attr_value", "#text":"something more"},
map[string]interface{}{"newattr": "some_attr_value", textK:"something more"},
"list":
map[string]interface{}{"listattr":"val", "item":[]interface{}{"1", "2"}},
}}
Expand Down

0 comments on commit 9fb13b0

Please sign in to comment.