fix: String() handled ns prefixes incorrectly

Previously parsing a document like this:

  <root xmlns:foo='http:/example.org/foo' foo:bar='1'/>

Would produce an incorrect document when turning it back into a string:

  <root xmlns:foo='http:/example.org/foo' http:/example.org/foo:bar='1'/>

This patch fixes this by implementing a proper lookup for namespace
prefixes.
This commit is contained in:
Felix Geisendörfer 2013-09-04 00:35:22 +02:00
parent 089e94f17d
commit 08c0943149
3 changed files with 47 additions and 1 deletions

17
node.go
View File

@ -500,7 +500,8 @@ func (this *Node) printElement(indent int) []byte {
for _, v := range this.Attributes { for _, v := range this.Attributes {
if len(v.Name.Space) > 0 { if len(v.Name.Space) > 0 {
b.WriteString(fmt.Sprintf(` %s:%s="%s"`, v.Name.Space, v.Name.Local, v.Value)) prefix := this.spacePrefix(v.Name.Space)
b.WriteString(fmt.Sprintf(` %s:%s="%s"`, prefix, v.Name.Local, v.Value))
} else { } else {
b.WriteString(fmt.Sprintf(` %s="%s"`, v.Name.Local, v.Value)) b.WriteString(fmt.Sprintf(` %s="%s"`, v.Name.Local, v.Value))
} }
@ -541,6 +542,20 @@ func (this *Node) printElement(indent int) []byte {
return b.Bytes() return b.Bytes()
} }
// spacePrefix resolves the given space (e.g. a url) to the prefix it was
// assigned by an attribute by the current node, or one of its parents.
func (this *Node) spacePrefix(space string) string {
for _, attr := range this.Attributes {
if attr.Name.Space == "xmlns" && attr.Value == space {
return attr.Name.Local
}
}
if this.Parent == nil {
return space
}
return this.Parent.spacePrefix(space)
}
// Add a child node // Add a child node
func (this *Node) AddChild(t *Node) { func (this *Node) AddChild(t *Node) {
if t.Parent != nil { if t.Parent != nil {

8
test3.xml Normal file
View File

@ -0,0 +1,8 @@
<root xmlns:foo='http:/example.org/foo'>
<child foo:bar='1'>
<grandchild xmlns:foo=''>
<great-grandchild foo:bar='2'>
</great-grandchild>
</grandchild>
</child>
</root>

View File

@ -136,3 +136,26 @@ func TestUnmarshal(t *testing.T) {
return return
} }
} }
func TestString(t *testing.T) {
doc := New()
err := doc.LoadFile("test3.xml", nil)
if err != nil {
t.Errorf("LoadFile(): %s", err)
return
}
expected := `<root xmlns:foo="http:/example.org/foo">
<child foo:bar="1">
<grandchild xmlns:foo="">
<great-grandchild bar="2" />
</grandchild>
</child>
</root>
`
if got := doc.Root.String(); got != expected {
t.Fatalf("expected: %s\ngot: %s\n", expected, got)
}
}