From c085b35fb9a66c8b44fb0ace0f4a0a5732955e53 Mon Sep 17 00:00:00 2001 From: jimt Date: Sun, 25 Nov 2012 23:46:56 +0100 Subject: [PATCH] Adds optional indented output for the Node.String() and Node.Bytes() methods. Set the global `IndentPrefix` var to a tab or spaces to enable indented output. The existing API has not been changed. This addresses issue #7. --- document.go | 5 ++++- node.go | 52 +++++++++++++++++++++++++++++++++++++--------------- test1.xml | 51 ++++++++++++++++++++++++++++++++++++++++++++++++++- xmlx_test.go | 1 + 4 files changed, 92 insertions(+), 17 deletions(-) diff --git a/document.go b/document.go index 1cade3c..b9131f0 100644 --- a/document.go +++ b/document.go @@ -29,7 +29,6 @@ package xmlx import ( "bytes" - //"code.google.com/p/go-charset/charset" "encoding/xml" "errors" "fmt" @@ -206,6 +205,10 @@ func (this *Document) SaveBytes() []byte { if this.SaveDocType { b.WriteString(fmt.Sprintf(``, this.Version, this.Encoding, this.StandAlone)) + + if len(IndentPrefix) > 0 { + b.WriteByte('\n') + } } b.Write(this.Root.Bytes()) diff --git a/node.go b/node.go index e20181a..8618804 100644 --- a/node.go +++ b/node.go @@ -9,6 +9,7 @@ import ( "encoding/xml" "fmt" "strconv" + "strings" ) const ( @@ -19,6 +20,11 @@ const ( NT_ELEMENT ) +// IndentPrefix holds the value for a single identation level, if one +// chooses to want indentation in the node.String() and node.Bytes() output. +// This would normally be set to a single tab, or a number of spaces. +var IndentPrefix = "" + type Attr struct { Name xml.Name // Attribute namespace and name. Value string // Attribute value. @@ -45,7 +51,7 @@ func NewNode(tid byte) *Node { // This wraps the standard xml.Unmarshal function and supplies this particular // node as the content to be unmarshalled. func (this *Node) Unmarshal(obj interface{}) error { - return xml.NewDecoder(bytes.NewBuffer(this.Bytes())).Decode(obj) + return xml.NewDecoder(bytes.NewBuffer(this.bytes(0))).Decode(obj) } // Get node value as string @@ -258,18 +264,20 @@ func rec_SelectNodes(cn *Node, namespace, name string, list *[]*Node, recurse bo // Note that NT_ROOT is a special-case empty node used as the root for a // Document. This one has no representation by itself. It merely forwards the // String() call to it's child nodes. -func (this *Node) Bytes() (b []byte) { +func (this *Node) Bytes() []byte { return this.bytes(0) } + +func (this *Node) bytes(indent int) (b []byte) { switch this.Type { case NT_PROCINST: - b = this.printProcInst() + b = this.printProcInst(indent) case NT_COMMENT: - b = this.printComment() + b = this.printComment(indent) case NT_DIRECTIVE: - b = this.printDirective() + b = this.printDirective(indent) case NT_ELEMENT: - b = this.printElement() + b = this.printElement(indent) case NT_ROOT: - b = this.printRoot() + b = this.printRoot(indent) } return } @@ -279,32 +287,38 @@ func (this *Node) Bytes() (b []byte) { // Document. This one has no representation by itself. It merely forwards the // String() call to it's child nodes. func (this *Node) String() (s string) { - return string(this.Bytes()) + return string(this.bytes(0)) } -func (this *Node) printRoot() []byte { +func (this *Node) printRoot(indent int) []byte { var b bytes.Buffer for _, v := range this.Children { - b.Write(v.Bytes()) + b.Write(v.bytes(indent)) } return b.Bytes() } -func (this *Node) printProcInst() []byte { +func (this *Node) printProcInst(indent int) []byte { return []byte("") } -func (this *Node) printComment() []byte { +func (this *Node) printComment(indent int) []byte { return []byte("") } -func (this *Node) printDirective() []byte { +func (this *Node) printDirective(indent int) []byte { return []byte("") } -func (this *Node) printElement() []byte { +func (this *Node) printElement(indent int) []byte { var b bytes.Buffer + lineSuffix, linePrefix := "", strings.Repeat(IndentPrefix, indent) + if len(IndentPrefix) > 0 { + lineSuffix = "\n" + } + + b.WriteString(linePrefix) if len(this.Name.Space) > 0 { b.WriteRune('<') b.WriteString(this.Name.Space) @@ -325,16 +339,23 @@ func (this *Node) printElement() []byte { if len(this.Children) == 0 && len(this.Value) == 0 { b.WriteString(" />") + b.WriteString(lineSuffix) return b.Bytes() } b.WriteRune('>') + if len(this.Value) == 0 { + b.WriteString(lineSuffix) + } for _, v := range this.Children { - b.Write(v.Bytes()) + b.Write(v.bytes(indent + 1)) } b.WriteString(this.Value) + if len(this.Value) == 0 { + b.WriteString(linePrefix) + } if len(this.Name.Space) > 0 { b.WriteString("') } + b.WriteString(lineSuffix) return b.Bytes() } diff --git a/test1.xml b/test1.xml index db44efa..1a59ac9 100644 --- a/test1.xml +++ b/test1.xml @@ -1 +1,50 @@ -WriteTheWebhttp://writetheweb.comNews for web users that write backen-usCopyright 2000, WriteTheWeb team.editor@writetheweb.comwebmaster@writetheweb.comWriteTheWebhttp://writetheweb.com/images/mynetscape88.gifhttp://writetheweb.com8831News for web users that write backGiving the world a pluggable Gnutellahttp://writetheweb.com/read.php?item=24WorldOS is a framework on which to build programs that work like Freenet or Gnutella -allowing distributed applications using peer-to-peer routing.Syndication discussions hot uphttp://writetheweb.com/read.php?item=23After a period of dormancy, the Syndication mailing list has become active again, with contributions from leaders in traditional media and Web syndication.Personal web server integrates file sharing and messaginghttp://writetheweb.com/read.php?item=22The Magi Project is an innovative project to create a combined personal web server and messaging system that enables the sharing and synchronization of information across desktop, laptop and palmtop devices.Syndication and Metadatahttp://writetheweb.com/read.php?item=21RSS is probably the best known metadata format around. RDF is probably one of the least understood. In this essay, published on my O'Reilly Network weblog, I argue that the next generation of RSS should be based on RDF.UK bloggers get organisedhttp://writetheweb.com/read.php?item=20Looks like the weblogs scene is gathering pace beyond the shores of the US. There's now a UK-specific page on weblogs.com, and a mailing list at egroups.Yournamehere.com more important than anythinghttp://writetheweb.com/read.php?item=19Whatever you're publishing on the web, your site name is the most valuable asset you have, according to Carl Steadman. \ No newline at end of file + + + + WriteTheWeb + http://writetheweb.com + News for web users that write back + en-us + Copyright 2000, WriteTheWeb team. + editor@writetheweb.com + webmaster@writetheweb.com + + WriteTheWeb + http://writetheweb.com/images/mynetscape88.gif + http://writetheweb.com + 88 + 31 + News for web users that write back + + + Giving the world a pluggable Gnutella + http://writetheweb.com/read.php?item=24 + WorldOS is a framework on which to build programs that work like Freenet or Gnutella -allowing distributed applications using peer-to-peer routing. + + + Syndication discussions hot up + http://writetheweb.com/read.php?item=23 + After a period of dormancy, the Syndication mailing list has become active again, with contributions from leaders in traditional media and Web syndication. + + + Personal web server integrates file sharing and messaging + http://writetheweb.com/read.php?item=22 + The Magi Project is an innovative project to create a combined personal web server and messaging system that enables the sharing and synchronization of information across desktop, laptop and palmtop devices. + + + Syndication and Metadata + http://writetheweb.com/read.php?item=21 + RSS is probably the best known metadata format around. RDF is probably one of the least understood. In this essay, published on my O'Reilly Network weblog, I argue that the next generation of RSS should be based on RDF. + + + UK bloggers get organised + http://writetheweb.com/read.php?item=20 + Looks like the weblogs scene is gathering pace beyond the shores of the US. There's now a UK-specific page on weblogs.com, and a mailing list at egroups. + + + Yournamehere.com more important than anything + http://writetheweb.com/read.php?item=19 + Whatever you're publishing on the web, your site name is the most valuable asset you have, according to Carl Steadman. + + + diff --git a/xmlx_test.go b/xmlx_test.go index 8a3414a..97fe4de 100644 --- a/xmlx_test.go +++ b/xmlx_test.go @@ -74,6 +74,7 @@ func TestSave(t *testing.T) { return } + IndentPrefix = "\t" if err := doc.SaveFile("test1.xml"); err != nil { t.Errorf("SaveFile(): %s", err) return