mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
encoding/xml: improve package based on the suggestions from metalinter
Existing code in encoding/xml packages contains code which breaks various linter rules (comments, constant and variable naming, variable shadowing, etc). Fixes #21578 Change-Id: Id4bd9a9be6d5728ce88fb6efe33030ef943c078c Reviewed-on: https://go-review.googlesource.com/58210 Reviewed-by: Sam Whited <sam@samwhited.com> Reviewed-by: Ian Lance Taylor <iant@golang.org> Run-TryBot: Sam Whited <sam@samwhited.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
77b4beba2f
commit
6e9e9dfa46
8 changed files with 103 additions and 94 deletions
|
|
@ -12,20 +12,20 @@ var atomValue = &Feed{
|
||||||
Link: []Link{{Href: "http://example.org/"}},
|
Link: []Link{{Href: "http://example.org/"}},
|
||||||
Updated: ParseTime("2003-12-13T18:30:02Z"),
|
Updated: ParseTime("2003-12-13T18:30:02Z"),
|
||||||
Author: Person{Name: "John Doe"},
|
Author: Person{Name: "John Doe"},
|
||||||
Id: "urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6",
|
ID: "urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6",
|
||||||
|
|
||||||
Entry: []Entry{
|
Entry: []Entry{
|
||||||
{
|
{
|
||||||
Title: "Atom-Powered Robots Run Amok",
|
Title: "Atom-Powered Robots Run Amok",
|
||||||
Link: []Link{{Href: "http://example.org/2003/12/13/atom03"}},
|
Link: []Link{{Href: "http://example.org/2003/12/13/atom03"}},
|
||||||
Id: "urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a",
|
ID: "urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a",
|
||||||
Updated: ParseTime("2003-12-13T18:30:02Z"),
|
Updated: ParseTime("2003-12-13T18:30:02Z"),
|
||||||
Summary: NewText("Some text."),
|
Summary: NewText("Some text."),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
var atomXml = `` +
|
var atomXML = `` +
|
||||||
`<feed xmlns="http://www.w3.org/2005/Atom" updated="2003-12-13T18:30:02Z">` +
|
`<feed xmlns="http://www.w3.org/2005/Atom" updated="2003-12-13T18:30:02Z">` +
|
||||||
`<title>Example Feed</title>` +
|
`<title>Example Feed</title>` +
|
||||||
`<id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>` +
|
`<id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>` +
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,11 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// A generic XML header suitable for use with the output of Marshal.
|
// Header is a generic XML header suitable for use with the output of Marshal.
|
||||||
// This is not automatically added to any output of this package,
|
// This is not automatically added to any output of this package,
|
||||||
// it is provided as a convenience.
|
// it is provided as a convenience.
|
||||||
Header = `<?xml version="1.0" encoding="UTF-8"?>` + "\n"
|
Header = `<?xml version="1.0" encoding="UTF-8"?>` + "\n"
|
||||||
|
xmlNamespacePrefix = "xml"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Marshal returns the XML encoding of v.
|
// Marshal returns the XML encoding of v.
|
||||||
|
|
@ -320,7 +321,7 @@ func (p *printer) createAttrPrefix(url string) string {
|
||||||
// (The "http://www.w3.org/2000/xmlns/" name space is also predefined as "xmlns",
|
// (The "http://www.w3.org/2000/xmlns/" name space is also predefined as "xmlns",
|
||||||
// but users should not be trying to use that one directly - that's our job.)
|
// but users should not be trying to use that one directly - that's our job.)
|
||||||
if url == xmlURL {
|
if url == xmlURL {
|
||||||
return "xml"
|
return xmlNamespacePrefix
|
||||||
}
|
}
|
||||||
|
|
||||||
// Need to define a new name space.
|
// Need to define a new name space.
|
||||||
|
|
@ -1011,7 +1012,7 @@ func (s *parentStack) push(parents []string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// A MarshalXMLError is returned when Marshal encounters a type
|
// UnsupportedTypeError is returned when Marshal encounters a type
|
||||||
// that cannot be converted into XML.
|
// that cannot be converted into XML.
|
||||||
type UnsupportedTypeError struct {
|
type UnsupportedTypeError struct {
|
||||||
Type reflect.Type
|
Type reflect.Type
|
||||||
|
|
|
||||||
|
|
@ -646,7 +646,7 @@ var marshalTests = []struct {
|
||||||
{Value: &Universe{Visible: 9.3e13}, ExpectXML: `<universe>9.3e+13</universe>`},
|
{Value: &Universe{Visible: 9.3e13}, ExpectXML: `<universe>9.3e+13</universe>`},
|
||||||
{Value: &Particle{HasMass: true}, ExpectXML: `<particle>true</particle>`},
|
{Value: &Particle{HasMass: true}, ExpectXML: `<particle>true</particle>`},
|
||||||
{Value: &Departure{When: ParseTime("2013-01-09T00:15:00-09:00")}, ExpectXML: `<departure>2013-01-09T00:15:00-09:00</departure>`},
|
{Value: &Departure{When: ParseTime("2013-01-09T00:15:00-09:00")}, ExpectXML: `<departure>2013-01-09T00:15:00-09:00</departure>`},
|
||||||
{Value: atomValue, ExpectXML: atomXml},
|
{Value: atomValue, ExpectXML: atomXML},
|
||||||
{
|
{
|
||||||
Value: &Ship{
|
Value: &Ship{
|
||||||
Name: "Heart of Gold",
|
Name: "Heart of Gold",
|
||||||
|
|
@ -1910,7 +1910,7 @@ func BenchmarkMarshal(b *testing.B) {
|
||||||
|
|
||||||
func BenchmarkUnmarshal(b *testing.B) {
|
func BenchmarkUnmarshal(b *testing.B) {
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
xml := []byte(atomXml)
|
xml := []byte(atomXML)
|
||||||
b.RunParallel(func(pb *testing.PB) {
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
for pb.Next() {
|
for pb.Next() {
|
||||||
Unmarshal(xml, &Feed{})
|
Unmarshal(xml, &Feed{})
|
||||||
|
|
|
||||||
|
|
@ -192,19 +192,19 @@ func receiverType(val interface{}) string {
|
||||||
|
|
||||||
// unmarshalInterface unmarshals a single XML element into val.
|
// unmarshalInterface unmarshals a single XML element into val.
|
||||||
// start is the opening tag of the element.
|
// start is the opening tag of the element.
|
||||||
func (p *Decoder) unmarshalInterface(val Unmarshaler, start *StartElement) error {
|
func (d *Decoder) unmarshalInterface(val Unmarshaler, start *StartElement) error {
|
||||||
// Record that decoder must stop at end tag corresponding to start.
|
// Record that decoder must stop at end tag corresponding to start.
|
||||||
p.pushEOF()
|
d.pushEOF()
|
||||||
|
|
||||||
p.unmarshalDepth++
|
d.unmarshalDepth++
|
||||||
err := val.UnmarshalXML(p, *start)
|
err := val.UnmarshalXML(d, *start)
|
||||||
p.unmarshalDepth--
|
d.unmarshalDepth--
|
||||||
if err != nil {
|
if err != nil {
|
||||||
p.popEOF()
|
d.popEOF()
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !p.popEOF() {
|
if !d.popEOF() {
|
||||||
return fmt.Errorf("xml: %s.UnmarshalXML did not consume entire <%s> element", receiverType(val), start.Name.Local)
|
return fmt.Errorf("xml: %s.UnmarshalXML did not consume entire <%s> element", receiverType(val), start.Name.Local)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -214,11 +214,11 @@ func (p *Decoder) unmarshalInterface(val Unmarshaler, start *StartElement) error
|
||||||
// unmarshalTextInterface unmarshals a single XML element into val.
|
// unmarshalTextInterface unmarshals a single XML element into val.
|
||||||
// The chardata contained in the element (but not its children)
|
// The chardata contained in the element (but not its children)
|
||||||
// is passed to the text unmarshaler.
|
// is passed to the text unmarshaler.
|
||||||
func (p *Decoder) unmarshalTextInterface(val encoding.TextUnmarshaler) error {
|
func (d *Decoder) unmarshalTextInterface(val encoding.TextUnmarshaler) error {
|
||||||
var buf []byte
|
var buf []byte
|
||||||
depth := 1
|
depth := 1
|
||||||
for depth > 0 {
|
for depth > 0 {
|
||||||
t, err := p.Token()
|
t, err := d.Token()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -237,7 +237,7 @@ func (p *Decoder) unmarshalTextInterface(val encoding.TextUnmarshaler) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// unmarshalAttr unmarshals a single XML attribute into val.
|
// unmarshalAttr unmarshals a single XML attribute into val.
|
||||||
func (p *Decoder) unmarshalAttr(val reflect.Value, attr Attr) error {
|
func (d *Decoder) unmarshalAttr(val reflect.Value, attr Attr) error {
|
||||||
if val.Kind() == reflect.Ptr {
|
if val.Kind() == reflect.Ptr {
|
||||||
if val.IsNil() {
|
if val.IsNil() {
|
||||||
val.Set(reflect.New(val.Type().Elem()))
|
val.Set(reflect.New(val.Type().Elem()))
|
||||||
|
|
@ -276,7 +276,7 @@ func (p *Decoder) unmarshalAttr(val reflect.Value, attr Attr) error {
|
||||||
val.Set(reflect.Append(val, reflect.Zero(val.Type().Elem())))
|
val.Set(reflect.Append(val, reflect.Zero(val.Type().Elem())))
|
||||||
|
|
||||||
// Recur to read element into slice.
|
// Recur to read element into slice.
|
||||||
if err := p.unmarshalAttr(val.Index(n), attr); err != nil {
|
if err := d.unmarshalAttr(val.Index(n), attr); err != nil {
|
||||||
val.SetLen(n)
|
val.SetLen(n)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -299,11 +299,11 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
// Unmarshal a single XML element into val.
|
// Unmarshal a single XML element into val.
|
||||||
func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
|
func (d *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
|
||||||
// Find start element if we need it.
|
// Find start element if we need it.
|
||||||
if start == nil {
|
if start == nil {
|
||||||
for {
|
for {
|
||||||
tok, err := p.Token()
|
tok, err := d.Token()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -333,24 +333,24 @@ func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
|
||||||
if val.CanInterface() && val.Type().Implements(unmarshalerType) {
|
if val.CanInterface() && val.Type().Implements(unmarshalerType) {
|
||||||
// This is an unmarshaler with a non-pointer receiver,
|
// This is an unmarshaler with a non-pointer receiver,
|
||||||
// so it's likely to be incorrect, but we do what we're told.
|
// so it's likely to be incorrect, but we do what we're told.
|
||||||
return p.unmarshalInterface(val.Interface().(Unmarshaler), start)
|
return d.unmarshalInterface(val.Interface().(Unmarshaler), start)
|
||||||
}
|
}
|
||||||
|
|
||||||
if val.CanAddr() {
|
if val.CanAddr() {
|
||||||
pv := val.Addr()
|
pv := val.Addr()
|
||||||
if pv.CanInterface() && pv.Type().Implements(unmarshalerType) {
|
if pv.CanInterface() && pv.Type().Implements(unmarshalerType) {
|
||||||
return p.unmarshalInterface(pv.Interface().(Unmarshaler), start)
|
return d.unmarshalInterface(pv.Interface().(Unmarshaler), start)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if val.CanInterface() && val.Type().Implements(textUnmarshalerType) {
|
if val.CanInterface() && val.Type().Implements(textUnmarshalerType) {
|
||||||
return p.unmarshalTextInterface(val.Interface().(encoding.TextUnmarshaler))
|
return d.unmarshalTextInterface(val.Interface().(encoding.TextUnmarshaler))
|
||||||
}
|
}
|
||||||
|
|
||||||
if val.CanAddr() {
|
if val.CanAddr() {
|
||||||
pv := val.Addr()
|
pv := val.Addr()
|
||||||
if pv.CanInterface() && pv.Type().Implements(textUnmarshalerType) {
|
if pv.CanInterface() && pv.Type().Implements(textUnmarshalerType) {
|
||||||
return p.unmarshalTextInterface(pv.Interface().(encoding.TextUnmarshaler))
|
return d.unmarshalTextInterface(pv.Interface().(encoding.TextUnmarshaler))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -376,7 +376,7 @@ func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
|
||||||
// TODO: For now, simply ignore the field. In the near
|
// TODO: For now, simply ignore the field. In the near
|
||||||
// future we may choose to unmarshal the start
|
// future we may choose to unmarshal the start
|
||||||
// element on it, if not nil.
|
// element on it, if not nil.
|
||||||
return p.Skip()
|
return d.Skip()
|
||||||
|
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
typ := v.Type()
|
typ := v.Type()
|
||||||
|
|
@ -392,7 +392,7 @@ func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
|
||||||
v.Set(reflect.Append(val, reflect.Zero(v.Type().Elem())))
|
v.Set(reflect.Append(val, reflect.Zero(v.Type().Elem())))
|
||||||
|
|
||||||
// Recur to read element into slice.
|
// Recur to read element into slice.
|
||||||
if err := p.unmarshal(v.Index(n), start); err != nil {
|
if err := d.unmarshal(v.Index(n), start); err != nil {
|
||||||
v.SetLen(n)
|
v.SetLen(n)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -445,7 +445,7 @@ func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
|
||||||
case fAttr:
|
case fAttr:
|
||||||
strv := finfo.value(sv)
|
strv := finfo.value(sv)
|
||||||
if a.Name.Local == finfo.name && (finfo.xmlns == "" || finfo.xmlns == a.Name.Space) {
|
if a.Name.Local == finfo.name && (finfo.xmlns == "" || finfo.xmlns == a.Name.Space) {
|
||||||
if err := p.unmarshalAttr(strv, a); err != nil {
|
if err := d.unmarshalAttr(strv, a); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
handled = true
|
handled = true
|
||||||
|
|
@ -460,7 +460,7 @@ func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
|
||||||
if !handled && any >= 0 {
|
if !handled && any >= 0 {
|
||||||
finfo := &tinfo.fields[any]
|
finfo := &tinfo.fields[any]
|
||||||
strv := finfo.value(sv)
|
strv := finfo.value(sv)
|
||||||
if err := p.unmarshalAttr(strv, a); err != nil {
|
if err := d.unmarshalAttr(strv, a); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -488,11 +488,11 @@ func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
|
||||||
case fInnerXml:
|
case fInnerXml:
|
||||||
if !saveXML.IsValid() {
|
if !saveXML.IsValid() {
|
||||||
saveXML = finfo.value(sv)
|
saveXML = finfo.value(sv)
|
||||||
if p.saved == nil {
|
if d.saved == nil {
|
||||||
saveXMLIndex = 0
|
saveXMLIndex = 0
|
||||||
p.saved = new(bytes.Buffer)
|
d.saved = new(bytes.Buffer)
|
||||||
} else {
|
} else {
|
||||||
saveXMLIndex = p.savedOffset()
|
saveXMLIndex = d.savedOffset()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -505,9 +505,9 @@ Loop:
|
||||||
for {
|
for {
|
||||||
var savedOffset int
|
var savedOffset int
|
||||||
if saveXML.IsValid() {
|
if saveXML.IsValid() {
|
||||||
savedOffset = p.savedOffset()
|
savedOffset = d.savedOffset()
|
||||||
}
|
}
|
||||||
tok, err := p.Token()
|
tok, err := d.Token()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -515,28 +515,28 @@ Loop:
|
||||||
case StartElement:
|
case StartElement:
|
||||||
consumed := false
|
consumed := false
|
||||||
if sv.IsValid() {
|
if sv.IsValid() {
|
||||||
consumed, err = p.unmarshalPath(tinfo, sv, nil, &t)
|
consumed, err = d.unmarshalPath(tinfo, sv, nil, &t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !consumed && saveAny.IsValid() {
|
if !consumed && saveAny.IsValid() {
|
||||||
consumed = true
|
consumed = true
|
||||||
if err := p.unmarshal(saveAny, &t); err != nil {
|
if err := d.unmarshal(saveAny, &t); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !consumed {
|
if !consumed {
|
||||||
if err := p.Skip(); err != nil {
|
if err := d.Skip(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
case EndElement:
|
case EndElement:
|
||||||
if saveXML.IsValid() {
|
if saveXML.IsValid() {
|
||||||
saveXMLData = p.saved.Bytes()[saveXMLIndex:savedOffset]
|
saveXMLData = d.saved.Bytes()[saveXMLIndex:savedOffset]
|
||||||
if saveXMLIndex == 0 {
|
if saveXMLIndex == 0 {
|
||||||
p.saved = nil
|
d.saved = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break Loop
|
break Loop
|
||||||
|
|
@ -666,7 +666,7 @@ func copyValue(dst reflect.Value, src []byte) (err error) {
|
||||||
// The consumed result tells whether XML elements have been consumed
|
// The consumed result tells whether XML elements have been consumed
|
||||||
// from the Decoder until start's matching end element, or if it's
|
// from the Decoder until start's matching end element, or if it's
|
||||||
// still untouched because start is uninteresting for sv's fields.
|
// still untouched because start is uninteresting for sv's fields.
|
||||||
func (p *Decoder) unmarshalPath(tinfo *typeInfo, sv reflect.Value, parents []string, start *StartElement) (consumed bool, err error) {
|
func (d *Decoder) unmarshalPath(tinfo *typeInfo, sv reflect.Value, parents []string, start *StartElement) (consumed bool, err error) {
|
||||||
recurse := false
|
recurse := false
|
||||||
Loop:
|
Loop:
|
||||||
for i := range tinfo.fields {
|
for i := range tinfo.fields {
|
||||||
|
|
@ -681,7 +681,7 @@ Loop:
|
||||||
}
|
}
|
||||||
if len(finfo.parents) == len(parents) && finfo.name == start.Name.Local {
|
if len(finfo.parents) == len(parents) && finfo.name == start.Name.Local {
|
||||||
// It's a perfect match, unmarshal the field.
|
// It's a perfect match, unmarshal the field.
|
||||||
return true, p.unmarshal(finfo.value(sv), start)
|
return true, d.unmarshal(finfo.value(sv), start)
|
||||||
}
|
}
|
||||||
if len(finfo.parents) > len(parents) && finfo.parents[len(parents)] == start.Name.Local {
|
if len(finfo.parents) > len(parents) && finfo.parents[len(parents)] == start.Name.Local {
|
||||||
// It's a prefix for the field. Break and recurse
|
// It's a prefix for the field. Break and recurse
|
||||||
|
|
@ -704,18 +704,18 @@ Loop:
|
||||||
// prefix. Recurse and attempt to match these.
|
// prefix. Recurse and attempt to match these.
|
||||||
for {
|
for {
|
||||||
var tok Token
|
var tok Token
|
||||||
tok, err = p.Token()
|
tok, err = d.Token()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
switch t := tok.(type) {
|
switch t := tok.(type) {
|
||||||
case StartElement:
|
case StartElement:
|
||||||
consumed2, err := p.unmarshalPath(tinfo, sv, parents, &t)
|
consumed2, err := d.unmarshalPath(tinfo, sv, parents, &t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
if !consumed2 {
|
if !consumed2 {
|
||||||
if err := p.Skip(); err != nil {
|
if err := d.Skip(); err != nil {
|
||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ not being used from outside intra_region_diff.py.
|
||||||
type Feed struct {
|
type Feed struct {
|
||||||
XMLName Name `xml:"http://www.w3.org/2005/Atom feed"`
|
XMLName Name `xml:"http://www.w3.org/2005/Atom feed"`
|
||||||
Title string `xml:"title"`
|
Title string `xml:"title"`
|
||||||
Id string `xml:"id"`
|
ID string `xml:"id"`
|
||||||
Link []Link `xml:"link"`
|
Link []Link `xml:"link"`
|
||||||
Updated time.Time `xml:"updated,attr"`
|
Updated time.Time `xml:"updated,attr"`
|
||||||
Author Person `xml:"author"`
|
Author Person `xml:"author"`
|
||||||
|
|
@ -92,7 +92,7 @@ type Feed struct {
|
||||||
|
|
||||||
type Entry struct {
|
type Entry struct {
|
||||||
Title string `xml:"title"`
|
Title string `xml:"title"`
|
||||||
Id string `xml:"id"`
|
ID string `xml:"id"`
|
||||||
Link []Link `xml:"link"`
|
Link []Link `xml:"link"`
|
||||||
Updated time.Time `xml:"updated"`
|
Updated time.Time `xml:"updated"`
|
||||||
Author Person `xml:"author"`
|
Author Person `xml:"author"`
|
||||||
|
|
@ -123,7 +123,7 @@ var atomFeed = Feed{
|
||||||
{Rel: "alternate", Href: "http://codereview.appspot.com/"},
|
{Rel: "alternate", Href: "http://codereview.appspot.com/"},
|
||||||
{Rel: "self", Href: "http://codereview.appspot.com/rss/mine/rsc"},
|
{Rel: "self", Href: "http://codereview.appspot.com/rss/mine/rsc"},
|
||||||
},
|
},
|
||||||
Id: "http://codereview.appspot.com/",
|
ID: "http://codereview.appspot.com/",
|
||||||
Updated: ParseTime("2009-10-04T01:35:58+00:00"),
|
Updated: ParseTime("2009-10-04T01:35:58+00:00"),
|
||||||
Author: Person{
|
Author: Person{
|
||||||
Name: "rietveld<>",
|
Name: "rietveld<>",
|
||||||
|
|
@ -140,7 +140,7 @@ var atomFeed = Feed{
|
||||||
Name: "email-address-removed",
|
Name: "email-address-removed",
|
||||||
InnerXML: "<name>email-address-removed</name>",
|
InnerXML: "<name>email-address-removed</name>",
|
||||||
},
|
},
|
||||||
Id: "urn:md5:134d9179c41f806be79b3a5f7877d19a",
|
ID: "urn:md5:134d9179c41f806be79b3a5f7877d19a",
|
||||||
Summary: Text{
|
Summary: Text{
|
||||||
Type: "html",
|
Type: "html",
|
||||||
Body: `
|
Body: `
|
||||||
|
|
@ -187,7 +187,7 @@ the top of feeds.py marked NOTE(rsc).
|
||||||
Name: "email-address-removed",
|
Name: "email-address-removed",
|
||||||
InnerXML: "<name>email-address-removed</name>",
|
InnerXML: "<name>email-address-removed</name>",
|
||||||
},
|
},
|
||||||
Id: "urn:md5:0a2a4f19bb815101f0ba2904aed7c35a",
|
ID: "urn:md5:0a2a4f19bb815101f0ba2904aed7c35a",
|
||||||
Summary: Text{
|
Summary: Text{
|
||||||
Type: "html",
|
Type: "html",
|
||||||
Body: `
|
Body: `
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,8 @@ const (
|
||||||
fOmitEmpty
|
fOmitEmpty
|
||||||
|
|
||||||
fMode = fElement | fAttr | fCDATA | fCharData | fInnerXml | fComment | fAny
|
fMode = fElement | fAttr | fCDATA | fCharData | fInnerXml | fComment | fAny
|
||||||
|
|
||||||
|
xmlName = "XMLName"
|
||||||
)
|
)
|
||||||
|
|
||||||
var tinfoMap sync.Map // map[reflect.Type]*typeInfo
|
var tinfoMap sync.Map // map[reflect.Type]*typeInfo
|
||||||
|
|
@ -91,7 +93,7 @@ func getTypeInfo(typ reflect.Type) (*typeInfo, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.Name == "XMLName" {
|
if f.Name == xmlName {
|
||||||
tinfo.xmlname = finfo
|
tinfo.xmlname = finfo
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
@ -148,7 +150,7 @@ func structFieldInfo(typ reflect.Type, f *reflect.StructField) (*fieldInfo, erro
|
||||||
case 0:
|
case 0:
|
||||||
finfo.flags |= fElement
|
finfo.flags |= fElement
|
||||||
case fAttr, fCDATA, fCharData, fInnerXml, fComment, fAny, fAny | fAttr:
|
case fAttr, fCDATA, fCharData, fInnerXml, fComment, fAny, fAny | fAttr:
|
||||||
if f.Name == "XMLName" || tag != "" && mode != fAttr {
|
if f.Name == xmlName || tag != "" && mode != fAttr {
|
||||||
valid = false
|
valid = false
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
@ -173,7 +175,7 @@ func structFieldInfo(typ reflect.Type, f *reflect.StructField) (*fieldInfo, erro
|
||||||
f.Name, typ, f.Tag.Get("xml"))
|
f.Name, typ, f.Tag.Get("xml"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if f.Name == "XMLName" {
|
if f.Name == xmlName {
|
||||||
// The XMLName field records the XML element name. Don't
|
// The XMLName field records the XML element name. Don't
|
||||||
// process it as usual because its name should default to
|
// process it as usual because its name should default to
|
||||||
// empty rather than to the field name.
|
// empty rather than to the field name.
|
||||||
|
|
@ -235,7 +237,7 @@ func lookupXMLName(typ reflect.Type) (xmlname *fieldInfo) {
|
||||||
}
|
}
|
||||||
for i, n := 0, typ.NumField(); i < n; i++ {
|
for i, n := 0, typ.NumField(); i < n; i++ {
|
||||||
f := typ.Field(i)
|
f := typ.Field(i)
|
||||||
if f.Name != "XMLName" {
|
if f.Name != xmlName {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
finfo, err := structFieldInfo(typ, &f)
|
finfo, err := structFieldInfo(typ, &f)
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,7 @@ type StartElement struct {
|
||||||
Attr []Attr
|
Attr []Attr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copy creates a new copy of StartElement.
|
||||||
func (e StartElement) Copy() StartElement {
|
func (e StartElement) Copy() StartElement {
|
||||||
attrs := make([]Attr, len(e.Attr))
|
attrs := make([]Attr, len(e.Attr))
|
||||||
copy(attrs, e.Attr)
|
copy(attrs, e.Attr)
|
||||||
|
|
@ -88,12 +89,14 @@ func makeCopy(b []byte) []byte {
|
||||||
return b1
|
return b1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copy creates a new copy of CharData.
|
||||||
func (c CharData) Copy() CharData { return CharData(makeCopy(c)) }
|
func (c CharData) Copy() CharData { return CharData(makeCopy(c)) }
|
||||||
|
|
||||||
// A Comment represents an XML comment of the form <!--comment-->.
|
// A Comment represents an XML comment of the form <!--comment-->.
|
||||||
// The bytes do not include the <!-- and --> comment markers.
|
// The bytes do not include the <!-- and --> comment markers.
|
||||||
type Comment []byte
|
type Comment []byte
|
||||||
|
|
||||||
|
// Copy creates a new copy of Comment.
|
||||||
func (c Comment) Copy() Comment { return Comment(makeCopy(c)) }
|
func (c Comment) Copy() Comment { return Comment(makeCopy(c)) }
|
||||||
|
|
||||||
// A ProcInst represents an XML processing instruction of the form <?target inst?>
|
// A ProcInst represents an XML processing instruction of the form <?target inst?>
|
||||||
|
|
@ -102,6 +105,7 @@ type ProcInst struct {
|
||||||
Inst []byte
|
Inst []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copy creates a new copy of ProcInst.
|
||||||
func (p ProcInst) Copy() ProcInst {
|
func (p ProcInst) Copy() ProcInst {
|
||||||
p.Inst = makeCopy(p.Inst)
|
p.Inst = makeCopy(p.Inst)
|
||||||
return p
|
return p
|
||||||
|
|
@ -111,6 +115,7 @@ func (p ProcInst) Copy() ProcInst {
|
||||||
// The bytes do not include the <! and > markers.
|
// The bytes do not include the <! and > markers.
|
||||||
type Directive []byte
|
type Directive []byte
|
||||||
|
|
||||||
|
// Copy creates a new copy of Directive.
|
||||||
func (d Directive) Copy() Directive { return Directive(makeCopy(d)) }
|
func (d Directive) Copy() Directive { return Directive(makeCopy(d)) }
|
||||||
|
|
||||||
// CopyToken returns a copy of a Token.
|
// CopyToken returns a copy of a Token.
|
||||||
|
|
@ -266,12 +271,12 @@ func (d *Decoder) Token() (Token, error) {
|
||||||
// to the other attribute names, so process
|
// to the other attribute names, so process
|
||||||
// the translations first.
|
// the translations first.
|
||||||
for _, a := range t1.Attr {
|
for _, a := range t1.Attr {
|
||||||
if a.Name.Space == "xmlns" {
|
if a.Name.Space == xmlnsPrefix {
|
||||||
v, ok := d.ns[a.Name.Local]
|
v, ok := d.ns[a.Name.Local]
|
||||||
d.pushNs(a.Name.Local, v, ok)
|
d.pushNs(a.Name.Local, v, ok)
|
||||||
d.ns[a.Name.Local] = a.Value
|
d.ns[a.Name.Local] = a.Value
|
||||||
}
|
}
|
||||||
if a.Name.Space == "" && a.Name.Local == "xmlns" {
|
if a.Name.Space == "" && a.Name.Local == xmlnsPrefix {
|
||||||
// Default space for untagged names
|
// Default space for untagged names
|
||||||
v, ok := d.ns[""]
|
v, ok := d.ns[""]
|
||||||
d.pushNs("", v, ok)
|
d.pushNs("", v, ok)
|
||||||
|
|
@ -296,20 +301,23 @@ func (d *Decoder) Token() (Token, error) {
|
||||||
return t, err
|
return t, err
|
||||||
}
|
}
|
||||||
|
|
||||||
const xmlURL = "http://www.w3.org/XML/1998/namespace"
|
const (
|
||||||
|
xmlURL = "http://www.w3.org/XML/1998/namespace"
|
||||||
|
xmlnsPrefix = "xmlns"
|
||||||
|
)
|
||||||
|
|
||||||
// Apply name space translation to name n.
|
// Apply name space translation to name n.
|
||||||
// The default name space (for Space=="")
|
// The default name space (for Space=="")
|
||||||
// applies only to element names, not to attribute names.
|
// applies only to element names, not to attribute names.
|
||||||
func (d *Decoder) translate(n *Name, isElementName bool) {
|
func (d *Decoder) translate(n *Name, isElementName bool) {
|
||||||
switch {
|
switch {
|
||||||
case n.Space == "xmlns":
|
case n.Space == xmlnsPrefix:
|
||||||
return
|
return
|
||||||
case n.Space == "" && !isElementName:
|
case n.Space == "" && !isElementName:
|
||||||
return
|
return
|
||||||
case n.Space == "xml":
|
case n.Space == xmlNamespacePrefix:
|
||||||
n.Space = xmlURL
|
n.Space = xmlURL
|
||||||
case n.Space == "" && n.Local == "xmlns":
|
case n.Space == "" && n.Local == xmlnsPrefix:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if v, ok := d.ns[n.Space]; ok {
|
if v, ok := d.ns[n.Space]; ok {
|
||||||
|
|
@ -786,10 +794,9 @@ func (d *Decoder) rawToken() (Token, error) {
|
||||||
if d.Strict {
|
if d.Strict {
|
||||||
d.err = d.syntaxError("attribute name without = in element")
|
d.err = d.syntaxError("attribute name without = in element")
|
||||||
return nil, d.err
|
return nil, d.err
|
||||||
} else {
|
}
|
||||||
d.ungetc(b)
|
d.ungetc(b)
|
||||||
a.Value = a.Name.Local
|
a.Value = a.Name.Local
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
d.space()
|
d.space()
|
||||||
data := d.attrval()
|
data := d.attrval()
|
||||||
|
|
@ -1027,7 +1034,6 @@ Input:
|
||||||
if d.err != nil {
|
if d.err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
ok = false
|
|
||||||
}
|
}
|
||||||
if b, ok = d.mustgetc(); !ok {
|
if b, ok = d.mustgetc(); !ok {
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -1837,15 +1843,15 @@ var htmlAutoClose = []string{
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
esc_quot = []byte(""") // shorter than """
|
escQuot = []byte(""") // shorter than """
|
||||||
esc_apos = []byte("'") // shorter than "'"
|
escApos = []byte("'") // shorter than "'"
|
||||||
esc_amp = []byte("&")
|
escAmp = []byte("&")
|
||||||
esc_lt = []byte("<")
|
escLT = []byte("<")
|
||||||
esc_gt = []byte(">")
|
escGT = []byte(">")
|
||||||
esc_tab = []byte("	")
|
escTab = []byte("	")
|
||||||
esc_nl = []byte("
")
|
escNL = []byte("
")
|
||||||
esc_cr = []byte("
")
|
escCR = []byte("
")
|
||||||
esc_fffd = []byte("\uFFFD") // Unicode replacement character
|
escFFFD = []byte("\uFFFD") // Unicode replacement character
|
||||||
)
|
)
|
||||||
|
|
||||||
// EscapeText writes to w the properly escaped XML equivalent
|
// EscapeText writes to w the properly escaped XML equivalent
|
||||||
|
|
@ -1865,27 +1871,27 @@ func escapeText(w io.Writer, s []byte, escapeNewline bool) error {
|
||||||
i += width
|
i += width
|
||||||
switch r {
|
switch r {
|
||||||
case '"':
|
case '"':
|
||||||
esc = esc_quot
|
esc = escQuot
|
||||||
case '\'':
|
case '\'':
|
||||||
esc = esc_apos
|
esc = escApos
|
||||||
case '&':
|
case '&':
|
||||||
esc = esc_amp
|
esc = escAmp
|
||||||
case '<':
|
case '<':
|
||||||
esc = esc_lt
|
esc = escLT
|
||||||
case '>':
|
case '>':
|
||||||
esc = esc_gt
|
esc = escGT
|
||||||
case '\t':
|
case '\t':
|
||||||
esc = esc_tab
|
esc = escTab
|
||||||
case '\n':
|
case '\n':
|
||||||
if !escapeNewline {
|
if !escapeNewline {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
esc = esc_nl
|
esc = escNL
|
||||||
case '\r':
|
case '\r':
|
||||||
esc = esc_cr
|
esc = escCR
|
||||||
default:
|
default:
|
||||||
if !isInCharacterRange(r) || (r == 0xFFFD && width == 1) {
|
if !isInCharacterRange(r) || (r == 0xFFFD && width == 1) {
|
||||||
esc = esc_fffd
|
esc = escFFFD
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
|
|
@ -1914,24 +1920,24 @@ func (p *printer) EscapeString(s string) {
|
||||||
i += width
|
i += width
|
||||||
switch r {
|
switch r {
|
||||||
case '"':
|
case '"':
|
||||||
esc = esc_quot
|
esc = escQuot
|
||||||
case '\'':
|
case '\'':
|
||||||
esc = esc_apos
|
esc = escApos
|
||||||
case '&':
|
case '&':
|
||||||
esc = esc_amp
|
esc = escAmp
|
||||||
case '<':
|
case '<':
|
||||||
esc = esc_lt
|
esc = escLT
|
||||||
case '>':
|
case '>':
|
||||||
esc = esc_gt
|
esc = escGT
|
||||||
case '\t':
|
case '\t':
|
||||||
esc = esc_tab
|
esc = escTab
|
||||||
case '\n':
|
case '\n':
|
||||||
esc = esc_nl
|
esc = escNL
|
||||||
case '\r':
|
case '\r':
|
||||||
esc = esc_cr
|
esc = escCR
|
||||||
default:
|
default:
|
||||||
if !isInCharacterRange(r) || (r == 0xFFFD && width == 1) {
|
if !isInCharacterRange(r) || (r == 0xFFFD && width == 1) {
|
||||||
esc = esc_fffd
|
esc = escFFFD
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
|
|
|
||||||
|
|
@ -479,15 +479,15 @@ func TestAllScalars(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type item struct {
|
type item struct {
|
||||||
Field_a string
|
FieldA string
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIssue569(t *testing.T) {
|
func TestIssue569(t *testing.T) {
|
||||||
data := `<item><Field_a>abcd</Field_a></item>`
|
data := `<item><FieldA>abcd</FieldA></item>`
|
||||||
var i item
|
var i item
|
||||||
err := Unmarshal([]byte(data), &i)
|
err := Unmarshal([]byte(data), &i)
|
||||||
|
|
||||||
if err != nil || i.Field_a != "abcd" {
|
if err != nil || i.FieldA != "abcd" {
|
||||||
t.Fatal("Expecting abcd")
|
t.Fatal("Expecting abcd")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue