From aed20a6951948ef7f6edd1f4160fc8c1d3e8df56 Mon Sep 17 00:00:00 2001 From: Gustavo Niemeyer Date: Thu, 16 Feb 2012 02:01:46 -0200 Subject: [PATCH] encoding/xml: add MarshalIndent and move the example An unindented XML example is hard to follow. MarshalIndent allows moving the example over to a test file (and fixing it). R=golang-dev, r, gustavo, r, rsc CC=golang-dev https://golang.org/cl/5674050 --- src/pkg/encoding/xml/example_test.go | 43 ++++++++++++++ src/pkg/encoding/xml/marshal.go | 87 ++++++++++++++++++---------- 2 files changed, 101 insertions(+), 29 deletions(-) create mode 100644 src/pkg/encoding/xml/example_test.go diff --git a/src/pkg/encoding/xml/example_test.go b/src/pkg/encoding/xml/example_test.go new file mode 100644 index 00000000000..2f0c1747ced --- /dev/null +++ b/src/pkg/encoding/xml/example_test.go @@ -0,0 +1,43 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package xml_test + +import ( + "encoding/xml" + "fmt" + "os" +) + +// +// +// John +// Doe +// +// 42 +// false +// +// +func ExampleMarshalIndent() { + type Person struct { + XMLName xml.Name `xml:"person"` + Id int `xml:"id,attr"` + FirstName string `xml:"name>first"` + LastName string `xml:"name>last"` + Age int `xml:"age"` + Height float32 `xml:"height,omitempty"` + Married bool + Comment string `xml:",comment"` + } + + v := &Person{Id: 13, FirstName: "John", LastName: "Doe", Age: 42} + v.Comment = " Need more fields. " + + output, err := xml.MarshalIndent(v, "\t", "\t") + if err != nil { + fmt.Printf("error: %v\n", err) + } + + os.Stdout.Write(output) +} diff --git a/src/pkg/encoding/xml/marshal.go b/src/pkg/encoding/xml/marshal.go index a96c523d553..25d88c4619b 100644 --- a/src/pkg/encoding/xml/marshal.go +++ b/src/pkg/encoding/xml/marshal.go @@ -60,32 +60,9 @@ const ( // // If a field uses a tag "a>b>c", then the element c will be nested inside // parent elements a and b. Fields that appear next to each other that name -// the same parent will be enclosed in one XML element. For example: +// the same parent will be enclosed in one XML element. // -// type Result struct { -// XMLName xml.Name `xml:"result"` -// Id int `xml:"id,attr"` -// FirstName string `xml:"person>name>first"` -// LastName string `xml:"person>name>last"` -// Age int `xml:"person>age"` -// Height float `xml:"person>height,omitempty"` -// Married bool `xml:"person>married"` -// } -// -// xml.Marshal(&Result{Id: 13, FirstName: "John", LastName: "Doe", Age: 42}) -// -// would be marshalled as: -// -// -// -// -// John -// Doe -// -// 42 -// false -// -// +// See MarshalIndent for an example. // // Marshal will return an error if asked to marshal a channel, function, or map. func Marshal(v interface{}) ([]byte, error) { @@ -96,6 +73,22 @@ func Marshal(v interface{}) ([]byte, error) { return b.Bytes(), nil } +// MarshalIndent works like Marshal, but each XML element begins on a new +// indented line that starts with prefix and is followed by one or more +// copies of indent according to the nesting depth. +func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error) { + var b bytes.Buffer + enc := NewEncoder(&b) + enc.prefix = prefix + enc.indent = indent + err := enc.marshalValue(reflect.ValueOf(v), nil) + enc.Flush() + if err != nil { + return nil, err + } + return b.Bytes(), nil +} + // An Encoder writes XML data to an output stream. type Encoder struct { printer @@ -103,7 +96,7 @@ type Encoder struct { // NewEncoder returns a new encoder that writes to w. func NewEncoder(w io.Writer) *Encoder { - return &Encoder{printer{bufio.NewWriter(w)}} + return &Encoder{printer{Writer: bufio.NewWriter(w)}} } // Encode writes the XML encoding of v to the stream. @@ -118,8 +111,14 @@ func (enc *Encoder) Encode(v interface{}) error { type printer struct { *bufio.Writer + indent string + prefix string + depth int + indentedIn bool } +// marshalValue writes one or more XML elements representing val. +// If val was obtained from a struct field, finfo must have its details. func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo) error { if !val.IsValid() { return nil @@ -177,6 +176,7 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo) error { } } + p.writeIndent(1) p.WriteByte('<') p.WriteString(name) @@ -216,6 +216,7 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo) error { return err } + p.writeIndent(-1) p.WriteByte('<') p.WriteByte('/') p.WriteString(name) @@ -294,6 +295,7 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error { if vf.Len() == 0 { continue } + p.writeIndent(0) p.WriteString("