mirror of
https://github.com/golang/go
synced 2024-11-22 10:54:46 -07:00
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
This commit is contained in:
parent
0fc441b053
commit
aed20a6951
43
src/pkg/encoding/xml/example_test.go
Normal file
43
src/pkg/encoding/xml/example_test.go
Normal file
@ -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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// <person id="13">
|
||||||
|
// <name>
|
||||||
|
// <first>John</first>
|
||||||
|
// <last>Doe</last>
|
||||||
|
// </name>
|
||||||
|
// <age>42</age>
|
||||||
|
// <Married>false</Married>
|
||||||
|
// <!-- Need more fields. -->
|
||||||
|
// </person>
|
||||||
|
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)
|
||||||
|
}
|
@ -60,32 +60,9 @@ const (
|
|||||||
//
|
//
|
||||||
// If a field uses a tag "a>b>c", then the element c will be nested inside
|
// 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
|
// 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 {
|
// See MarshalIndent for an example.
|
||||||
// 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:
|
|
||||||
//
|
|
||||||
// <result>
|
|
||||||
// <person id="13">
|
|
||||||
// <name>
|
|
||||||
// <first>John</first>
|
|
||||||
// <last>Doe</last>
|
|
||||||
// </name>
|
|
||||||
// <age>42</age>
|
|
||||||
// <married>false</married>
|
|
||||||
// </person>
|
|
||||||
// </result>
|
|
||||||
//
|
//
|
||||||
// Marshal will return an error if asked to marshal a channel, function, or map.
|
// Marshal will return an error if asked to marshal a channel, function, or map.
|
||||||
func Marshal(v interface{}) ([]byte, error) {
|
func Marshal(v interface{}) ([]byte, error) {
|
||||||
@ -96,6 +73,22 @@ func Marshal(v interface{}) ([]byte, error) {
|
|||||||
return b.Bytes(), nil
|
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.
|
// An Encoder writes XML data to an output stream.
|
||||||
type Encoder struct {
|
type Encoder struct {
|
||||||
printer
|
printer
|
||||||
@ -103,7 +96,7 @@ type Encoder struct {
|
|||||||
|
|
||||||
// NewEncoder returns a new encoder that writes to w.
|
// NewEncoder returns a new encoder that writes to w.
|
||||||
func NewEncoder(w io.Writer) *Encoder {
|
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.
|
// Encode writes the XML encoding of v to the stream.
|
||||||
@ -118,8 +111,14 @@ func (enc *Encoder) Encode(v interface{}) error {
|
|||||||
|
|
||||||
type printer struct {
|
type printer struct {
|
||||||
*bufio.Writer
|
*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 {
|
func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo) error {
|
||||||
if !val.IsValid() {
|
if !val.IsValid() {
|
||||||
return nil
|
return nil
|
||||||
@ -177,6 +176,7 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p.writeIndent(1)
|
||||||
p.WriteByte('<')
|
p.WriteByte('<')
|
||||||
p.WriteString(name)
|
p.WriteString(name)
|
||||||
|
|
||||||
@ -216,6 +216,7 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p.writeIndent(-1)
|
||||||
p.WriteByte('<')
|
p.WriteByte('<')
|
||||||
p.WriteByte('/')
|
p.WriteByte('/')
|
||||||
p.WriteString(name)
|
p.WriteString(name)
|
||||||
@ -294,6 +295,7 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
|
|||||||
if vf.Len() == 0 {
|
if vf.Len() == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
p.writeIndent(0)
|
||||||
p.WriteString("<!--")
|
p.WriteString("<!--")
|
||||||
dashDash := false
|
dashDash := false
|
||||||
dashLast := false
|
dashLast := false
|
||||||
@ -352,6 +354,33 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *printer) writeIndent(depthDelta int) {
|
||||||
|
if len(p.prefix) == 0 && len(p.indent) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if depthDelta < 0 {
|
||||||
|
p.depth--
|
||||||
|
if p.indentedIn {
|
||||||
|
p.indentedIn = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.indentedIn = false
|
||||||
|
}
|
||||||
|
p.WriteByte('\n')
|
||||||
|
if len(p.prefix) > 0 {
|
||||||
|
p.WriteString(p.prefix)
|
||||||
|
}
|
||||||
|
if len(p.indent) > 0 {
|
||||||
|
for i := 0; i < p.depth; i++ {
|
||||||
|
p.WriteString(p.indent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if depthDelta > 0 {
|
||||||
|
p.depth++
|
||||||
|
p.indentedIn = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type parentStack struct {
|
type parentStack struct {
|
||||||
*printer
|
*printer
|
||||||
stack []string
|
stack []string
|
||||||
@ -367,20 +396,20 @@ func (s *parentStack) trim(parents []string) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := len(s.stack) - 1; i >= split; i-- {
|
for i := len(s.stack) - 1; i >= split; i-- {
|
||||||
|
s.writeIndent(-1)
|
||||||
s.WriteString("</")
|
s.WriteString("</")
|
||||||
s.WriteString(s.stack[i])
|
s.WriteString(s.stack[i])
|
||||||
s.WriteByte('>')
|
s.WriteByte('>')
|
||||||
}
|
}
|
||||||
|
|
||||||
s.stack = parents[:split]
|
s.stack = parents[:split]
|
||||||
}
|
}
|
||||||
|
|
||||||
// push adds parent elements to the stack and writes open tags.
|
// push adds parent elements to the stack and writes open tags.
|
||||||
func (s *parentStack) push(parents []string) {
|
func (s *parentStack) push(parents []string) {
|
||||||
for i := 0; i < len(parents); i++ {
|
for i := 0; i < len(parents); i++ {
|
||||||
s.WriteString("<")
|
s.writeIndent(1)
|
||||||
|
s.WriteByte('<')
|
||||||
s.WriteString(parents[i])
|
s.WriteString(parents[i])
|
||||||
s.WriteByte('>')
|
s.WriteByte('>')
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user