diff options
author | Christopher Speller <crspeller@gmail.com> | 2018-04-16 05:37:14 -0700 |
---|---|---|
committer | Joram Wilander <jwawilander@gmail.com> | 2018-04-16 08:37:14 -0400 |
commit | 6e2cb00008cbf09e556b00f87603797fcaa47e09 (patch) | |
tree | 3c0eb55ff4226a3f024aad373140d1fb860a6404 /vendor/golang.org/x/net/webdav/internal/xml | |
parent | bf24f51c4e1cc6286885460672f7f449e8c6f5ef (diff) | |
download | chat-6e2cb00008cbf09e556b00f87603797fcaa47e09.tar.gz chat-6e2cb00008cbf09e556b00f87603797fcaa47e09.tar.bz2 chat-6e2cb00008cbf09e556b00f87603797fcaa47e09.zip |
Depenancy upgrades and movign to dep. (#8630)
Diffstat (limited to 'vendor/golang.org/x/net/webdav/internal/xml')
-rw-r--r-- | vendor/golang.org/x/net/webdav/internal/xml/README | 11 | ||||
-rw-r--r-- | vendor/golang.org/x/net/webdav/internal/xml/atom_test.go | 56 | ||||
-rw-r--r-- | vendor/golang.org/x/net/webdav/internal/xml/example_test.go | 151 | ||||
-rw-r--r-- | vendor/golang.org/x/net/webdav/internal/xml/marshal.go | 1223 | ||||
-rw-r--r-- | vendor/golang.org/x/net/webdav/internal/xml/marshal_test.go | 1939 | ||||
-rw-r--r-- | vendor/golang.org/x/net/webdav/internal/xml/read.go | 692 | ||||
-rw-r--r-- | vendor/golang.org/x/net/webdav/internal/xml/read_test.go | 744 | ||||
-rw-r--r-- | vendor/golang.org/x/net/webdav/internal/xml/typeinfo.go | 371 | ||||
-rw-r--r-- | vendor/golang.org/x/net/webdav/internal/xml/xml.go | 1998 | ||||
-rw-r--r-- | vendor/golang.org/x/net/webdav/internal/xml/xml_test.go | 752 |
10 files changed, 0 insertions, 7937 deletions
diff --git a/vendor/golang.org/x/net/webdav/internal/xml/README b/vendor/golang.org/x/net/webdav/internal/xml/README deleted file mode 100644 index 89656f489..000000000 --- a/vendor/golang.org/x/net/webdav/internal/xml/README +++ /dev/null @@ -1,11 +0,0 @@ -This is a fork of the encoding/xml package at ca1d6c4, the last commit before -https://go.googlesource.com/go/+/c0d6d33 "encoding/xml: restore Go 1.4 name -space behavior" made late in the lead-up to the Go 1.5 release. - -The list of encoding/xml changes is at -https://go.googlesource.com/go/+log/master/src/encoding/xml - -This fork is temporary, and I (nigeltao) expect to revert it after Go 1.6 is -released. - -See http://golang.org/issue/11841 diff --git a/vendor/golang.org/x/net/webdav/internal/xml/atom_test.go b/vendor/golang.org/x/net/webdav/internal/xml/atom_test.go deleted file mode 100644 index a71284312..000000000 --- a/vendor/golang.org/x/net/webdav/internal/xml/atom_test.go +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2011 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 - -import "time" - -var atomValue = &Feed{ - XMLName: Name{"http://www.w3.org/2005/Atom", "feed"}, - Title: "Example Feed", - Link: []Link{{Href: "http://example.org/"}}, - Updated: ParseTime("2003-12-13T18:30:02Z"), - Author: Person{Name: "John Doe"}, - Id: "urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6", - - Entry: []Entry{ - { - Title: "Atom-Powered Robots Run Amok", - Link: []Link{{Href: "http://example.org/2003/12/13/atom03"}}, - Id: "urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a", - Updated: ParseTime("2003-12-13T18:30:02Z"), - Summary: NewText("Some text."), - }, - }, -} - -var atomXml = `` + - `<feed xmlns="http://www.w3.org/2005/Atom" updated="2003-12-13T18:30:02Z">` + - `<title>Example Feed</title>` + - `<id>urn:uuid:60a76c80-d399-11d9-b93C-0003939e0af6</id>` + - `<link href="http://example.org/"></link>` + - `<author><name>John Doe</name><uri></uri><email></email></author>` + - `<entry>` + - `<title>Atom-Powered Robots Run Amok</title>` + - `<id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>` + - `<link href="http://example.org/2003/12/13/atom03"></link>` + - `<updated>2003-12-13T18:30:02Z</updated>` + - `<author><name></name><uri></uri><email></email></author>` + - `<summary>Some text.</summary>` + - `</entry>` + - `</feed>` - -func ParseTime(str string) time.Time { - t, err := time.Parse(time.RFC3339, str) - if err != nil { - panic(err) - } - return t -} - -func NewText(text string) Text { - return Text{ - Body: text, - } -} diff --git a/vendor/golang.org/x/net/webdav/internal/xml/example_test.go b/vendor/golang.org/x/net/webdav/internal/xml/example_test.go deleted file mode 100644 index 21b48dea5..000000000 --- a/vendor/golang.org/x/net/webdav/internal/xml/example_test.go +++ /dev/null @@ -1,151 +0,0 @@ -// 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" -) - -func ExampleMarshalIndent() { - type Address struct { - City, State string - } - 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 - Address - Comment string `xml:",comment"` - } - - v := &Person{Id: 13, FirstName: "John", LastName: "Doe", Age: 42} - v.Comment = " Need more details. " - v.Address = Address{"Hanga Roa", "Easter Island"} - - output, err := xml.MarshalIndent(v, " ", " ") - if err != nil { - fmt.Printf("error: %v\n", err) - } - - os.Stdout.Write(output) - // Output: - // <person id="13"> - // <name> - // <first>John</first> - // <last>Doe</last> - // </name> - // <age>42</age> - // <Married>false</Married> - // <City>Hanga Roa</City> - // <State>Easter Island</State> - // <!-- Need more details. --> - // </person> -} - -func ExampleEncoder() { - type Address struct { - City, State string - } - 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 - Address - Comment string `xml:",comment"` - } - - v := &Person{Id: 13, FirstName: "John", LastName: "Doe", Age: 42} - v.Comment = " Need more details. " - v.Address = Address{"Hanga Roa", "Easter Island"} - - enc := xml.NewEncoder(os.Stdout) - enc.Indent(" ", " ") - if err := enc.Encode(v); err != nil { - fmt.Printf("error: %v\n", err) - } - - // Output: - // <person id="13"> - // <name> - // <first>John</first> - // <last>Doe</last> - // </name> - // <age>42</age> - // <Married>false</Married> - // <City>Hanga Roa</City> - // <State>Easter Island</State> - // <!-- Need more details. --> - // </person> -} - -// This example demonstrates unmarshaling an XML excerpt into a value with -// some preset fields. Note that the Phone field isn't modified and that -// the XML <Company> element is ignored. Also, the Groups field is assigned -// considering the element path provided in its tag. -func ExampleUnmarshal() { - type Email struct { - Where string `xml:"where,attr"` - Addr string - } - type Address struct { - City, State string - } - type Result struct { - XMLName xml.Name `xml:"Person"` - Name string `xml:"FullName"` - Phone string - Email []Email - Groups []string `xml:"Group>Value"` - Address - } - v := Result{Name: "none", Phone: "none"} - - data := ` - <Person> - <FullName>Grace R. Emlin</FullName> - <Company>Example Inc.</Company> - <Email where="home"> - <Addr>gre@example.com</Addr> - </Email> - <Email where='work'> - <Addr>gre@work.com</Addr> - </Email> - <Group> - <Value>Friends</Value> - <Value>Squash</Value> - </Group> - <City>Hanga Roa</City> - <State>Easter Island</State> - </Person> - ` - err := xml.Unmarshal([]byte(data), &v) - if err != nil { - fmt.Printf("error: %v", err) - return - } - fmt.Printf("XMLName: %#v\n", v.XMLName) - fmt.Printf("Name: %q\n", v.Name) - fmt.Printf("Phone: %q\n", v.Phone) - fmt.Printf("Email: %v\n", v.Email) - fmt.Printf("Groups: %v\n", v.Groups) - fmt.Printf("Address: %v\n", v.Address) - // Output: - // XMLName: xml.Name{Space:"", Local:"Person"} - // Name: "Grace R. Emlin" - // Phone: "none" - // Email: [{home gre@example.com} {work gre@work.com}] - // Groups: [Friends Squash] - // Address: {Hanga Roa Easter Island} -} diff --git a/vendor/golang.org/x/net/webdav/internal/xml/marshal.go b/vendor/golang.org/x/net/webdav/internal/xml/marshal.go deleted file mode 100644 index cb82ec214..000000000 --- a/vendor/golang.org/x/net/webdav/internal/xml/marshal.go +++ /dev/null @@ -1,1223 +0,0 @@ -// Copyright 2011 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 - -import ( - "bufio" - "bytes" - "encoding" - "fmt" - "io" - "reflect" - "strconv" - "strings" -) - -const ( - // A generic XML header suitable for use with the output of Marshal. - // This is not automatically added to any output of this package, - // it is provided as a convenience. - Header = `<?xml version="1.0" encoding="UTF-8"?>` + "\n" -) - -// Marshal returns the XML encoding of v. -// -// Marshal handles an array or slice by marshalling each of the elements. -// Marshal handles a pointer by marshalling the value it points at or, if the -// pointer is nil, by writing nothing. Marshal handles an interface value by -// marshalling the value it contains or, if the interface value is nil, by -// writing nothing. Marshal handles all other data by writing one or more XML -// elements containing the data. -// -// The name for the XML elements is taken from, in order of preference: -// - the tag on the XMLName field, if the data is a struct -// - the value of the XMLName field of type xml.Name -// - the tag of the struct field used to obtain the data -// - the name of the struct field used to obtain the data -// - the name of the marshalled type -// -// The XML element for a struct contains marshalled elements for each of the -// exported fields of the struct, with these exceptions: -// - the XMLName field, described above, is omitted. -// - a field with tag "-" is omitted. -// - a field with tag "name,attr" becomes an attribute with -// the given name in the XML element. -// - a field with tag ",attr" becomes an attribute with the -// field name in the XML element. -// - a field with tag ",chardata" is written as character data, -// not as an XML element. -// - a field with tag ",innerxml" is written verbatim, not subject -// to the usual marshalling procedure. -// - a field with tag ",comment" is written as an XML comment, not -// subject to the usual marshalling procedure. It must not contain -// the "--" string within it. -// - a field with a tag including the "omitempty" option is omitted -// if the field value is empty. The empty values are false, 0, any -// nil pointer or interface value, and any array, slice, map, or -// string of length zero. -// - an anonymous struct field is handled as if the fields of its -// value were part of the outer struct. -// -// 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. -// -// 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) { - var b bytes.Buffer - if err := NewEncoder(&b).Encode(v); err != nil { - return nil, err - } - return b.Bytes(), nil -} - -// Marshaler is the interface implemented by objects that can marshal -// themselves into valid XML elements. -// -// MarshalXML encodes the receiver as zero or more XML elements. -// By convention, arrays or slices are typically encoded as a sequence -// of elements, one per entry. -// Using start as the element tag is not required, but doing so -// will enable Unmarshal to match the XML elements to the correct -// struct field. -// One common implementation strategy is to construct a separate -// value with a layout corresponding to the desired XML and then -// to encode it using e.EncodeElement. -// Another common strategy is to use repeated calls to e.EncodeToken -// to generate the XML output one token at a time. -// The sequence of encoded tokens must make up zero or more valid -// XML elements. -type Marshaler interface { - MarshalXML(e *Encoder, start StartElement) error -} - -// MarshalerAttr is the interface implemented by objects that can marshal -// themselves into valid XML attributes. -// -// MarshalXMLAttr returns an XML attribute with the encoded value of the receiver. -// Using name as the attribute name is not required, but doing so -// will enable Unmarshal to match the attribute to the correct -// struct field. -// If MarshalXMLAttr returns the zero attribute Attr{}, no attribute -// will be generated in the output. -// MarshalXMLAttr is used only for struct fields with the -// "attr" option in the field tag. -type MarshalerAttr interface { - MarshalXMLAttr(name Name) (Attr, error) -} - -// 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.Indent(prefix, indent) - if err := enc.Encode(v); err != nil { - return nil, err - } - return b.Bytes(), nil -} - -// An Encoder writes XML data to an output stream. -type Encoder struct { - p printer -} - -// NewEncoder returns a new encoder that writes to w. -func NewEncoder(w io.Writer) *Encoder { - e := &Encoder{printer{Writer: bufio.NewWriter(w)}} - e.p.encoder = e - return e -} - -// Indent sets the encoder to generate XML in which each 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 (enc *Encoder) Indent(prefix, indent string) { - enc.p.prefix = prefix - enc.p.indent = indent -} - -// Encode writes the XML encoding of v to the stream. -// -// See the documentation for Marshal for details about the conversion -// of Go values to XML. -// -// Encode calls Flush before returning. -func (enc *Encoder) Encode(v interface{}) error { - err := enc.p.marshalValue(reflect.ValueOf(v), nil, nil) - if err != nil { - return err - } - return enc.p.Flush() -} - -// EncodeElement writes the XML encoding of v to the stream, -// using start as the outermost tag in the encoding. -// -// See the documentation for Marshal for details about the conversion -// of Go values to XML. -// -// EncodeElement calls Flush before returning. -func (enc *Encoder) EncodeElement(v interface{}, start StartElement) error { - err := enc.p.marshalValue(reflect.ValueOf(v), nil, &start) - if err != nil { - return err - } - return enc.p.Flush() -} - -var ( - begComment = []byte("<!--") - endComment = []byte("-->") - endProcInst = []byte("?>") - endDirective = []byte(">") -) - -// EncodeToken writes the given XML token to the stream. -// It returns an error if StartElement and EndElement tokens are not -// properly matched. -// -// EncodeToken does not call Flush, because usually it is part of a -// larger operation such as Encode or EncodeElement (or a custom -// Marshaler's MarshalXML invoked during those), and those will call -// Flush when finished. Callers that create an Encoder and then invoke -// EncodeToken directly, without using Encode or EncodeElement, need to -// call Flush when finished to ensure that the XML is written to the -// underlying writer. -// -// EncodeToken allows writing a ProcInst with Target set to "xml" only -// as the first token in the stream. -// -// When encoding a StartElement holding an XML namespace prefix -// declaration for a prefix that is not already declared, contained -// elements (including the StartElement itself) will use the declared -// prefix when encoding names with matching namespace URIs. -func (enc *Encoder) EncodeToken(t Token) error { - - p := &enc.p - switch t := t.(type) { - case StartElement: - if err := p.writeStart(&t); err != nil { - return err - } - case EndElement: - if err := p.writeEnd(t.Name); err != nil { - return err - } - case CharData: - escapeText(p, t, false) - case Comment: - if bytes.Contains(t, endComment) { - return fmt.Errorf("xml: EncodeToken of Comment containing --> marker") - } - p.WriteString("<!--") - p.Write(t) - p.WriteString("-->") - return p.cachedWriteError() - case ProcInst: - // First token to be encoded which is also a ProcInst with target of xml - // is the xml declaration. The only ProcInst where target of xml is allowed. - if t.Target == "xml" && p.Buffered() != 0 { - return fmt.Errorf("xml: EncodeToken of ProcInst xml target only valid for xml declaration, first token encoded") - } - if !isNameString(t.Target) { - return fmt.Errorf("xml: EncodeToken of ProcInst with invalid Target") - } - if bytes.Contains(t.Inst, endProcInst) { - return fmt.Errorf("xml: EncodeToken of ProcInst containing ?> marker") - } - p.WriteString("<?") - p.WriteString(t.Target) - if len(t.Inst) > 0 { - p.WriteByte(' ') - p.Write(t.Inst) - } - p.WriteString("?>") - case Directive: - if !isValidDirective(t) { - return fmt.Errorf("xml: EncodeToken of Directive containing wrong < or > markers") - } - p.WriteString("<!") - p.Write(t) - p.WriteString(">") - default: - return fmt.Errorf("xml: EncodeToken of invalid token type") - - } - return p.cachedWriteError() -} - -// isValidDirective reports whether dir is a valid directive text, -// meaning angle brackets are matched, ignoring comments and strings. -func isValidDirective(dir Directive) bool { - var ( - depth int - inquote uint8 - incomment bool - ) - for i, c := range dir { - switch { - case incomment: - if c == '>' { - if n := 1 + i - len(endComment); n >= 0 && bytes.Equal(dir[n:i+1], endComment) { - incomment = false - } - } - // Just ignore anything in comment - case inquote != 0: - if c == inquote { - inquote = 0 - } - // Just ignore anything within quotes - case c == '\'' || c == '"': - inquote = c - case c == '<': - if i+len(begComment) < len(dir) && bytes.Equal(dir[i:i+len(begComment)], begComment) { - incomment = true - } else { - depth++ - } - case c == '>': - if depth == 0 { - return false - } - depth-- - } - } - return depth == 0 && inquote == 0 && !incomment -} - -// Flush flushes any buffered XML to the underlying writer. -// See the EncodeToken documentation for details about when it is necessary. -func (enc *Encoder) Flush() error { - return enc.p.Flush() -} - -type printer struct { - *bufio.Writer - encoder *Encoder - seq int - indent string - prefix string - depth int - indentedIn bool - putNewline bool - defaultNS string - attrNS map[string]string // map prefix -> name space - attrPrefix map[string]string // map name space -> prefix - prefixes []printerPrefix - tags []Name -} - -// printerPrefix holds a namespace undo record. -// When an element is popped, the prefix record -// is set back to the recorded URL. The empty -// prefix records the URL for the default name space. -// -// The start of an element is recorded with an element -// that has mark=true. -type printerPrefix struct { - prefix string - url string - mark bool -} - -func (p *printer) prefixForNS(url string, isAttr bool) string { - // The "http://www.w3.org/XML/1998/namespace" name space is predefined as "xml" - // and must be referred to that way. - // (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.) - if url == xmlURL { - return "xml" - } - if !isAttr && url == p.defaultNS { - // We can use the default name space. - return "" - } - return p.attrPrefix[url] -} - -// defineNS pushes any namespace definition found in the given attribute. -// If ignoreNonEmptyDefault is true, an xmlns="nonempty" -// attribute will be ignored. -func (p *printer) defineNS(attr Attr, ignoreNonEmptyDefault bool) error { - var prefix string - if attr.Name.Local == "xmlns" { - if attr.Name.Space != "" && attr.Name.Space != "xml" && attr.Name.Space != xmlURL { - return fmt.Errorf("xml: cannot redefine xmlns attribute prefix") - } - } else if attr.Name.Space == "xmlns" && attr.Name.Local != "" { - prefix = attr.Name.Local - if attr.Value == "" { - // Technically, an empty XML namespace is allowed for an attribute. - // From http://www.w3.org/TR/xml-names11/#scoping-defaulting: - // - // The attribute value in a namespace declaration for a prefix may be - // empty. This has the effect, within the scope of the declaration, of removing - // any association of the prefix with a namespace name. - // - // However our namespace prefixes here are used only as hints. There's - // no need to respect the removal of a namespace prefix, so we ignore it. - return nil - } - } else { - // Ignore: it's not a namespace definition - return nil - } - if prefix == "" { - if attr.Value == p.defaultNS { - // No need for redefinition. - return nil - } - if attr.Value != "" && ignoreNonEmptyDefault { - // We have an xmlns="..." value but - // it can't define a name space in this context, - // probably because the element has an empty - // name space. In this case, we just ignore - // the name space declaration. - return nil - } - } else if _, ok := p.attrPrefix[attr.Value]; ok { - // There's already a prefix for the given name space, - // so use that. This prevents us from - // having two prefixes for the same name space - // so attrNS and attrPrefix can remain bijective. - return nil - } - p.pushPrefix(prefix, attr.Value) - return nil -} - -// createNSPrefix creates a name space prefix attribute -// to use for the given name space, defining a new prefix -// if necessary. -// If isAttr is true, the prefix is to be created for an attribute -// prefix, which means that the default name space cannot -// be used. -func (p *printer) createNSPrefix(url string, isAttr bool) { - if _, ok := p.attrPrefix[url]; ok { - // We already have a prefix for the given URL. - return - } - switch { - case !isAttr && url == p.defaultNS: - // We can use the default name space. - return - case url == "": - // The only way we can encode names in the empty - // name space is by using the default name space, - // so we must use that. - if p.defaultNS != "" { - // The default namespace is non-empty, so we - // need to set it to empty. - p.pushPrefix("", "") - } - return - case url == xmlURL: - return - } - // TODO If the URL is an existing prefix, we could - // use it as is. That would enable the - // marshaling of elements that had been unmarshaled - // and with a name space prefix that was not found. - // although technically it would be incorrect. - - // Pick a name. We try to use the final element of the path - // but fall back to _. - prefix := strings.TrimRight(url, "/") - if i := strings.LastIndex(prefix, "/"); i >= 0 { - prefix = prefix[i+1:] - } - if prefix == "" || !isName([]byte(prefix)) || strings.Contains(prefix, ":") { - prefix = "_" - } - if strings.HasPrefix(prefix, "xml") { - // xmlanything is reserved. - prefix = "_" + prefix - } - if p.attrNS[prefix] != "" { - // Name is taken. Find a better one. - for p.seq++; ; p.seq++ { - if id := prefix + "_" + strconv.Itoa(p.seq); p.attrNS[id] == "" { - prefix = id - break - } - } - } - - p.pushPrefix(prefix, url) -} - -// writeNamespaces writes xmlns attributes for all the -// namespace prefixes that have been defined in -// the current element. -func (p *printer) writeNamespaces() { - for i := len(p.prefixes) - 1; i >= 0; i-- { - prefix := p.prefixes[i] - if prefix.mark { - return - } - p.WriteString(" ") - if prefix.prefix == "" { - // Default name space. - p.WriteString(`xmlns="`) - } else { - p.WriteString("xmlns:") - p.WriteString(prefix.prefix) - p.WriteString(`="`) - } - EscapeText(p, []byte(p.nsForPrefix(prefix.prefix))) - p.WriteString(`"`) - } -} - -// pushPrefix pushes a new prefix on the prefix stack -// without checking to see if it is already defined. -func (p *printer) pushPrefix(prefix, url string) { - p.prefixes = append(p.prefixes, printerPrefix{ - prefix: prefix, - url: p.nsForPrefix(prefix), - }) - p.setAttrPrefix(prefix, url) -} - -// nsForPrefix returns the name space for the given -// prefix. Note that this is not valid for the -// empty attribute prefix, which always has an empty -// name space. -func (p *printer) nsForPrefix(prefix string) string { - if prefix == "" { - return p.defaultNS - } - return p.attrNS[prefix] -} - -// markPrefix marks the start of an element on the prefix -// stack. -func (p *printer) markPrefix() { - p.prefixes = append(p.prefixes, printerPrefix{ - mark: true, - }) -} - -// popPrefix pops all defined prefixes for the current -// element. -func (p *printer) popPrefix() { - for len(p.prefixes) > 0 { - prefix := p.prefixes[len(p.prefixes)-1] - p.prefixes = p.prefixes[:len(p.prefixes)-1] - if prefix.mark { - break - } - p.setAttrPrefix(prefix.prefix, prefix.url) - } -} - -// setAttrPrefix sets an attribute name space prefix. -// If url is empty, the attribute is removed. -// If prefix is empty, the default name space is set. -func (p *printer) setAttrPrefix(prefix, url string) { - if prefix == "" { - p.defaultNS = url - return - } - if url == "" { - delete(p.attrPrefix, p.attrNS[prefix]) - delete(p.attrNS, prefix) - return - } - if p.attrPrefix == nil { - // Need to define a new name space. - p.attrPrefix = make(map[string]string) - p.attrNS = make(map[string]string) - } - // Remove any old prefix value. This is OK because we maintain a - // strict one-to-one mapping between prefix and URL (see - // defineNS) - delete(p.attrPrefix, p.attrNS[prefix]) - p.attrPrefix[url] = prefix - p.attrNS[prefix] = url -} - -var ( - marshalerType = reflect.TypeOf((*Marshaler)(nil)).Elem() - marshalerAttrType = reflect.TypeOf((*MarshalerAttr)(nil)).Elem() - textMarshalerType = reflect.TypeOf((*encoding.TextMarshaler)(nil)).Elem() -) - -// 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, startTemplate *StartElement) error { - if startTemplate != nil && startTemplate.Name.Local == "" { - return fmt.Errorf("xml: EncodeElement of StartElement with missing name") - } - - if !val.IsValid() { - return nil - } - if finfo != nil && finfo.flags&fOmitEmpty != 0 && isEmptyValue(val) { - return nil - } - - // Drill into interfaces and pointers. - // This can turn into an infinite loop given a cyclic chain, - // but it matches the Go 1 behavior. - for val.Kind() == reflect.Interface || val.Kind() == reflect.Ptr { - if val.IsNil() { - return nil - } - val = val.Elem() - } - - kind := val.Kind() - typ := val.Type() - - // Check for marshaler. - if val.CanInterface() && typ.Implements(marshalerType) { - return p.marshalInterface(val.Interface().(Marshaler), p.defaultStart(typ, finfo, startTemplate)) - } - if val.CanAddr() { - pv := val.Addr() - if pv.CanInterface() && pv.Type().Implements(marshalerType) { - return p.marshalInterface(pv.Interface().(Marshaler), p.defaultStart(pv.Type(), finfo, startTemplate)) - } - } - - // Check for text marshaler. - if val.CanInterface() && typ.Implements(textMarshalerType) { - return p.marshalTextInterface(val.Interface().(encoding.TextMarshaler), p.defaultStart(typ, finfo, startTemplate)) - } - if val.CanAddr() { - pv := val.Addr() - if pv.CanInterface() && pv.Type().Implements(textMarshalerType) { - return p.marshalTextInterface(pv.Interface().(encoding.TextMarshaler), p.defaultStart(pv.Type(), finfo, startTemplate)) - } - } - - // Slices and arrays iterate over the elements. They do not have an enclosing tag. - if (kind == reflect.Slice || kind == reflect.Array) && typ.Elem().Kind() != reflect.Uint8 { - for i, n := 0, val.Len(); i < n; i++ { - if err := p.marshalValue(val.Index(i), finfo, startTemplate); err != nil { - return err - } - } - return nil - } - - tinfo, err := getTypeInfo(typ) - if err != nil { - return err - } - - // Create start element. - // Precedence for the XML element name is: - // 0. startTemplate - // 1. XMLName field in underlying struct; - // 2. field name/tag in the struct field; and - // 3. type name - var start StartElement - - // explicitNS records whether the element's name space has been - // explicitly set (for example an XMLName field). - explicitNS := false - - if startTemplate != nil { - start.Name = startTemplate.Name - explicitNS = true - start.Attr = append(start.Attr, startTemplate.Attr...) - } else if tinfo.xmlname != nil { - xmlname := tinfo.xmlname - if xmlname.name != "" { - start.Name.Space, start.Name.Local = xmlname.xmlns, xmlname.name - } else if v, ok := xmlname.value(val).Interface().(Name); ok && v.Local != "" { - start.Name = v - } - explicitNS = true - } - if start.Name.Local == "" && finfo != nil { - start.Name.Local = finfo.name - if finfo.xmlns != "" { - start.Name.Space = finfo.xmlns - explicitNS = true - } - } - if start.Name.Local == "" { - name := typ.Name() - if name == "" { - return &UnsupportedTypeError{typ} - } - start.Name.Local = name - } - - // defaultNS records the default name space as set by a xmlns="..." - // attribute. We don't set p.defaultNS because we want to let - // the attribute writing code (in p.defineNS) be solely responsible - // for maintaining that. - defaultNS := p.defaultNS - - // Attributes - for i := range tinfo.fields { - finfo := &tinfo.fields[i] - if finfo.flags&fAttr == 0 { - continue - } - attr, err := p.fieldAttr(finfo, val) - if err != nil { - return err - } - if attr.Name.Local == "" { - continue - } - start.Attr = append(start.Attr, attr) - if attr.Name.Space == "" && attr.Name.Local == "xmlns" { - defaultNS = attr.Value - } - } - if !explicitNS { - // Historic behavior: elements use the default name space - // they are contained in by default. - start.Name.Space = defaultNS - } - // Historic behaviour: an element that's in a namespace sets - // the default namespace for all elements contained within it. - start.setDefaultNamespace() - - if err := p.writeStart(&start); err != nil { - return err - } - - if val.Kind() == reflect.Struct { - err = p.marshalStruct(tinfo, val) - } else { - s, b, err1 := p.marshalSimple(typ, val) - if err1 != nil { - err = err1 - } else if b != nil { - EscapeText(p, b) - } else { - p.EscapeString(s) - } - } - if err != nil { - return err - } - - if err := p.writeEnd(start.Name); err != nil { - return err - } - - return p.cachedWriteError() -} - -// fieldAttr returns the attribute of the given field. -// If the returned attribute has an empty Name.Local, -// it should not be used. -// The given value holds the value containing the field. -func (p *printer) fieldAttr(finfo *fieldInfo, val reflect.Value) (Attr, error) { - fv := finfo.value(val) - name := Name{Space: finfo.xmlns, Local: finfo.name} - if finfo.flags&fOmitEmpty != 0 && isEmptyValue(fv) { - return Attr{}, nil - } - if fv.Kind() == reflect.Interface && fv.IsNil() { - return Attr{}, nil - } - if fv.CanInterface() && fv.Type().Implements(marshalerAttrType) { - attr, err := fv.Interface().(MarshalerAttr).MarshalXMLAttr(name) - return attr, err - } - if fv.CanAddr() { - pv := fv.Addr() - if pv.CanInterface() && pv.Type().Implements(marshalerAttrType) { - attr, err := pv.Interface().(MarshalerAttr).MarshalXMLAttr(name) - return attr, err - } - } - if fv.CanInterface() && fv.Type().Implements(textMarshalerType) { - text, err := fv.Interface().(encoding.TextMarshaler).MarshalText() - if err != nil { - return Attr{}, err - } - return Attr{name, string(text)}, nil - } - if fv.CanAddr() { - pv := fv.Addr() - if pv.CanInterface() && pv.Type().Implements(textMarshalerType) { - text, err := pv.Interface().(encoding.TextMarshaler).MarshalText() - if err != nil { - return Attr{}, err - } - return Attr{name, string(text)}, nil - } - } - // Dereference or skip nil pointer, interface values. - switch fv.Kind() { - case reflect.Ptr, reflect.Interface: - if fv.IsNil() { - return Attr{}, nil - } - fv = fv.Elem() - } - s, b, err := p.marshalSimple(fv.Type(), fv) - if err != nil { - return Attr{}, err - } - if b != nil { - s = string(b) - } - return Attr{name, s}, nil -} - -// defaultStart returns the default start element to use, -// given the reflect type, field info, and start template. -func (p *printer) defaultStart(typ reflect.Type, finfo *fieldInfo, startTemplate *StartElement) StartElement { - var start StartElement - // Precedence for the XML element name is as above, - // except that we do not look inside structs for the first field. - if startTemplate != nil { - start.Name = startTemplate.Name - start.Attr = append(start.Attr, startTemplate.Attr...) - } else if finfo != nil && finfo.name != "" { - start.Name.Local = finfo.name - start.Name.Space = finfo.xmlns - } else if typ.Name() != "" { - start.Name.Local = typ.Name() - } else { - // Must be a pointer to a named type, - // since it has the Marshaler methods. - start.Name.Local = typ.Elem().Name() - } - // Historic behaviour: elements use the name space of - // the element they are contained in by default. - if start.Name.Space == "" { - start.Name.Space = p.defaultNS - } - start.setDefaultNamespace() - return start -} - -// marshalInterface marshals a Marshaler interface value. -func (p *printer) marshalInterface(val Marshaler, start StartElement) error { - // Push a marker onto the tag stack so that MarshalXML - // cannot close the XML tags that it did not open. - p.tags = append(p.tags, Name{}) - n := len(p.tags) - - err := val.MarshalXML(p.encoder, start) - if err != nil { - return err - } - - // Make sure MarshalXML closed all its tags. p.tags[n-1] is the mark. - if len(p.tags) > n { - return fmt.Errorf("xml: %s.MarshalXML wrote invalid XML: <%s> not closed", receiverType(val), p.tags[len(p.tags)-1].Local) - } - p.tags = p.tags[:n-1] - return nil -} - -// marshalTextInterface marshals a TextMarshaler interface value. -func (p *printer) marshalTextInterface(val encoding.TextMarshaler, start StartElement) error { - if err := p.writeStart(&start); err != nil { - return err - } - text, err := val.MarshalText() - if err != nil { - return err - } - EscapeText(p, text) - return p.writeEnd(start.Name) -} - -// writeStart writes the given start element. -func (p *printer) writeStart(start *StartElement) error { - if start.Name.Local == "" { - return fmt.Errorf("xml: start tag with no name") - } - - p.tags = append(p.tags, start.Name) - p.markPrefix() - // Define any name spaces explicitly declared in the attributes. - // We do this as a separate pass so that explicitly declared prefixes - // will take precedence over implicitly declared prefixes - // regardless of the order of the attributes. - ignoreNonEmptyDefault := start.Name.Space == "" - for _, attr := range start.Attr { - if err := p.defineNS(attr, ignoreNonEmptyDefault); err != nil { - return err - } - } - // Define any new name spaces implied by the attributes. - for _, attr := range start.Attr { - name := attr.Name - // From http://www.w3.org/TR/xml-names11/#defaulting - // "Default namespace declarations do not apply directly - // to attribute names; the interpretation of unprefixed - // attributes is determined by the element on which they - // appear." - // This means we don't need to create a new namespace - // when an attribute name space is empty. - if name.Space != "" && !name.isNamespace() { - p.createNSPrefix(name.Space, true) - } - } - p.createNSPrefix(start.Name.Space, false) - - p.writeIndent(1) - p.WriteByte('<') - p.writeName(start.Name, false) - p.writeNamespaces() - for _, attr := range start.Attr { - name := attr.Name - if name.Local == "" || name.isNamespace() { - // Namespaces have already been written by writeNamespaces above. - continue - } - p.WriteByte(' ') - p.writeName(name, true) - p.WriteString(`="`) - p.EscapeString(attr.Value) - p.WriteByte('"') - } - p.WriteByte('>') - return nil -} - -// writeName writes the given name. It assumes -// that p.createNSPrefix(name) has already been called. -func (p *printer) writeName(name Name, isAttr bool) { - if prefix := p.prefixForNS(name.Space, isAttr); prefix != "" { - p.WriteString(prefix) - p.WriteByte(':') - } - p.WriteString(name.Local) -} - -func (p *printer) writeEnd(name Name) error { - if name.Local == "" { - return fmt.Errorf("xml: end tag with no name") - } - if len(p.tags) == 0 || p.tags[len(p.tags)-1].Local == "" { - return fmt.Errorf("xml: end tag </%s> without start tag", name.Local) - } - if top := p.tags[len(p.tags)-1]; top != name { - if top.Local != name.Local { - return fmt.Errorf("xml: end tag </%s> does not match start tag <%s>", name.Local, top.Local) - } - return fmt.Errorf("xml: end tag </%s> in namespace %s does not match start tag <%s> in namespace %s", name.Local, name.Space, top.Local, top.Space) - } - p.tags = p.tags[:len(p.tags)-1] - - p.writeIndent(-1) - p.WriteByte('<') - p.WriteByte('/') - p.writeName(name, false) - p.WriteByte('>') - p.popPrefix() - return nil -} - -func (p *printer) marshalSimple(typ reflect.Type, val reflect.Value) (string, []byte, error) { - switch val.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return strconv.FormatInt(val.Int(), 10), nil, nil - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return strconv.FormatUint(val.Uint(), 10), nil, nil - case reflect.Float32, reflect.Float64: - return strconv.FormatFloat(val.Float(), 'g', -1, val.Type().Bits()), nil, nil - case reflect.String: - return val.String(), nil, nil - case reflect.Bool: - return strconv.FormatBool(val.Bool()), nil, nil - case reflect.Array: - if typ.Elem().Kind() != reflect.Uint8 { - break - } - // [...]byte - var bytes []byte - if val.CanAddr() { - bytes = val.Slice(0, val.Len()).Bytes() - } else { - bytes = make([]byte, val.Len()) - reflect.Copy(reflect.ValueOf(bytes), val) - } - return "", bytes, nil - case reflect.Slice: - if typ.Elem().Kind() != reflect.Uint8 { - break - } - // []byte - return "", val.Bytes(), nil - } - return "", nil, &UnsupportedTypeError{typ} -} - -var ddBytes = []byte("--") - -func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error { - s := parentStack{p: p} - for i := range tinfo.fields { - finfo := &tinfo.fields[i] - if finfo.flags&fAttr != 0 { - continue - } - vf := finfo.value(val) - - // Dereference or skip nil pointer, interface values. - switch vf.Kind() { - case reflect.Ptr, reflect.Interface: - if !vf.IsNil() { - vf = vf.Elem() - } - } - - switch finfo.flags & fMode { - case fCharData: - if err := s.setParents(&noField, reflect.Value{}); err != nil { - return err - } - if vf.CanInterface() && vf.Type().Implements(textMarshalerType) { - data, err := vf.Interface().(encoding.TextMarshaler).MarshalText() - if err != nil { - return err - } - Escape(p, data) - continue - } - if vf.CanAddr() { - pv := vf.Addr() - if pv.CanInterface() && pv.Type().Implements(textMarshalerType) { - data, err := pv.Interface().(encoding.TextMarshaler).MarshalText() - if err != nil { - return err - } - Escape(p, data) - continue - } - } - var scratch [64]byte - switch vf.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - Escape(p, strconv.AppendInt(scratch[:0], vf.Int(), 10)) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - Escape(p, strconv.AppendUint(scratch[:0], vf.Uint(), 10)) - case reflect.Float32, reflect.Float64: - Escape(p, strconv.AppendFloat(scratch[:0], vf.Float(), 'g', -1, vf.Type().Bits())) - case reflect.Bool: - Escape(p, strconv.AppendBool(scratch[:0], vf.Bool())) - case reflect.String: - if err := EscapeText(p, []byte(vf.String())); err != nil { - return err - } - case reflect.Slice: - if elem, ok := vf.Interface().([]byte); ok { - if err := EscapeText(p, elem); err != nil { - return err - } - } - } - continue - - case fComment: - if err := s.setParents(&noField, reflect.Value{}); err != nil { - return err - } - k := vf.Kind() - if !(k == reflect.String || k == reflect.Slice && vf.Type().Elem().Kind() == reflect.Uint8) { - return fmt.Errorf("xml: bad type for comment field of %s", val.Type()) - } - if vf.Len() == 0 { - continue - } - p.writeIndent(0) - p.WriteString("<!--") - dashDash := false - dashLast := false - switch k { - case reflect.String: - s := vf.String() - dashDash = strings.Index(s, "--") >= 0 - dashLast = s[len(s)-1] == '-' - if !dashDash { - p.WriteString(s) - } - case reflect.Slice: - b := vf.Bytes() - dashDash = bytes.Index(b, ddBytes) >= 0 - dashLast = b[len(b)-1] == '-' - if !dashDash { - p.Write(b) - } - default: - panic("can't happen") - } - if dashDash { - return fmt.Errorf(`xml: comments must not contain "--"`) - } - if dashLast { - // "--->" is invalid grammar. Make it "- -->" - p.WriteByte(' ') - } - p.WriteString("-->") - continue - - case fInnerXml: - iface := vf.Interface() - switch raw := iface.(type) { - case []byte: - p.Write(raw) - continue - case string: - p.WriteString(raw) - continue - } - - case fElement, fElement | fAny: - if err := s.setParents(finfo, vf); err != nil { - return err - } - } - if err := p.marshalValue(vf, finfo, nil); err != nil { - return err - } - } - if err := s.setParents(&noField, reflect.Value{}); err != nil { - return err - } - return p.cachedWriteError() -} - -var noField fieldInfo - -// return the bufio Writer's cached write error -func (p *printer) cachedWriteError() error { - _, err := p.Write(nil) - return err -} - -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 - } - if p.putNewline { - p.WriteByte('\n') - } else { - p.putNewline = true - } - 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 { - p *printer - xmlns string - parents []string -} - -// setParents sets the stack of current parents to those found in finfo. -// It only writes the start elements if vf holds a non-nil value. -// If finfo is &noField, it pops all elements. -func (s *parentStack) setParents(finfo *fieldInfo, vf reflect.Value) error { - xmlns := s.p.defaultNS - if finfo.xmlns != "" { - xmlns = finfo.xmlns - } - commonParents := 0 - if xmlns == s.xmlns { - for ; commonParents < len(finfo.parents) && commonParents < len(s.parents); commonParents++ { - if finfo.parents[commonParents] != s.parents[commonParents] { - break - } - } - } - // Pop off any parents that aren't in common with the previous field. - for i := len(s.parents) - 1; i >= commonParents; i-- { - if err := s.p.writeEnd(Name{ - Space: s.xmlns, - Local: s.parents[i], - }); err != nil { - return err - } - } - s.parents = finfo.parents - s.xmlns = xmlns - if commonParents >= len(s.parents) { - // No new elements to push. - return nil - } - if (vf.Kind() == reflect.Ptr || vf.Kind() == reflect.Interface) && vf.IsNil() { - // The element is nil, so no need for the start elements. - s.parents = s.parents[:commonParents] - return nil - } - // Push any new parents required. - for _, name := range s.parents[commonParents:] { - start := &StartElement{ - Name: Name{ - Space: s.xmlns, - Local: name, - }, - } - // Set the default name space for parent elements - // to match what we do with other elements. - if s.xmlns != s.p.defaultNS { - start.setDefaultNamespace() - } - if err := s.p.writeStart(start); err != nil { - return err - } - } - return nil -} - -// A MarshalXMLError is returned when Marshal encounters a type -// that cannot be converted into XML. -type UnsupportedTypeError struct { - Type reflect.Type -} - -func (e *UnsupportedTypeError) Error() string { - return "xml: unsupported type: " + e.Type.String() -} - -func isEmptyValue(v reflect.Value) bool { - switch v.Kind() { - case reflect.Array, reflect.Map, reflect.Slice, reflect.String: - return v.Len() == 0 - case reflect.Bool: - return !v.Bool() - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return v.Int() == 0 - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return v.Uint() == 0 - case reflect.Float32, reflect.Float64: - return v.Float() == 0 - case reflect.Interface, reflect.Ptr: - return v.IsNil() - } - return false -} diff --git a/vendor/golang.org/x/net/webdav/internal/xml/marshal_test.go b/vendor/golang.org/x/net/webdav/internal/xml/marshal_test.go deleted file mode 100644 index 226cfd013..000000000 --- a/vendor/golang.org/x/net/webdav/internal/xml/marshal_test.go +++ /dev/null @@ -1,1939 +0,0 @@ -// Copyright 2011 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 - -import ( - "bytes" - "errors" - "fmt" - "io" - "reflect" - "strconv" - "strings" - "sync" - "testing" - "time" -) - -type DriveType int - -const ( - HyperDrive DriveType = iota - ImprobabilityDrive -) - -type Passenger struct { - Name []string `xml:"name"` - Weight float32 `xml:"weight"` -} - -type Ship struct { - XMLName struct{} `xml:"spaceship"` - - Name string `xml:"name,attr"` - Pilot string `xml:"pilot,attr"` - Drive DriveType `xml:"drive"` - Age uint `xml:"age"` - Passenger []*Passenger `xml:"passenger"` - secret string -} - -type NamedType string - -type Port struct { - XMLName struct{} `xml:"port"` - Type string `xml:"type,attr,omitempty"` - Comment string `xml:",comment"` - Number string `xml:",chardata"` -} - -type Domain struct { - XMLName struct{} `xml:"domain"` - Country string `xml:",attr,omitempty"` - Name []byte `xml:",chardata"` - Comment []byte `xml:",comment"` -} - -type Book struct { - XMLName struct{} `xml:"book"` - Title string `xml:",chardata"` -} - -type Event struct { - XMLName struct{} `xml:"event"` - Year int `xml:",chardata"` -} - -type Movie struct { - XMLName struct{} `xml:"movie"` - Length uint `xml:",chardata"` -} - -type Pi struct { - XMLName struct{} `xml:"pi"` - Approximation float32 `xml:",chardata"` -} - -type Universe struct { - XMLName struct{} `xml:"universe"` - Visible float64 `xml:",chardata"` -} - -type Particle struct { - XMLName struct{} `xml:"particle"` - HasMass bool `xml:",chardata"` -} - -type Departure struct { - XMLName struct{} `xml:"departure"` - When time.Time `xml:",chardata"` -} - -type SecretAgent struct { - XMLName struct{} `xml:"agent"` - Handle string `xml:"handle,attr"` - Identity string - Obfuscate string `xml:",innerxml"` -} - -type NestedItems struct { - XMLName struct{} `xml:"result"` - Items []string `xml:">item"` - Item1 []string `xml:"Items>item1"` -} - -type NestedOrder struct { - XMLName struct{} `xml:"result"` - Field1 string `xml:"parent>c"` - Field2 string `xml:"parent>b"` - Field3 string `xml:"parent>a"` -} - -type MixedNested struct { - XMLName struct{} `xml:"result"` - A string `xml:"parent1>a"` - B string `xml:"b"` - C string `xml:"parent1>parent2>c"` - D string `xml:"parent1>d"` -} - -type NilTest struct { - A interface{} `xml:"parent1>parent2>a"` - B interface{} `xml:"parent1>b"` - C interface{} `xml:"parent1>parent2>c"` -} - -type Service struct { - XMLName struct{} `xml:"service"` - Domain *Domain `xml:"host>domain"` - Port *Port `xml:"host>port"` - Extra1 interface{} - Extra2 interface{} `xml:"host>extra2"` -} - -var nilStruct *Ship - -type EmbedA struct { - EmbedC - EmbedB EmbedB - FieldA string -} - -type EmbedB struct { - FieldB string - *EmbedC -} - -type EmbedC struct { - FieldA1 string `xml:"FieldA>A1"` - FieldA2 string `xml:"FieldA>A2"` - FieldB string - FieldC string -} - -type NameCasing struct { - XMLName struct{} `xml:"casing"` - Xy string - XY string - XyA string `xml:"Xy,attr"` - XYA string `xml:"XY,attr"` -} - -type NamePrecedence struct { - XMLName Name `xml:"Parent"` - FromTag XMLNameWithoutTag `xml:"InTag"` - FromNameVal XMLNameWithoutTag - FromNameTag XMLNameWithTag - InFieldName string -} - -type XMLNameWithTag struct { - XMLName Name `xml:"InXMLNameTag"` - Value string `xml:",chardata"` -} - -type XMLNameWithNSTag struct { - XMLName Name `xml:"ns InXMLNameWithNSTag"` - Value string `xml:",chardata"` -} - -type XMLNameWithoutTag struct { - XMLName Name - Value string `xml:",chardata"` -} - -type NameInField struct { - Foo Name `xml:"ns foo"` -} - -type AttrTest struct { - Int int `xml:",attr"` - Named int `xml:"int,attr"` - Float float64 `xml:",attr"` - Uint8 uint8 `xml:",attr"` - Bool bool `xml:",attr"` - Str string `xml:",attr"` - Bytes []byte `xml:",attr"` -} - -type OmitAttrTest struct { - Int int `xml:",attr,omitempty"` - Named int `xml:"int,attr,omitempty"` - Float float64 `xml:",attr,omitempty"` - Uint8 uint8 `xml:",attr,omitempty"` - Bool bool `xml:",attr,omitempty"` - Str string `xml:",attr,omitempty"` - Bytes []byte `xml:",attr,omitempty"` -} - -type OmitFieldTest struct { - Int int `xml:",omitempty"` - Named int `xml:"int,omitempty"` - Float float64 `xml:",omitempty"` - Uint8 uint8 `xml:",omitempty"` - Bool bool `xml:",omitempty"` - Str string `xml:",omitempty"` - Bytes []byte `xml:",omitempty"` - Ptr *PresenceTest `xml:",omitempty"` -} - -type AnyTest struct { - XMLName struct{} `xml:"a"` - Nested string `xml:"nested>value"` - AnyField AnyHolder `xml:",any"` -} - -type AnyOmitTest struct { - XMLName struct{} `xml:"a"` - Nested string `xml:"nested>value"` - AnyField *AnyHolder `xml:",any,omitempty"` -} - -type AnySliceTest struct { - XMLName struct{} `xml:"a"` - Nested string `xml:"nested>value"` - AnyField []AnyHolder `xml:",any"` -} - -type AnyHolder struct { - XMLName Name - XML string `xml:",innerxml"` -} - -type RecurseA struct { - A string - B *RecurseB -} - -type RecurseB struct { - A *RecurseA - B string -} - -type PresenceTest struct { - Exists *struct{} -} - -type IgnoreTest struct { - PublicSecret string `xml:"-"` -} - -type MyBytes []byte - -type Data struct { - Bytes []byte - Attr []byte `xml:",attr"` - Custom MyBytes -} - -type Plain struct { - V interface{} -} - -type MyInt int - -type EmbedInt struct { - MyInt -} - -type Strings struct { - X []string `xml:"A>B,omitempty"` -} - -type PointerFieldsTest struct { - XMLName Name `xml:"dummy"` - Name *string `xml:"name,attr"` - Age *uint `xml:"age,attr"` - Empty *string `xml:"empty,attr"` - Contents *string `xml:",chardata"` -} - -type ChardataEmptyTest struct { - XMLName Name `xml:"test"` - Contents *string `xml:",chardata"` -} - -type MyMarshalerTest struct { -} - -var _ Marshaler = (*MyMarshalerTest)(nil) - -func (m *MyMarshalerTest) MarshalXML(e *Encoder, start StartElement) error { - e.EncodeToken(start) - e.EncodeToken(CharData([]byte("hello world"))) - e.EncodeToken(EndElement{start.Name}) - return nil -} - -type MyMarshalerAttrTest struct{} - -var _ MarshalerAttr = (*MyMarshalerAttrTest)(nil) - -func (m *MyMarshalerAttrTest) MarshalXMLAttr(name Name) (Attr, error) { - return Attr{name, "hello world"}, nil -} - -type MyMarshalerValueAttrTest struct{} - -var _ MarshalerAttr = MyMarshalerValueAttrTest{} - -func (m MyMarshalerValueAttrTest) MarshalXMLAttr(name Name) (Attr, error) { - return Attr{name, "hello world"}, nil -} - -type MarshalerStruct struct { - Foo MyMarshalerAttrTest `xml:",attr"` -} - -type MarshalerValueStruct struct { - Foo MyMarshalerValueAttrTest `xml:",attr"` -} - -type InnerStruct struct { - XMLName Name `xml:"testns outer"` -} - -type OuterStruct struct { - InnerStruct - IntAttr int `xml:"int,attr"` -} - -type OuterNamedStruct struct { - InnerStruct - XMLName Name `xml:"outerns test"` - IntAttr int `xml:"int,attr"` -} - -type OuterNamedOrderedStruct struct { - XMLName Name `xml:"outerns test"` - InnerStruct - IntAttr int `xml:"int,attr"` -} - -type OuterOuterStruct struct { - OuterStruct -} - -type NestedAndChardata struct { - AB []string `xml:"A>B"` - Chardata string `xml:",chardata"` -} - -type NestedAndComment struct { - AB []string `xml:"A>B"` - Comment string `xml:",comment"` -} - -type XMLNSFieldStruct struct { - Ns string `xml:"xmlns,attr"` - Body string -} - -type NamedXMLNSFieldStruct struct { - XMLName struct{} `xml:"testns test"` - Ns string `xml:"xmlns,attr"` - Body string -} - -type XMLNSFieldStructWithOmitEmpty struct { - Ns string `xml:"xmlns,attr,omitempty"` - Body string -} - -type NamedXMLNSFieldStructWithEmptyNamespace struct { - XMLName struct{} `xml:"test"` - Ns string `xml:"xmlns,attr"` - Body string -} - -type RecursiveXMLNSFieldStruct struct { - Ns string `xml:"xmlns,attr"` - Body *RecursiveXMLNSFieldStruct `xml:",omitempty"` - Text string `xml:",omitempty"` -} - -func ifaceptr(x interface{}) interface{} { - return &x -} - -var ( - nameAttr = "Sarah" - ageAttr = uint(12) - contentsAttr = "lorem ipsum" -) - -// Unless explicitly stated as such (or *Plain), all of the -// tests below are two-way tests. When introducing new tests, -// please try to make them two-way as well to ensure that -// marshalling and unmarshalling are as symmetrical as feasible. -var marshalTests = []struct { - Value interface{} - ExpectXML string - MarshalOnly bool - UnmarshalOnly bool -}{ - // Test nil marshals to nothing - {Value: nil, ExpectXML: ``, MarshalOnly: true}, - {Value: nilStruct, ExpectXML: ``, MarshalOnly: true}, - - // Test value types - {Value: &Plain{true}, ExpectXML: `<Plain><V>true</V></Plain>`}, - {Value: &Plain{false}, ExpectXML: `<Plain><V>false</V></Plain>`}, - {Value: &Plain{int(42)}, ExpectXML: `<Plain><V>42</V></Plain>`}, - {Value: &Plain{int8(42)}, ExpectXML: `<Plain><V>42</V></Plain>`}, - {Value: &Plain{int16(42)}, ExpectXML: `<Plain><V>42</V></Plain>`}, - {Value: &Plain{int32(42)}, ExpectXML: `<Plain><V>42</V></Plain>`}, - {Value: &Plain{uint(42)}, ExpectXML: `<Plain><V>42</V></Plain>`}, - {Value: &Plain{uint8(42)}, ExpectXML: `<Plain><V>42</V></Plain>`}, - {Value: &Plain{uint16(42)}, ExpectXML: `<Plain><V>42</V></Plain>`}, - {Value: &Plain{uint32(42)}, ExpectXML: `<Plain><V>42</V></Plain>`}, - {Value: &Plain{float32(1.25)}, ExpectXML: `<Plain><V>1.25</V></Plain>`}, - {Value: &Plain{float64(1.25)}, ExpectXML: `<Plain><V>1.25</V></Plain>`}, - {Value: &Plain{uintptr(0xFFDD)}, ExpectXML: `<Plain><V>65501</V></Plain>`}, - {Value: &Plain{"gopher"}, ExpectXML: `<Plain><V>gopher</V></Plain>`}, - {Value: &Plain{[]byte("gopher")}, ExpectXML: `<Plain><V>gopher</V></Plain>`}, - {Value: &Plain{"</>"}, ExpectXML: `<Plain><V></></V></Plain>`}, - {Value: &Plain{[]byte("</>")}, ExpectXML: `<Plain><V></></V></Plain>`}, - {Value: &Plain{[3]byte{'<', '/', '>'}}, ExpectXML: `<Plain><V></></V></Plain>`}, - {Value: &Plain{NamedType("potato")}, ExpectXML: `<Plain><V>potato</V></Plain>`}, - {Value: &Plain{[]int{1, 2, 3}}, ExpectXML: `<Plain><V>1</V><V>2</V><V>3</V></Plain>`}, - {Value: &Plain{[3]int{1, 2, 3}}, ExpectXML: `<Plain><V>1</V><V>2</V><V>3</V></Plain>`}, - {Value: ifaceptr(true), MarshalOnly: true, ExpectXML: `<bool>true</bool>`}, - - // Test time. - { - Value: &Plain{time.Unix(1e9, 123456789).UTC()}, - ExpectXML: `<Plain><V>2001-09-09T01:46:40.123456789Z</V></Plain>`, - }, - - // A pointer to struct{} may be used to test for an element's presence. - { - Value: &PresenceTest{new(struct{})}, - ExpectXML: `<PresenceTest><Exists></Exists></PresenceTest>`, - }, - { - Value: &PresenceTest{}, - ExpectXML: `<PresenceTest></PresenceTest>`, - }, - - // A pointer to struct{} may be used to test for an element's presence. - { - Value: &PresenceTest{new(struct{})}, - ExpectXML: `<PresenceTest><Exists></Exists></PresenceTest>`, - }, - { - Value: &PresenceTest{}, - ExpectXML: `<PresenceTest></PresenceTest>`, - }, - - // A []byte field is only nil if the element was not found. - { - Value: &Data{}, - ExpectXML: `<Data></Data>`, - UnmarshalOnly: true, - }, - { - Value: &Data{Bytes: []byte{}, Custom: MyBytes{}, Attr: []byte{}}, - ExpectXML: `<Data Attr=""><Bytes></Bytes><Custom></Custom></Data>`, - UnmarshalOnly: true, - }, - - // Check that []byte works, including named []byte types. - { - Value: &Data{Bytes: []byte("ab"), Custom: MyBytes("cd"), Attr: []byte{'v'}}, - ExpectXML: `<Data Attr="v"><Bytes>ab</Bytes><Custom>cd</Custom></Data>`, - }, - - // Test innerxml - { - Value: &SecretAgent{ - Handle: "007", - Identity: "James Bond", - Obfuscate: "<redacted/>", - }, - ExpectXML: `<agent handle="007"><Identity>James Bond</Identity><redacted/></agent>`, - MarshalOnly: true, - }, - { - Value: &SecretAgent{ - Handle: "007", - Identity: "James Bond", - Obfuscate: "<Identity>James Bond</Identity><redacted/>", - }, - ExpectXML: `<agent handle="007"><Identity>James Bond</Identity><redacted/></agent>`, - UnmarshalOnly: true, - }, - - // Test structs - {Value: &Port{Type: "ssl", Number: "443"}, ExpectXML: `<port type="ssl">443</port>`}, - {Value: &Port{Number: "443"}, ExpectXML: `<port>443</port>`}, - {Value: &Port{Type: "<unix>"}, ExpectXML: `<port type="<unix>"></port>`}, - {Value: &Port{Number: "443", Comment: "https"}, ExpectXML: `<port><!--https-->443</port>`}, - {Value: &Port{Number: "443", Comment: "add space-"}, ExpectXML: `<port><!--add space- -->443</port>`, MarshalOnly: true}, - {Value: &Domain{Name: []byte("google.com&friends")}, ExpectXML: `<domain>google.com&friends</domain>`}, - {Value: &Domain{Name: []byte("google.com"), Comment: []byte(" &friends ")}, ExpectXML: `<domain>google.com<!-- &friends --></domain>`}, - {Value: &Book{Title: "Pride & Prejudice"}, ExpectXML: `<book>Pride & Prejudice</book>`}, - {Value: &Event{Year: -3114}, ExpectXML: `<event>-3114</event>`}, - {Value: &Movie{Length: 13440}, ExpectXML: `<movie>13440</movie>`}, - {Value: &Pi{Approximation: 3.14159265}, ExpectXML: `<pi>3.1415927</pi>`}, - {Value: &Universe{Visible: 9.3e13}, ExpectXML: `<universe>9.3e+13</universe>`}, - {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: atomValue, ExpectXML: atomXml}, - { - Value: &Ship{ - Name: "Heart of Gold", - Pilot: "Computer", - Age: 1, - Drive: ImprobabilityDrive, - Passenger: []*Passenger{ - { - Name: []string{"Zaphod", "Beeblebrox"}, - Weight: 7.25, - }, - { - Name: []string{"Trisha", "McMillen"}, - Weight: 5.5, - }, - { - Name: []string{"Ford", "Prefect"}, - Weight: 7, - }, - { - Name: []string{"Arthur", "Dent"}, - Weight: 6.75, - }, - }, - }, - ExpectXML: `<spaceship name="Heart of Gold" pilot="Computer">` + - `<drive>` + strconv.Itoa(int(ImprobabilityDrive)) + `</drive>` + - `<age>1</age>` + - `<passenger>` + - `<name>Zaphod</name>` + - `<name>Beeblebrox</name>` + - `<weight>7.25</weight>` + - `</passenger>` + - `<passenger>` + - `<name>Trisha</name>` + - `<name>McMillen</name>` + - `<weight>5.5</weight>` + - `</passenger>` + - `<passenger>` + - `<name>Ford</name>` + - `<name>Prefect</name>` + - `<weight>7</weight>` + - `</passenger>` + - `<passenger>` + - `<name>Arthur</name>` + - `<name>Dent</name>` + - `<weight>6.75</weight>` + - `</passenger>` + - `</spaceship>`, - }, - - // Test a>b - { - Value: &NestedItems{Items: nil, Item1: nil}, - ExpectXML: `<result>` + - `<Items>` + - `</Items>` + - `</result>`, - }, - { - Value: &NestedItems{Items: []string{}, Item1: []string{}}, - ExpectXML: `<result>` + - `<Items>` + - `</Items>` + - `</result>`, - MarshalOnly: true, - }, - { - Value: &NestedItems{Items: nil, Item1: []string{"A"}}, - ExpectXML: `<result>` + - `<Items>` + - `<item1>A</item1>` + - `</Items>` + - `</result>`, - }, - { - Value: &NestedItems{Items: []string{"A", "B"}, Item1: nil}, - ExpectXML: `<result>` + - `<Items>` + - `<item>A</item>` + - `<item>B</item>` + - `</Items>` + - `</result>`, - }, - { - Value: &NestedItems{Items: []string{"A", "B"}, Item1: []string{"C"}}, - ExpectXML: `<result>` + - `<Items>` + - `<item>A</item>` + - `<item>B</item>` + - `<item1>C</item1>` + - `</Items>` + - `</result>`, - }, - { - Value: &NestedOrder{Field1: "C", Field2: "B", Field3: "A"}, - ExpectXML: `<result>` + - `<parent>` + - `<c>C</c>` + - `<b>B</b>` + - `<a>A</a>` + - `</parent>` + - `</result>`, - }, - { - Value: &NilTest{A: "A", B: nil, C: "C"}, - ExpectXML: `<NilTest>` + - `<parent1>` + - `<parent2><a>A</a></parent2>` + - `<parent2><c>C</c></parent2>` + - `</parent1>` + - `</NilTest>`, - MarshalOnly: true, // Uses interface{} - }, - { - Value: &MixedNested{A: "A", B: "B", C: "C", D: "D"}, - ExpectXML: `<result>` + - `<parent1><a>A</a></parent1>` + - `<b>B</b>` + - `<parent1>` + - `<parent2><c>C</c></parent2>` + - `<d>D</d>` + - `</parent1>` + - `</result>`, - }, - { - Value: &Service{Port: &Port{Number: "80"}}, - ExpectXML: `<service><host><port>80</port></host></service>`, - }, - { - Value: &Service{}, - ExpectXML: `<service></service>`, - }, - { - Value: &Service{Port: &Port{Number: "80"}, Extra1: "A", Extra2: "B"}, - ExpectXML: `<service>` + - `<host><port>80</port></host>` + - `<Extra1>A</Extra1>` + - `<host><extra2>B</extra2></host>` + - `</service>`, - MarshalOnly: true, - }, - { - Value: &Service{Port: &Port{Number: "80"}, Extra2: "example"}, - ExpectXML: `<service>` + - `<host><port>80</port></host>` + - `<host><extra2>example</extra2></host>` + - `</service>`, - MarshalOnly: true, - }, - { - Value: &struct { - XMLName struct{} `xml:"space top"` - A string `xml:"x>a"` - B string `xml:"x>b"` - C string `xml:"space x>c"` - C1 string `xml:"space1 x>c"` - D1 string `xml:"space1 x>d"` - E1 string `xml:"x>e"` - }{ - A: "a", - B: "b", - C: "c", - C1: "c1", - D1: "d1", - E1: "e1", - }, - ExpectXML: `<top xmlns="space">` + - `<x><a>a</a><b>b</b><c>c</c></x>` + - `<x xmlns="space1">` + - `<c>c1</c>` + - `<d>d1</d>` + - `</x>` + - `<x>` + - `<e>e1</e>` + - `</x>` + - `</top>`, - }, - { - Value: &struct { - XMLName Name - A string `xml:"x>a"` - B string `xml:"x>b"` - C string `xml:"space x>c"` - C1 string `xml:"space1 x>c"` - D1 string `xml:"space1 x>d"` - }{ - XMLName: Name{ - Space: "space0", - Local: "top", - }, - A: "a", - B: "b", - C: "c", - C1: "c1", - D1: "d1", - }, - ExpectXML: `<top xmlns="space0">` + - `<x><a>a</a><b>b</b></x>` + - `<x xmlns="space"><c>c</c></x>` + - `<x xmlns="space1">` + - `<c>c1</c>` + - `<d>d1</d>` + - `</x>` + - `</top>`, - }, - { - Value: &struct { - XMLName struct{} `xml:"top"` - B string `xml:"space x>b"` - B1 string `xml:"space1 x>b"` - }{ - B: "b", - B1: "b1", - }, - ExpectXML: `<top>` + - `<x xmlns="space"><b>b</b></x>` + - `<x xmlns="space1"><b>b1</b></x>` + - `</top>`, - }, - - // Test struct embedding - { - Value: &EmbedA{ - EmbedC: EmbedC{ - FieldA1: "", // Shadowed by A.A - FieldA2: "", // Shadowed by A.A - FieldB: "A.C.B", - FieldC: "A.C.C", - }, - EmbedB: EmbedB{ - FieldB: "A.B.B", - EmbedC: &EmbedC{ - FieldA1: "A.B.C.A1", - FieldA2: "A.B.C.A2", - FieldB: "", // Shadowed by A.B.B - FieldC: "A.B.C.C", - }, - }, - FieldA: "A.A", - }, - ExpectXML: `<EmbedA>` + - `<FieldB>A.C.B</FieldB>` + - `<FieldC>A.C.C</FieldC>` + - `<EmbedB>` + - `<FieldB>A.B.B</FieldB>` + - `<FieldA>` + - `<A1>A.B.C.A1</A1>` + - `<A2>A.B.C.A2</A2>` + - `</FieldA>` + - `<FieldC>A.B.C.C</FieldC>` + - `</EmbedB>` + - `<FieldA>A.A</FieldA>` + - `</EmbedA>`, - }, - - // Test that name casing matters - { - Value: &NameCasing{Xy: "mixed", XY: "upper", XyA: "mixedA", XYA: "upperA"}, - ExpectXML: `<casing Xy="mixedA" XY="upperA"><Xy>mixed</Xy><XY>upper</XY></casing>`, - }, - - // Test the order in which the XML element name is chosen - { - Value: &NamePrecedence{ - FromTag: XMLNameWithoutTag{Value: "A"}, - FromNameVal: XMLNameWithoutTag{XMLName: Name{Local: "InXMLName"}, Value: "B"}, - FromNameTag: XMLNameWithTag{Value: "C"}, - InFieldName: "D", - }, - ExpectXML: `<Parent>` + - `<InTag>A</InTag>` + - `<InXMLName>B</InXMLName>` + - `<InXMLNameTag>C</InXMLNameTag>` + - `<InFieldName>D</InFieldName>` + - `</Parent>`, - MarshalOnly: true, - }, - { - Value: &NamePrecedence{ - XMLName: Name{Local: "Parent"}, - FromTag: XMLNameWithoutTag{XMLName: Name{Local: "InTag"}, Value: "A"}, - FromNameVal: XMLNameWithoutTag{XMLName: Name{Local: "FromNameVal"}, Value: "B"}, - FromNameTag: XMLNameWithTag{XMLName: Name{Local: "InXMLNameTag"}, Value: "C"}, - InFieldName: "D", - }, - ExpectXML: `<Parent>` + - `<InTag>A</InTag>` + - `<FromNameVal>B</FromNameVal>` + - `<InXMLNameTag>C</InXMLNameTag>` + - `<InFieldName>D</InFieldName>` + - `</Parent>`, - UnmarshalOnly: true, - }, - - // xml.Name works in a plain field as well. - { - Value: &NameInField{Name{Space: "ns", Local: "foo"}}, - ExpectXML: `<NameInField><foo xmlns="ns"></foo></NameInField>`, - }, - { - Value: &NameInField{Name{Space: "ns", Local: "foo"}}, - ExpectXML: `<NameInField><foo xmlns="ns"><ignore></ignore></foo></NameInField>`, - UnmarshalOnly: true, - }, - - // Marshaling zero xml.Name uses the tag or field name. - { - Value: &NameInField{}, - ExpectXML: `<NameInField><foo xmlns="ns"></foo></NameInField>`, - MarshalOnly: true, - }, - - // Test attributes - { - Value: &AttrTest{ - Int: 8, - Named: 9, - Float: 23.5, - Uint8: 255, - Bool: true, - Str: "str", - Bytes: []byte("byt"), - }, - ExpectXML: `<AttrTest Int="8" int="9" Float="23.5" Uint8="255"` + - ` Bool="true" Str="str" Bytes="byt"></AttrTest>`, - }, - { - Value: &AttrTest{Bytes: []byte{}}, - ExpectXML: `<AttrTest Int="0" int="0" Float="0" Uint8="0"` + - ` Bool="false" Str="" Bytes=""></AttrTest>`, - }, - { - Value: &OmitAttrTest{ - Int: 8, - Named: 9, - Float: 23.5, - Uint8: 255, - Bool: true, - Str: "str", - Bytes: []byte("byt"), - }, - ExpectXML: `<OmitAttrTest Int="8" int="9" Float="23.5" Uint8="255"` + - ` Bool="true" Str="str" Bytes="byt"></OmitAttrTest>`, - }, - { - Value: &OmitAttrTest{}, - ExpectXML: `<OmitAttrTest></OmitAttrTest>`, - }, - - // pointer fields - { - Value: &PointerFieldsTest{Name: &nameAttr, Age: &ageAttr, Contents: &contentsAttr}, - ExpectXML: `<dummy name="Sarah" age="12">lorem ipsum</dummy>`, - MarshalOnly: true, - }, - - // empty chardata pointer field - { - Value: &ChardataEmptyTest{}, - ExpectXML: `<test></test>`, - MarshalOnly: true, - }, - - // omitempty on fields - { - Value: &OmitFieldTest{ - Int: 8, - Named: 9, - Float: 23.5, - Uint8: 255, - Bool: true, - Str: "str", - Bytes: []byte("byt"), - Ptr: &PresenceTest{}, - }, - ExpectXML: `<OmitFieldTest>` + - `<Int>8</Int>` + - `<int>9</int>` + - `<Float>23.5</Float>` + - `<Uint8>255</Uint8>` + - `<Bool>true</Bool>` + - `<Str>str</Str>` + - `<Bytes>byt</Bytes>` + - `<Ptr></Ptr>` + - `</OmitFieldTest>`, - }, - { - Value: &OmitFieldTest{}, - ExpectXML: `<OmitFieldTest></OmitFieldTest>`, - }, - - // Test ",any" - { - ExpectXML: `<a><nested><value>known</value></nested><other><sub>unknown</sub></other></a>`, - Value: &AnyTest{ - Nested: "known", - AnyField: AnyHolder{ - XMLName: Name{Local: "other"}, - XML: "<sub>unknown</sub>", - }, - }, - }, - { - Value: &AnyTest{Nested: "known", - AnyField: AnyHolder{ - XML: "<unknown/>", - XMLName: Name{Local: "AnyField"}, - }, - }, - ExpectXML: `<a><nested><value>known</value></nested><AnyField><unknown/></AnyField></a>`, - }, - { - ExpectXML: `<a><nested><value>b</value></nested></a>`, - Value: &AnyOmitTest{ - Nested: "b", - }, - }, - { - ExpectXML: `<a><nested><value>b</value></nested><c><d>e</d></c><g xmlns="f"><h>i</h></g></a>`, - Value: &AnySliceTest{ - Nested: "b", - AnyField: []AnyHolder{ - { - XMLName: Name{Local: "c"}, - XML: "<d>e</d>", - }, - { - XMLName: Name{Space: "f", Local: "g"}, - XML: "<h>i</h>", - }, - }, - }, - }, - { - ExpectXML: `<a><nested><value>b</value></nested></a>`, - Value: &AnySliceTest{ - Nested: "b", - }, - }, - - // Test recursive types. - { - Value: &RecurseA{ - A: "a1", - B: &RecurseB{ - A: &RecurseA{"a2", nil}, - B: "b1", - }, - }, - ExpectXML: `<RecurseA><A>a1</A><B><A><A>a2</A></A><B>b1</B></B></RecurseA>`, - }, - - // Test ignoring fields via "-" tag - { - ExpectXML: `<IgnoreTest></IgnoreTest>`, - Value: &IgnoreTest{}, - }, - { - ExpectXML: `<IgnoreTest></IgnoreTest>`, - Value: &IgnoreTest{PublicSecret: "can't tell"}, - MarshalOnly: true, - }, - { - ExpectXML: `<IgnoreTest><PublicSecret>ignore me</PublicSecret></IgnoreTest>`, - Value: &IgnoreTest{}, - UnmarshalOnly: true, - }, - - // Test escaping. - { - ExpectXML: `<a><nested><value>dquote: "; squote: '; ampersand: &; less: <; greater: >;</value></nested><empty></empty></a>`, - Value: &AnyTest{ - Nested: `dquote: "; squote: '; ampersand: &; less: <; greater: >;`, - AnyField: AnyHolder{XMLName: Name{Local: "empty"}}, - }, - }, - { - ExpectXML: `<a><nested><value>newline: 
; cr: 
; tab: 	;</value></nested><AnyField></AnyField></a>`, - Value: &AnyTest{ - Nested: "newline: \n; cr: \r; tab: \t;", - AnyField: AnyHolder{XMLName: Name{Local: "AnyField"}}, - }, - }, - { - ExpectXML: "<a><nested><value>1\r2\r\n3\n\r4\n5</value></nested></a>", - Value: &AnyTest{ - Nested: "1\n2\n3\n\n4\n5", - }, - UnmarshalOnly: true, - }, - { - ExpectXML: `<EmbedInt><MyInt>42</MyInt></EmbedInt>`, - Value: &EmbedInt{ - MyInt: 42, - }, - }, - // Test omitempty with parent chain; see golang.org/issue/4168. - { - ExpectXML: `<Strings><A></A></Strings>`, - Value: &Strings{}, - }, - // Custom marshalers. - { - ExpectXML: `<MyMarshalerTest>hello world</MyMarshalerTest>`, - Value: &MyMarshalerTest{}, - }, - { - ExpectXML: `<MarshalerStruct Foo="hello world"></MarshalerStruct>`, - Value: &MarshalerStruct{}, - }, - { - ExpectXML: `<MarshalerValueStruct Foo="hello world"></MarshalerValueStruct>`, - Value: &MarshalerValueStruct{}, - }, - { - ExpectXML: `<outer xmlns="testns" int="10"></outer>`, - Value: &OuterStruct{IntAttr: 10}, - }, - { - ExpectXML: `<test xmlns="outerns" int="10"></test>`, - Value: &OuterNamedStruct{XMLName: Name{Space: "outerns", Local: "test"}, IntAttr: 10}, - }, - { - ExpectXML: `<test xmlns="outerns" int="10"></test>`, - Value: &OuterNamedOrderedStruct{XMLName: Name{Space: "outerns", Local: "test"}, IntAttr: 10}, - }, - { - ExpectXML: `<outer xmlns="testns" int="10"></outer>`, - Value: &OuterOuterStruct{OuterStruct{IntAttr: 10}}, - }, - { - ExpectXML: `<NestedAndChardata><A><B></B><B></B></A>test</NestedAndChardata>`, - Value: &NestedAndChardata{AB: make([]string, 2), Chardata: "test"}, - }, - { - ExpectXML: `<NestedAndComment><A><B></B><B></B></A><!--test--></NestedAndComment>`, - Value: &NestedAndComment{AB: make([]string, 2), Comment: "test"}, - }, - { - ExpectXML: `<XMLNSFieldStruct xmlns="http://example.com/ns"><Body>hello world</Body></XMLNSFieldStruct>`, - Value: &XMLNSFieldStruct{Ns: "http://example.com/ns", Body: "hello world"}, - }, - { - ExpectXML: `<testns:test xmlns:testns="testns" xmlns="http://example.com/ns"><Body>hello world</Body></testns:test>`, - Value: &NamedXMLNSFieldStruct{Ns: "http://example.com/ns", Body: "hello world"}, - }, - { - ExpectXML: `<testns:test xmlns:testns="testns"><Body>hello world</Body></testns:test>`, - Value: &NamedXMLNSFieldStruct{Ns: "", Body: "hello world"}, - }, - { - ExpectXML: `<XMLNSFieldStructWithOmitEmpty><Body>hello world</Body></XMLNSFieldStructWithOmitEmpty>`, - Value: &XMLNSFieldStructWithOmitEmpty{Body: "hello world"}, - }, - { - // The xmlns attribute must be ignored because the <test> - // element is in the empty namespace, so it's not possible - // to set the default namespace to something non-empty. - ExpectXML: `<test><Body>hello world</Body></test>`, - Value: &NamedXMLNSFieldStructWithEmptyNamespace{Ns: "foo", Body: "hello world"}, - MarshalOnly: true, - }, - { - ExpectXML: `<RecursiveXMLNSFieldStruct xmlns="foo"><Body xmlns=""><Text>hello world</Text></Body></RecursiveXMLNSFieldStruct>`, - Value: &RecursiveXMLNSFieldStruct{ - Ns: "foo", - Body: &RecursiveXMLNSFieldStruct{ - Text: "hello world", - }, - }, - }, -} - -func TestMarshal(t *testing.T) { - for idx, test := range marshalTests { - if test.UnmarshalOnly { - continue - } - data, err := Marshal(test.Value) - if err != nil { - t.Errorf("#%d: marshal(%#v): %s", idx, test.Value, err) - continue - } - if got, want := string(data), test.ExpectXML; got != want { - if strings.Contains(want, "\n") { - t.Errorf("#%d: marshal(%#v):\nHAVE:\n%s\nWANT:\n%s", idx, test.Value, got, want) - } else { - t.Errorf("#%d: marshal(%#v):\nhave %#q\nwant %#q", idx, test.Value, got, want) - } - } - } -} - -type AttrParent struct { - X string `xml:"X>Y,attr"` -} - -type BadAttr struct { - Name []string `xml:"name,attr"` -} - -var marshalErrorTests = []struct { - Value interface{} - Err string - Kind reflect.Kind -}{ - { - Value: make(chan bool), - Err: "xml: unsupported type: chan bool", - Kind: reflect.Chan, - }, - { - Value: map[string]string{ - "question": "What do you get when you multiply six by nine?", - "answer": "42", - }, - Err: "xml: unsupported type: map[string]string", - Kind: reflect.Map, - }, - { - Value: map[*Ship]bool{nil: false}, - Err: "xml: unsupported type: map[*xml.Ship]bool", - Kind: reflect.Map, - }, - { - Value: &Domain{Comment: []byte("f--bar")}, - Err: `xml: comments must not contain "--"`, - }, - // Reject parent chain with attr, never worked; see golang.org/issue/5033. - { - Value: &AttrParent{}, - Err: `xml: X>Y chain not valid with attr flag`, - }, - { - Value: BadAttr{[]string{"X", "Y"}}, - Err: `xml: unsupported type: []string`, - }, -} - -var marshalIndentTests = []struct { - Value interface{} - Prefix string - Indent string - ExpectXML string -}{ - { - Value: &SecretAgent{ - Handle: "007", - Identity: "James Bond", - Obfuscate: "<redacted/>", - }, - Prefix: "", - Indent: "\t", - ExpectXML: fmt.Sprintf("<agent handle=\"007\">\n\t<Identity>James Bond</Identity><redacted/>\n</agent>"), - }, -} - -func TestMarshalErrors(t *testing.T) { - for idx, test := range marshalErrorTests { - data, err := Marshal(test.Value) - if err == nil { - t.Errorf("#%d: marshal(%#v) = [success] %q, want error %v", idx, test.Value, data, test.Err) - continue - } - if err.Error() != test.Err { - t.Errorf("#%d: marshal(%#v) = [error] %v, want %v", idx, test.Value, err, test.Err) - } - if test.Kind != reflect.Invalid { - if kind := err.(*UnsupportedTypeError).Type.Kind(); kind != test.Kind { - t.Errorf("#%d: marshal(%#v) = [error kind] %s, want %s", idx, test.Value, kind, test.Kind) - } - } - } -} - -// Do invertibility testing on the various structures that we test -func TestUnmarshal(t *testing.T) { - for i, test := range marshalTests { - if test.MarshalOnly { - continue - } - if _, ok := test.Value.(*Plain); ok { - continue - } - vt := reflect.TypeOf(test.Value) - dest := reflect.New(vt.Elem()).Interface() - err := Unmarshal([]byte(test.ExpectXML), dest) - - switch fix := dest.(type) { - case *Feed: - fix.Author.InnerXML = "" - for i := range fix.Entry { - fix.Entry[i].Author.InnerXML = "" - } - } - - if err != nil { - t.Errorf("#%d: unexpected error: %#v", i, err) - } else if got, want := dest, test.Value; !reflect.DeepEqual(got, want) { - t.Errorf("#%d: unmarshal(%q):\nhave %#v\nwant %#v", i, test.ExpectXML, got, want) - } - } -} - -func TestMarshalIndent(t *testing.T) { - for i, test := range marshalIndentTests { - data, err := MarshalIndent(test.Value, test.Prefix, test.Indent) - if err != nil { - t.Errorf("#%d: Error: %s", i, err) - continue - } - if got, want := string(data), test.ExpectXML; got != want { - t.Errorf("#%d: MarshalIndent:\nGot:%s\nWant:\n%s", i, got, want) - } - } -} - -type limitedBytesWriter struct { - w io.Writer - remain int // until writes fail -} - -func (lw *limitedBytesWriter) Write(p []byte) (n int, err error) { - if lw.remain <= 0 { - println("error") - return 0, errors.New("write limit hit") - } - if len(p) > lw.remain { - p = p[:lw.remain] - n, _ = lw.w.Write(p) - lw.remain = 0 - return n, errors.New("write limit hit") - } - n, err = lw.w.Write(p) - lw.remain -= n - return n, err -} - -func TestMarshalWriteErrors(t *testing.T) { - var buf bytes.Buffer - const writeCap = 1024 - w := &limitedBytesWriter{&buf, writeCap} - enc := NewEncoder(w) - var err error - var i int - const n = 4000 - for i = 1; i <= n; i++ { - err = enc.Encode(&Passenger{ - Name: []string{"Alice", "Bob"}, - Weight: 5, - }) - if err != nil { - break - } - } - if err == nil { - t.Error("expected an error") - } - if i == n { - t.Errorf("expected to fail before the end") - } - if buf.Len() != writeCap { - t.Errorf("buf.Len() = %d; want %d", buf.Len(), writeCap) - } -} - -func TestMarshalWriteIOErrors(t *testing.T) { - enc := NewEncoder(errWriter{}) - - expectErr := "unwritable" - err := enc.Encode(&Passenger{}) - if err == nil || err.Error() != expectErr { - t.Errorf("EscapeTest = [error] %v, want %v", err, expectErr) - } -} - -func TestMarshalFlush(t *testing.T) { - var buf bytes.Buffer - enc := NewEncoder(&buf) - if err := enc.EncodeToken(CharData("hello world")); err != nil { - t.Fatalf("enc.EncodeToken: %v", err) - } - if buf.Len() > 0 { - t.Fatalf("enc.EncodeToken caused actual write: %q", buf.Bytes()) - } - if err := enc.Flush(); err != nil { - t.Fatalf("enc.Flush: %v", err) - } - if buf.String() != "hello world" { - t.Fatalf("after enc.Flush, buf.String() = %q, want %q", buf.String(), "hello world") - } -} - -var encodeElementTests = []struct { - desc string - value interface{} - start StartElement - expectXML string -}{{ - desc: "simple string", - value: "hello", - start: StartElement{ - Name: Name{Local: "a"}, - }, - expectXML: `<a>hello</a>`, -}, { - desc: "string with added attributes", - value: "hello", - start: StartElement{ - Name: Name{Local: "a"}, - Attr: []Attr{{ - Name: Name{Local: "x"}, - Value: "y", - }, { - Name: Name{Local: "foo"}, - Value: "bar", - }}, - }, - expectXML: `<a x="y" foo="bar">hello</a>`, -}, { - desc: "start element with default name space", - value: struct { - Foo XMLNameWithNSTag - }{ - Foo: XMLNameWithNSTag{ - Value: "hello", - }, - }, - start: StartElement{ - Name: Name{Space: "ns", Local: "a"}, - Attr: []Attr{{ - Name: Name{Local: "xmlns"}, - // "ns" is the name space defined in XMLNameWithNSTag - Value: "ns", - }}, - }, - expectXML: `<a xmlns="ns"><InXMLNameWithNSTag>hello</InXMLNameWithNSTag></a>`, -}, { - desc: "start element in name space with different default name space", - value: struct { - Foo XMLNameWithNSTag - }{ - Foo: XMLNameWithNSTag{ - Value: "hello", - }, - }, - start: StartElement{ - Name: Name{Space: "ns2", Local: "a"}, - Attr: []Attr{{ - Name: Name{Local: "xmlns"}, - // "ns" is the name space defined in XMLNameWithNSTag - Value: "ns", - }}, - }, - expectXML: `<ns2:a xmlns:ns2="ns2" xmlns="ns"><InXMLNameWithNSTag>hello</InXMLNameWithNSTag></ns2:a>`, -}, { - desc: "XMLMarshaler with start element with default name space", - value: &MyMarshalerTest{}, - start: StartElement{ - Name: Name{Space: "ns2", Local: "a"}, - Attr: []Attr{{ - Name: Name{Local: "xmlns"}, - // "ns" is the name space defined in XMLNameWithNSTag - Value: "ns", - }}, - }, - expectXML: `<ns2:a xmlns:ns2="ns2" xmlns="ns">hello world</ns2:a>`, -}} - -func TestEncodeElement(t *testing.T) { - for idx, test := range encodeElementTests { - var buf bytes.Buffer - enc := NewEncoder(&buf) - err := enc.EncodeElement(test.value, test.start) - if err != nil { - t.Fatalf("enc.EncodeElement: %v", err) - } - err = enc.Flush() - if err != nil { - t.Fatalf("enc.Flush: %v", err) - } - if got, want := buf.String(), test.expectXML; got != want { - t.Errorf("#%d(%s): EncodeElement(%#v, %#v):\nhave %#q\nwant %#q", idx, test.desc, test.value, test.start, got, want) - } - } -} - -func BenchmarkMarshal(b *testing.B) { - b.ReportAllocs() - for i := 0; i < b.N; i++ { - Marshal(atomValue) - } -} - -func BenchmarkUnmarshal(b *testing.B) { - b.ReportAllocs() - xml := []byte(atomXml) - for i := 0; i < b.N; i++ { - Unmarshal(xml, &Feed{}) - } -} - -// golang.org/issue/6556 -func TestStructPointerMarshal(t *testing.T) { - type A struct { - XMLName string `xml:"a"` - B []interface{} - } - type C struct { - XMLName Name - Value string `xml:"value"` - } - - a := new(A) - a.B = append(a.B, &C{ - XMLName: Name{Local: "c"}, - Value: "x", - }) - - b, err := Marshal(a) - if err != nil { - t.Fatal(err) - } - if x := string(b); x != "<a><c><value>x</value></c></a>" { - t.Fatal(x) - } - var v A - err = Unmarshal(b, &v) - if err != nil { - t.Fatal(err) - } -} - -var encodeTokenTests = []struct { - desc string - toks []Token - want string - err string -}{{ - desc: "start element with name space", - toks: []Token{ - StartElement{Name{"space", "local"}, nil}, - }, - want: `<space:local xmlns:space="space">`, -}, { - desc: "start element with no name", - toks: []Token{ - StartElement{Name{"space", ""}, nil}, - }, - err: "xml: start tag with no name", -}, { - desc: "end element with no name", - toks: []Token{ - EndElement{Name{"space", ""}}, - }, - err: "xml: end tag with no name", -}, { - desc: "char data", - toks: []Token{ - CharData("foo"), - }, - want: `foo`, -}, { - desc: "char data with escaped chars", - toks: []Token{ - CharData(" \t\n"), - }, - want: " 	\n", -}, { - desc: "comment", - toks: []Token{ - Comment("foo"), - }, - want: `<!--foo-->`, -}, { - desc: "comment with invalid content", - toks: []Token{ - Comment("foo-->"), - }, - err: "xml: EncodeToken of Comment containing --> marker", -}, { - desc: "proc instruction", - toks: []Token{ - ProcInst{"Target", []byte("Instruction")}, - }, - want: `<?Target Instruction?>`, -}, { - desc: "proc instruction with empty target", - toks: []Token{ - ProcInst{"", []byte("Instruction")}, - }, - err: "xml: EncodeToken of ProcInst with invalid Target", -}, { - desc: "proc instruction with bad content", - toks: []Token{ - ProcInst{"", []byte("Instruction?>")}, - }, - err: "xml: EncodeToken of ProcInst with invalid Target", -}, { - desc: "directive", - toks: []Token{ - Directive("foo"), - }, - want: `<!foo>`, -}, { - desc: "more complex directive", - toks: []Token{ - Directive("DOCTYPE doc [ <!ELEMENT doc '>'> <!-- com>ment --> ]"), - }, - want: `<!DOCTYPE doc [ <!ELEMENT doc '>'> <!-- com>ment --> ]>`, -}, { - desc: "directive instruction with bad name", - toks: []Token{ - Directive("foo>"), - }, - err: "xml: EncodeToken of Directive containing wrong < or > markers", -}, { - desc: "end tag without start tag", - toks: []Token{ - EndElement{Name{"foo", "bar"}}, - }, - err: "xml: end tag </bar> without start tag", -}, { - desc: "mismatching end tag local name", - toks: []Token{ - StartElement{Name{"", "foo"}, nil}, - EndElement{Name{"", "bar"}}, - }, - err: "xml: end tag </bar> does not match start tag <foo>", - want: `<foo>`, -}, { - desc: "mismatching end tag namespace", - toks: []Token{ - StartElement{Name{"space", "foo"}, nil}, - EndElement{Name{"another", "foo"}}, - }, - err: "xml: end tag </foo> in namespace another does not match start tag <foo> in namespace space", - want: `<space:foo xmlns:space="space">`, -}, { - desc: "start element with explicit namespace", - toks: []Token{ - StartElement{Name{"space", "local"}, []Attr{ - {Name{"xmlns", "x"}, "space"}, - {Name{"space", "foo"}, "value"}, - }}, - }, - want: `<x:local xmlns:x="space" x:foo="value">`, -}, { - desc: "start element with explicit namespace and colliding prefix", - toks: []Token{ - StartElement{Name{"space", "local"}, []Attr{ - {Name{"xmlns", "x"}, "space"}, - {Name{"space", "foo"}, "value"}, - {Name{"x", "bar"}, "other"}, - }}, - }, - want: `<x:local xmlns:x_1="x" xmlns:x="space" x:foo="value" x_1:bar="other">`, -}, { - desc: "start element using previously defined namespace", - toks: []Token{ - StartElement{Name{"", "local"}, []Attr{ - {Name{"xmlns", "x"}, "space"}, - }}, - StartElement{Name{"space", "foo"}, []Attr{ - {Name{"space", "x"}, "y"}, - }}, - }, - want: `<local xmlns:x="space"><x:foo x:x="y">`, -}, { - desc: "nested name space with same prefix", - toks: []Token{ - StartElement{Name{"", "foo"}, []Attr{ - {Name{"xmlns", "x"}, "space1"}, - }}, - StartElement{Name{"", "foo"}, []Attr{ - {Name{"xmlns", "x"}, "space2"}, - }}, - StartElement{Name{"", "foo"}, []Attr{ - {Name{"space1", "a"}, "space1 value"}, - {Name{"space2", "b"}, "space2 value"}, - }}, - EndElement{Name{"", "foo"}}, - EndElement{Name{"", "foo"}}, - StartElement{Name{"", "foo"}, []Attr{ - {Name{"space1", "a"}, "space1 value"}, - {Name{"space2", "b"}, "space2 value"}, - }}, - }, - want: `<foo xmlns:x="space1"><foo xmlns:x="space2"><foo xmlns:space1="space1" space1:a="space1 value" x:b="space2 value"></foo></foo><foo xmlns:space2="space2" x:a="space1 value" space2:b="space2 value">`, -}, { - desc: "start element defining several prefixes for the same name space", - toks: []Token{ - StartElement{Name{"space", "foo"}, []Attr{ - {Name{"xmlns", "a"}, "space"}, - {Name{"xmlns", "b"}, "space"}, - {Name{"space", "x"}, "value"}, - }}, - }, - want: `<a:foo xmlns:a="space" a:x="value">`, -}, { - desc: "nested element redefines name space", - toks: []Token{ - StartElement{Name{"", "foo"}, []Attr{ - {Name{"xmlns", "x"}, "space"}, - }}, - StartElement{Name{"space", "foo"}, []Attr{ - {Name{"xmlns", "y"}, "space"}, - {Name{"space", "a"}, "value"}, - }}, - }, - want: `<foo xmlns:x="space"><x:foo x:a="value">`, -}, { - desc: "nested element creates alias for default name space", - toks: []Token{ - StartElement{Name{"space", "foo"}, []Attr{ - {Name{"", "xmlns"}, "space"}, - }}, - StartElement{Name{"space", "foo"}, []Attr{ - {Name{"xmlns", "y"}, "space"}, - {Name{"space", "a"}, "value"}, - }}, - }, - want: `<foo xmlns="space"><foo xmlns:y="space" y:a="value">`, -}, { - desc: "nested element defines default name space with existing prefix", - toks: []Token{ - StartElement{Name{"", "foo"}, []Attr{ - {Name{"xmlns", "x"}, "space"}, - }}, - StartElement{Name{"space", "foo"}, []Attr{ - {Name{"", "xmlns"}, "space"}, - {Name{"space", "a"}, "value"}, - }}, - }, - want: `<foo xmlns:x="space"><foo xmlns="space" x:a="value">`, -}, { - desc: "nested element uses empty attribute name space when default ns defined", - toks: []Token{ - StartElement{Name{"space", "foo"}, []Attr{ - {Name{"", "xmlns"}, "space"}, - }}, - StartElement{Name{"space", "foo"}, []Attr{ - {Name{"", "attr"}, "value"}, - }}, - }, - want: `<foo xmlns="space"><foo attr="value">`, -}, { - desc: "redefine xmlns", - toks: []Token{ - StartElement{Name{"", "foo"}, []Attr{ - {Name{"foo", "xmlns"}, "space"}, - }}, - }, - err: `xml: cannot redefine xmlns attribute prefix`, -}, { - desc: "xmlns with explicit name space #1", - toks: []Token{ - StartElement{Name{"space", "foo"}, []Attr{ - {Name{"xml", "xmlns"}, "space"}, - }}, - }, - want: `<foo xmlns="space">`, -}, { - desc: "xmlns with explicit name space #2", - toks: []Token{ - StartElement{Name{"space", "foo"}, []Attr{ - {Name{xmlURL, "xmlns"}, "space"}, - }}, - }, - want: `<foo xmlns="space">`, -}, { - desc: "empty name space declaration is ignored", - toks: []Token{ - StartElement{Name{"", "foo"}, []Attr{ - {Name{"xmlns", "foo"}, ""}, - }}, - }, - want: `<foo>`, -}, { - desc: "attribute with no name is ignored", - toks: []Token{ - StartElement{Name{"", "foo"}, []Attr{ - {Name{"", ""}, "value"}, - }}, - }, - want: `<foo>`, -}, { - desc: "namespace URL with non-valid name", - toks: []Token{ - StartElement{Name{"/34", "foo"}, []Attr{ - {Name{"/34", "x"}, "value"}, - }}, - }, - want: `<_:foo xmlns:_="/34" _:x="value">`, -}, { - desc: "nested element resets default namespace to empty", - toks: []Token{ - StartElement{Name{"space", "foo"}, []Attr{ - {Name{"", "xmlns"}, "space"}, - }}, - StartElement{Name{"", "foo"}, []Attr{ - {Name{"", "xmlns"}, ""}, - {Name{"", "x"}, "value"}, - {Name{"space", "x"}, "value"}, - }}, - }, - want: `<foo xmlns="space"><foo xmlns:space="space" xmlns="" x="value" space:x="value">`, -}, { - desc: "nested element requires empty default name space", - toks: []Token{ - StartElement{Name{"space", "foo"}, []Attr{ - {Name{"", "xmlns"}, "space"}, - }}, - StartElement{Name{"", "foo"}, nil}, - }, - want: `<foo xmlns="space"><foo xmlns="">`, -}, { - desc: "attribute uses name space from xmlns", - toks: []Token{ - StartElement{Name{"some/space", "foo"}, []Attr{ - {Name{"", "attr"}, "value"}, - {Name{"some/space", "other"}, "other value"}, - }}, - }, - want: `<space:foo xmlns:space="some/space" attr="value" space:other="other value">`, -}, { - desc: "default name space should not be used by attributes", - toks: []Token{ - StartElement{Name{"space", "foo"}, []Attr{ - {Name{"", "xmlns"}, "space"}, - {Name{"xmlns", "bar"}, "space"}, - {Name{"space", "baz"}, "foo"}, - }}, - StartElement{Name{"space", "baz"}, nil}, - EndElement{Name{"space", "baz"}}, - EndElement{Name{"space", "foo"}}, - }, - want: `<foo xmlns:bar="space" xmlns="space" bar:baz="foo"><baz></baz></foo>`, -}, { - desc: "default name space not used by attributes, not explicitly defined", - toks: []Token{ - StartElement{Name{"space", "foo"}, []Attr{ - {Name{"", "xmlns"}, "space"}, - {Name{"space", "baz"}, "foo"}, - }}, - StartElement{Name{"space", "baz"}, nil}, - EndElement{Name{"space", "baz"}}, - EndElement{Name{"space", "foo"}}, - }, - want: `<foo xmlns:space="space" xmlns="space" space:baz="foo"><baz></baz></foo>`, -}, { - desc: "impossible xmlns declaration", - toks: []Token{ - StartElement{Name{"", "foo"}, []Attr{ - {Name{"", "xmlns"}, "space"}, - }}, - StartElement{Name{"space", "bar"}, []Attr{ - {Name{"space", "attr"}, "value"}, - }}, - }, - want: `<foo><space:bar xmlns:space="space" space:attr="value">`, -}} - -func TestEncodeToken(t *testing.T) { -loop: - for i, tt := range encodeTokenTests { - var buf bytes.Buffer - enc := NewEncoder(&buf) - var err error - for j, tok := range tt.toks { - err = enc.EncodeToken(tok) - if err != nil && j < len(tt.toks)-1 { - t.Errorf("#%d %s token #%d: %v", i, tt.desc, j, err) - continue loop - } - } - errorf := func(f string, a ...interface{}) { - t.Errorf("#%d %s token #%d:%s", i, tt.desc, len(tt.toks)-1, fmt.Sprintf(f, a...)) - } - switch { - case tt.err != "" && err == nil: - errorf(" expected error; got none") - continue - case tt.err == "" && err != nil: - errorf(" got error: %v", err) - continue - case tt.err != "" && err != nil && tt.err != err.Error(): - errorf(" error mismatch; got %v, want %v", err, tt.err) - continue - } - if err := enc.Flush(); err != nil { - errorf(" %v", err) - continue - } - if got := buf.String(); got != tt.want { - errorf("\ngot %v\nwant %v", got, tt.want) - continue - } - } -} - -func TestProcInstEncodeToken(t *testing.T) { - var buf bytes.Buffer - enc := NewEncoder(&buf) - - if err := enc.EncodeToken(ProcInst{"xml", []byte("Instruction")}); err != nil { - t.Fatalf("enc.EncodeToken: expected to be able to encode xml target ProcInst as first token, %s", err) - } - - if err := enc.EncodeToken(ProcInst{"Target", []byte("Instruction")}); err != nil { - t.Fatalf("enc.EncodeToken: expected to be able to add non-xml target ProcInst") - } - - if err := enc.EncodeToken(ProcInst{"xml", []byte("Instruction")}); err == nil { - t.Fatalf("enc.EncodeToken: expected to not be allowed to encode xml target ProcInst when not first token") - } -} - -func TestDecodeEncode(t *testing.T) { - var in, out bytes.Buffer - in.WriteString(`<?xml version="1.0" encoding="UTF-8"?> -<?Target Instruction?> -<root> -</root> -`) - dec := NewDecoder(&in) - enc := NewEncoder(&out) - for tok, err := dec.Token(); err == nil; tok, err = dec.Token() { - err = enc.EncodeToken(tok) - if err != nil { - t.Fatalf("enc.EncodeToken: Unable to encode token (%#v), %v", tok, err) - } - } -} - -// Issue 9796. Used to fail with GORACE="halt_on_error=1" -race. -func TestRace9796(t *testing.T) { - type A struct{} - type B struct { - C []A `xml:"X>Y"` - } - var wg sync.WaitGroup - for i := 0; i < 2; i++ { - wg.Add(1) - go func() { - Marshal(B{[]A{{}}}) - wg.Done() - }() - } - wg.Wait() -} - -func TestIsValidDirective(t *testing.T) { - testOK := []string{ - "<>", - "< < > >", - "<!DOCTYPE '<' '>' '>' <!--nothing-->>", - "<!DOCTYPE doc [ <!ELEMENT doc ANY> <!ELEMENT doc ANY> ]>", - "<!DOCTYPE doc [ <!ELEMENT doc \"ANY> '<' <!E\" LEMENT '>' doc ANY> ]>", - "<!DOCTYPE doc <!-- just>>>> a < comment --> [ <!ITEM anything> ] >", - } - testKO := []string{ - "<", - ">", - "<!--", - "-->", - "< > > < < >", - "<!dummy <!-- > -->", - "<!DOCTYPE doc '>", - "<!DOCTYPE doc '>'", - "<!DOCTYPE doc <!--comment>", - } - for _, s := range testOK { - if !isValidDirective(Directive(s)) { - t.Errorf("Directive %q is expected to be valid", s) - } - } - for _, s := range testKO { - if isValidDirective(Directive(s)) { - t.Errorf("Directive %q is expected to be invalid", s) - } - } -} - -// Issue 11719. EncodeToken used to silently eat tokens with an invalid type. -func TestSimpleUseOfEncodeToken(t *testing.T) { - var buf bytes.Buffer - enc := NewEncoder(&buf) - if err := enc.EncodeToken(&StartElement{Name: Name{"", "object1"}}); err == nil { - t.Errorf("enc.EncodeToken: pointer type should be rejected") - } - if err := enc.EncodeToken(&EndElement{Name: Name{"", "object1"}}); err == nil { - t.Errorf("enc.EncodeToken: pointer type should be rejected") - } - if err := enc.EncodeToken(StartElement{Name: Name{"", "object2"}}); err != nil { - t.Errorf("enc.EncodeToken: StartElement %s", err) - } - if err := enc.EncodeToken(EndElement{Name: Name{"", "object2"}}); err != nil { - t.Errorf("enc.EncodeToken: EndElement %s", err) - } - if err := enc.EncodeToken(Universe{}); err == nil { - t.Errorf("enc.EncodeToken: invalid type not caught") - } - if err := enc.Flush(); err != nil { - t.Errorf("enc.Flush: %s", err) - } - if buf.Len() == 0 { - t.Errorf("enc.EncodeToken: empty buffer") - } - want := "<object2></object2>" - if buf.String() != want { - t.Errorf("enc.EncodeToken: expected %q; got %q", want, buf.String()) - } -} diff --git a/vendor/golang.org/x/net/webdav/internal/xml/read.go b/vendor/golang.org/x/net/webdav/internal/xml/read.go deleted file mode 100644 index 4089056a1..000000000 --- a/vendor/golang.org/x/net/webdav/internal/xml/read.go +++ /dev/null @@ -1,692 +0,0 @@ -// Copyright 2009 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 - -import ( - "bytes" - "encoding" - "errors" - "fmt" - "reflect" - "strconv" - "strings" -) - -// BUG(rsc): Mapping between XML elements and data structures is inherently flawed: -// an XML element is an order-dependent collection of anonymous -// values, while a data structure is an order-independent collection -// of named values. -// See package json for a textual representation more suitable -// to data structures. - -// Unmarshal parses the XML-encoded data and stores the result in -// the value pointed to by v, which must be an arbitrary struct, -// slice, or string. Well-formed data that does not fit into v is -// discarded. -// -// Because Unmarshal uses the reflect package, it can only assign -// to exported (upper case) fields. Unmarshal uses a case-sensitive -// comparison to match XML element names to tag values and struct -// field names. -// -// Unmarshal maps an XML element to a struct using the following rules. -// In the rules, the tag of a field refers to the value associated with the -// key 'xml' in the struct field's tag (see the example above). -// -// * If the struct has a field of type []byte or string with tag -// ",innerxml", Unmarshal accumulates the raw XML nested inside the -// element in that field. The rest of the rules still apply. -// -// * If the struct has a field named XMLName of type xml.Name, -// Unmarshal records the element name in that field. -// -// * If the XMLName field has an associated tag of the form -// "name" or "namespace-URL name", the XML element must have -// the given name (and, optionally, name space) or else Unmarshal -// returns an error. -// -// * If the XML element has an attribute whose name matches a -// struct field name with an associated tag containing ",attr" or -// the explicit name in a struct field tag of the form "name,attr", -// Unmarshal records the attribute value in that field. -// -// * If the XML element contains character data, that data is -// accumulated in the first struct field that has tag ",chardata". -// The struct field may have type []byte or string. -// If there is no such field, the character data is discarded. -// -// * If the XML element contains comments, they are accumulated in -// the first struct field that has tag ",comment". The struct -// field may have type []byte or string. If there is no such -// field, the comments are discarded. -// -// * If the XML element contains a sub-element whose name matches -// the prefix of a tag formatted as "a" or "a>b>c", unmarshal -// will descend into the XML structure looking for elements with the -// given names, and will map the innermost elements to that struct -// field. A tag starting with ">" is equivalent to one starting -// with the field name followed by ">". -// -// * If the XML element contains a sub-element whose name matches -// a struct field's XMLName tag and the struct field has no -// explicit name tag as per the previous rule, unmarshal maps -// the sub-element to that struct field. -// -// * If the XML element contains a sub-element whose name matches a -// field without any mode flags (",attr", ",chardata", etc), Unmarshal -// maps the sub-element to that struct field. -// -// * If the XML element contains a sub-element that hasn't matched any -// of the above rules and the struct has a field with tag ",any", -// unmarshal maps the sub-element to that struct field. -// -// * An anonymous struct field is handled as if the fields of its -// value were part of the outer struct. -// -// * A struct field with tag "-" is never unmarshalled into. -// -// Unmarshal maps an XML element to a string or []byte by saving the -// concatenation of that element's character data in the string or -// []byte. The saved []byte is never nil. -// -// Unmarshal maps an attribute value to a string or []byte by saving -// the value in the string or slice. -// -// Unmarshal maps an XML element to a slice by extending the length of -// the slice and mapping the element to the newly created value. -// -// Unmarshal maps an XML element or attribute value to a bool by -// setting it to the boolean value represented by the string. -// -// Unmarshal maps an XML element or attribute value to an integer or -// floating-point field by setting the field to the result of -// interpreting the string value in decimal. There is no check for -// overflow. -// -// Unmarshal maps an XML element to an xml.Name by recording the -// element name. -// -// Unmarshal maps an XML element to a pointer by setting the pointer -// to a freshly allocated value and then mapping the element to that value. -// -func Unmarshal(data []byte, v interface{}) error { - return NewDecoder(bytes.NewReader(data)).Decode(v) -} - -// Decode works like xml.Unmarshal, except it reads the decoder -// stream to find the start element. -func (d *Decoder) Decode(v interface{}) error { - return d.DecodeElement(v, nil) -} - -// DecodeElement works like xml.Unmarshal except that it takes -// a pointer to the start XML element to decode into v. -// It is useful when a client reads some raw XML tokens itself -// but also wants to defer to Unmarshal for some elements. -func (d *Decoder) DecodeElement(v interface{}, start *StartElement) error { - val := reflect.ValueOf(v) - if val.Kind() != reflect.Ptr { - return errors.New("non-pointer passed to Unmarshal") - } - return d.unmarshal(val.Elem(), start) -} - -// An UnmarshalError represents an error in the unmarshalling process. -type UnmarshalError string - -func (e UnmarshalError) Error() string { return string(e) } - -// Unmarshaler is the interface implemented by objects that can unmarshal -// an XML element description of themselves. -// -// UnmarshalXML decodes a single XML element -// beginning with the given start element. -// If it returns an error, the outer call to Unmarshal stops and -// returns that error. -// UnmarshalXML must consume exactly one XML element. -// One common implementation strategy is to unmarshal into -// a separate value with a layout matching the expected XML -// using d.DecodeElement, and then to copy the data from -// that value into the receiver. -// Another common strategy is to use d.Token to process the -// XML object one token at a time. -// UnmarshalXML may not use d.RawToken. -type Unmarshaler interface { - UnmarshalXML(d *Decoder, start StartElement) error -} - -// UnmarshalerAttr is the interface implemented by objects that can unmarshal -// an XML attribute description of themselves. -// -// UnmarshalXMLAttr decodes a single XML attribute. -// If it returns an error, the outer call to Unmarshal stops and -// returns that error. -// UnmarshalXMLAttr is used only for struct fields with the -// "attr" option in the field tag. -type UnmarshalerAttr interface { - UnmarshalXMLAttr(attr Attr) error -} - -// receiverType returns the receiver type to use in an expression like "%s.MethodName". -func receiverType(val interface{}) string { - t := reflect.TypeOf(val) - if t.Name() != "" { - return t.String() - } - return "(" + t.String() + ")" -} - -// unmarshalInterface unmarshals a single XML element into val. -// start is the opening tag of the element. -func (p *Decoder) unmarshalInterface(val Unmarshaler, start *StartElement) error { - // Record that decoder must stop at end tag corresponding to start. - p.pushEOF() - - p.unmarshalDepth++ - err := val.UnmarshalXML(p, *start) - p.unmarshalDepth-- - if err != nil { - p.popEOF() - return err - } - - if !p.popEOF() { - return fmt.Errorf("xml: %s.UnmarshalXML did not consume entire <%s> element", receiverType(val), start.Name.Local) - } - - return nil -} - -// unmarshalTextInterface unmarshals a single XML element into val. -// The chardata contained in the element (but not its children) -// is passed to the text unmarshaler. -func (p *Decoder) unmarshalTextInterface(val encoding.TextUnmarshaler, start *StartElement) error { - var buf []byte - depth := 1 - for depth > 0 { - t, err := p.Token() - if err != nil { - return err - } - switch t := t.(type) { - case CharData: - if depth == 1 { - buf = append(buf, t...) - } - case StartElement: - depth++ - case EndElement: - depth-- - } - } - return val.UnmarshalText(buf) -} - -// unmarshalAttr unmarshals a single XML attribute into val. -func (p *Decoder) unmarshalAttr(val reflect.Value, attr Attr) error { - if val.Kind() == reflect.Ptr { - if val.IsNil() { - val.Set(reflect.New(val.Type().Elem())) - } - val = val.Elem() - } - - if val.CanInterface() && val.Type().Implements(unmarshalerAttrType) { - // This is an unmarshaler with a non-pointer receiver, - // so it's likely to be incorrect, but we do what we're told. - return val.Interface().(UnmarshalerAttr).UnmarshalXMLAttr(attr) - } - if val.CanAddr() { - pv := val.Addr() - if pv.CanInterface() && pv.Type().Implements(unmarshalerAttrType) { - return pv.Interface().(UnmarshalerAttr).UnmarshalXMLAttr(attr) - } - } - - // Not an UnmarshalerAttr; try encoding.TextUnmarshaler. - if val.CanInterface() && val.Type().Implements(textUnmarshalerType) { - // This is an unmarshaler with a non-pointer receiver, - // so it's likely to be incorrect, but we do what we're told. - return val.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(attr.Value)) - } - if val.CanAddr() { - pv := val.Addr() - if pv.CanInterface() && pv.Type().Implements(textUnmarshalerType) { - return pv.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(attr.Value)) - } - } - - copyValue(val, []byte(attr.Value)) - return nil -} - -var ( - unmarshalerType = reflect.TypeOf((*Unmarshaler)(nil)).Elem() - unmarshalerAttrType = reflect.TypeOf((*UnmarshalerAttr)(nil)).Elem() - textUnmarshalerType = reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem() -) - -// Unmarshal a single XML element into val. -func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error { - // Find start element if we need it. - if start == nil { - for { - tok, err := p.Token() - if err != nil { - return err - } - if t, ok := tok.(StartElement); ok { - start = &t - break - } - } - } - - // Load value from interface, but only if the result will be - // usefully addressable. - if val.Kind() == reflect.Interface && !val.IsNil() { - e := val.Elem() - if e.Kind() == reflect.Ptr && !e.IsNil() { - val = e - } - } - - if val.Kind() == reflect.Ptr { - if val.IsNil() { - val.Set(reflect.New(val.Type().Elem())) - } - val = val.Elem() - } - - if val.CanInterface() && val.Type().Implements(unmarshalerType) { - // This is an unmarshaler with a non-pointer receiver, - // so it's likely to be incorrect, but we do what we're told. - return p.unmarshalInterface(val.Interface().(Unmarshaler), start) - } - - if val.CanAddr() { - pv := val.Addr() - if pv.CanInterface() && pv.Type().Implements(unmarshalerType) { - return p.unmarshalInterface(pv.Interface().(Unmarshaler), start) - } - } - - if val.CanInterface() && val.Type().Implements(textUnmarshalerType) { - return p.unmarshalTextInterface(val.Interface().(encoding.TextUnmarshaler), start) - } - - if val.CanAddr() { - pv := val.Addr() - if pv.CanInterface() && pv.Type().Implements(textUnmarshalerType) { - return p.unmarshalTextInterface(pv.Interface().(encoding.TextUnmarshaler), start) - } - } - - var ( - data []byte - saveData reflect.Value - comment []byte - saveComment reflect.Value - saveXML reflect.Value - saveXMLIndex int - saveXMLData []byte - saveAny reflect.Value - sv reflect.Value - tinfo *typeInfo - err error - ) - - switch v := val; v.Kind() { - default: - return errors.New("unknown type " + v.Type().String()) - - case reflect.Interface: - // TODO: For now, simply ignore the field. In the near - // future we may choose to unmarshal the start - // element on it, if not nil. - return p.Skip() - - case reflect.Slice: - typ := v.Type() - if typ.Elem().Kind() == reflect.Uint8 { - // []byte - saveData = v - break - } - - // Slice of element values. - // Grow slice. - n := v.Len() - if n >= v.Cap() { - ncap := 2 * n - if ncap < 4 { - ncap = 4 - } - new := reflect.MakeSlice(typ, n, ncap) - reflect.Copy(new, v) - v.Set(new) - } - v.SetLen(n + 1) - - // Recur to read element into slice. - if err := p.unmarshal(v.Index(n), start); err != nil { - v.SetLen(n) - return err - } - return nil - - case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.String: - saveData = v - - case reflect.Struct: - typ := v.Type() - if typ == nameType { - v.Set(reflect.ValueOf(start.Name)) - break - } - - sv = v - tinfo, err = getTypeInfo(typ) - if err != nil { - return err - } - - // Validate and assign element name. - if tinfo.xmlname != nil { - finfo := tinfo.xmlname - if finfo.name != "" && finfo.name != start.Name.Local { - return UnmarshalError("expected element type <" + finfo.name + "> but have <" + start.Name.Local + ">") - } - if finfo.xmlns != "" && finfo.xmlns != start.Name.Space { - e := "expected element <" + finfo.name + "> in name space " + finfo.xmlns + " but have " - if start.Name.Space == "" { - e += "no name space" - } else { - e += start.Name.Space - } - return UnmarshalError(e) - } - fv := finfo.value(sv) - if _, ok := fv.Interface().(Name); ok { - fv.Set(reflect.ValueOf(start.Name)) - } - } - - // Assign attributes. - // Also, determine whether we need to save character data or comments. - for i := range tinfo.fields { - finfo := &tinfo.fields[i] - switch finfo.flags & fMode { - case fAttr: - strv := finfo.value(sv) - // Look for attribute. - for _, a := range start.Attr { - if a.Name.Local == finfo.name && (finfo.xmlns == "" || finfo.xmlns == a.Name.Space) { - if err := p.unmarshalAttr(strv, a); err != nil { - return err - } - break - } - } - - case fCharData: - if !saveData.IsValid() { - saveData = finfo.value(sv) - } - - case fComment: - if !saveComment.IsValid() { - saveComment = finfo.value(sv) - } - - case fAny, fAny | fElement: - if !saveAny.IsValid() { - saveAny = finfo.value(sv) - } - - case fInnerXml: - if !saveXML.IsValid() { - saveXML = finfo.value(sv) - if p.saved == nil { - saveXMLIndex = 0 - p.saved = new(bytes.Buffer) - } else { - saveXMLIndex = p.savedOffset() - } - } - } - } - } - - // Find end element. - // Process sub-elements along the way. -Loop: - for { - var savedOffset int - if saveXML.IsValid() { - savedOffset = p.savedOffset() - } - tok, err := p.Token() - if err != nil { - return err - } - switch t := tok.(type) { - case StartElement: - consumed := false - if sv.IsValid() { - consumed, err = p.unmarshalPath(tinfo, sv, nil, &t) - if err != nil { - return err - } - if !consumed && saveAny.IsValid() { - consumed = true - if err := p.unmarshal(saveAny, &t); err != nil { - return err - } - } - } - if !consumed { - if err := p.Skip(); err != nil { - return err - } - } - - case EndElement: - if saveXML.IsValid() { - saveXMLData = p.saved.Bytes()[saveXMLIndex:savedOffset] - if saveXMLIndex == 0 { - p.saved = nil - } - } - break Loop - - case CharData: - if saveData.IsValid() { - data = append(data, t...) - } - - case Comment: - if saveComment.IsValid() { - comment = append(comment, t...) - } - } - } - - if saveData.IsValid() && saveData.CanInterface() && saveData.Type().Implements(textUnmarshalerType) { - if err := saveData.Interface().(encoding.TextUnmarshaler).UnmarshalText(data); err != nil { - return err - } - saveData = reflect.Value{} - } - - if saveData.IsValid() && saveData.CanAddr() { - pv := saveData.Addr() - if pv.CanInterface() && pv.Type().Implements(textUnmarshalerType) { - if err := pv.Interface().(encoding.TextUnmarshaler).UnmarshalText(data); err != nil { - return err - } - saveData = reflect.Value{} - } - } - - if err := copyValue(saveData, data); err != nil { - return err - } - - switch t := saveComment; t.Kind() { - case reflect.String: - t.SetString(string(comment)) - case reflect.Slice: - t.Set(reflect.ValueOf(comment)) - } - - switch t := saveXML; t.Kind() { - case reflect.String: - t.SetString(string(saveXMLData)) - case reflect.Slice: - t.Set(reflect.ValueOf(saveXMLData)) - } - - return nil -} - -func copyValue(dst reflect.Value, src []byte) (err error) { - dst0 := dst - - if dst.Kind() == reflect.Ptr { - if dst.IsNil() { - dst.Set(reflect.New(dst.Type().Elem())) - } - dst = dst.Elem() - } - - // Save accumulated data. - switch dst.Kind() { - case reflect.Invalid: - // Probably a comment. - default: - return errors.New("cannot unmarshal into " + dst0.Type().String()) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - itmp, err := strconv.ParseInt(string(src), 10, dst.Type().Bits()) - if err != nil { - return err - } - dst.SetInt(itmp) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - utmp, err := strconv.ParseUint(string(src), 10, dst.Type().Bits()) - if err != nil { - return err - } - dst.SetUint(utmp) - case reflect.Float32, reflect.Float64: - ftmp, err := strconv.ParseFloat(string(src), dst.Type().Bits()) - if err != nil { - return err - } - dst.SetFloat(ftmp) - case reflect.Bool: - value, err := strconv.ParseBool(strings.TrimSpace(string(src))) - if err != nil { - return err - } - dst.SetBool(value) - case reflect.String: - dst.SetString(string(src)) - case reflect.Slice: - if len(src) == 0 { - // non-nil to flag presence - src = []byte{} - } - dst.SetBytes(src) - } - return nil -} - -// unmarshalPath walks down an XML structure looking for wanted -// paths, and calls unmarshal on them. -// The consumed result tells whether XML elements have been consumed -// from the Decoder until start's matching end element, or if it's -// 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) { - recurse := false -Loop: - for i := range tinfo.fields { - finfo := &tinfo.fields[i] - if finfo.flags&fElement == 0 || len(finfo.parents) < len(parents) || finfo.xmlns != "" && finfo.xmlns != start.Name.Space { - continue - } - for j := range parents { - if parents[j] != finfo.parents[j] { - continue Loop - } - } - if len(finfo.parents) == len(parents) && finfo.name == start.Name.Local { - // It's a perfect match, unmarshal the field. - return true, p.unmarshal(finfo.value(sv), start) - } - if len(finfo.parents) > len(parents) && finfo.parents[len(parents)] == start.Name.Local { - // It's a prefix for the field. Break and recurse - // since it's not ok for one field path to be itself - // the prefix for another field path. - recurse = true - - // We can reuse the same slice as long as we - // don't try to append to it. - parents = finfo.parents[:len(parents)+1] - break - } - } - if !recurse { - // We have no business with this element. - return false, nil - } - // The element is not a perfect match for any field, but one - // or more fields have the path to this element as a parent - // prefix. Recurse and attempt to match these. - for { - var tok Token - tok, err = p.Token() - if err != nil { - return true, err - } - switch t := tok.(type) { - case StartElement: - consumed2, err := p.unmarshalPath(tinfo, sv, parents, &t) - if err != nil { - return true, err - } - if !consumed2 { - if err := p.Skip(); err != nil { - return true, err - } - } - case EndElement: - return true, nil - } - } -} - -// Skip reads tokens until it has consumed the end element -// matching the most recent start element already consumed. -// It recurs if it encounters a start element, so it can be used to -// skip nested structures. -// It returns nil if it finds an end element matching the start -// element; otherwise it returns an error describing the problem. -func (d *Decoder) Skip() error { - for { - tok, err := d.Token() - if err != nil { - return err - } - switch tok.(type) { - case StartElement: - if err := d.Skip(); err != nil { - return err - } - case EndElement: - return nil - } - } -} diff --git a/vendor/golang.org/x/net/webdav/internal/xml/read_test.go b/vendor/golang.org/x/net/webdav/internal/xml/read_test.go deleted file mode 100644 index 02f1e10c3..000000000 --- a/vendor/golang.org/x/net/webdav/internal/xml/read_test.go +++ /dev/null @@ -1,744 +0,0 @@ -// Copyright 2009 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 - -import ( - "bytes" - "fmt" - "io" - "reflect" - "strings" - "testing" - "time" -) - -// Stripped down Atom feed data structures. - -func TestUnmarshalFeed(t *testing.T) { - var f Feed - if err := Unmarshal([]byte(atomFeedString), &f); err != nil { - t.Fatalf("Unmarshal: %s", err) - } - if !reflect.DeepEqual(f, atomFeed) { - t.Fatalf("have %#v\nwant %#v", f, atomFeed) - } -} - -// hget http://codereview.appspot.com/rss/mine/rsc -const atomFeedString = ` -<?xml version="1.0" encoding="utf-8"?> -<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-us" updated="2009-10-04T01:35:58+00:00"><title>Code Review - My issues</title><link href="http://codereview.appspot.com/" rel="alternate"></link><link href="http://codereview.appspot.com/rss/mine/rsc" rel="self"></link><id>http://codereview.appspot.com/</id><author><name>rietveld<></name></author><entry><title>rietveld: an attempt at pubsubhubbub -</title><link href="http://codereview.appspot.com/126085" rel="alternate"></link><updated>2009-10-04T01:35:58+00:00</updated><author><name>email-address-removed</name></author><id>urn:md5:134d9179c41f806be79b3a5f7877d19a</id><summary type="html"> - An attempt at adding pubsubhubbub support to Rietveld. -http://code.google.com/p/pubsubhubbub -http://code.google.com/p/rietveld/issues/detail?id=155 - -The server side of the protocol is trivial: - 1. add a &lt;link rel=&quot;hub&quot; href=&quot;hub-server&quot;&gt; tag to all - feeds that will be pubsubhubbubbed. - 2. every time one of those feeds changes, tell the hub - with a simple POST request. - -I have tested this by adding debug prints to a local hub -server and checking that the server got the right publish -requests. - -I can&#39;t quite get the server to work, but I think the bug -is not in my code. I think that the server expects to be -able to grab the feed and see the feed&#39;s actual URL in -the link rel=&quot;self&quot;, but the default value for that drops -the :port from the URL, and I cannot for the life of me -figure out how to get the Atom generator deep inside -django not to do that, or even where it is doing that, -or even what code is running to generate the Atom feed. -(I thought I knew but I added some assert False statements -and it kept running!) - -Ignoring that particular problem, I would appreciate -feedback on the right way to get the two values at -the top of feeds.py marked NOTE(rsc). - - -</summary></entry><entry><title>rietveld: correct tab handling -</title><link href="http://codereview.appspot.com/124106" rel="alternate"></link><updated>2009-10-03T23:02:17+00:00</updated><author><name>email-address-removed</name></author><id>urn:md5:0a2a4f19bb815101f0ba2904aed7c35a</id><summary type="html"> - This fixes the buggy tab rendering that can be seen at -http://codereview.appspot.com/116075/diff/1/2 - -The fundamental problem was that the tab code was -not being told what column the text began in, so it -didn&#39;t know where to put the tab stops. Another problem -was that some of the code assumed that string byte -offsets were the same as column offsets, which is only -true if there are no tabs. - -In the process of fixing this, I cleaned up the arguments -to Fold and ExpandTabs and renamed them Break and -_ExpandTabs so that I could be sure that I found all the -call sites. I also wanted to verify that ExpandTabs was -not being used from outside intra_region_diff.py. - - -</summary></entry></feed> ` - -type Feed struct { - XMLName Name `xml:"http://www.w3.org/2005/Atom feed"` - Title string `xml:"title"` - Id string `xml:"id"` - Link []Link `xml:"link"` - Updated time.Time `xml:"updated,attr"` - Author Person `xml:"author"` - Entry []Entry `xml:"entry"` -} - -type Entry struct { - Title string `xml:"title"` - Id string `xml:"id"` - Link []Link `xml:"link"` - Updated time.Time `xml:"updated"` - Author Person `xml:"author"` - Summary Text `xml:"summary"` -} - -type Link struct { - Rel string `xml:"rel,attr,omitempty"` - Href string `xml:"href,attr"` -} - -type Person struct { - Name string `xml:"name"` - URI string `xml:"uri"` - Email string `xml:"email"` - InnerXML string `xml:",innerxml"` -} - -type Text struct { - Type string `xml:"type,attr,omitempty"` - Body string `xml:",chardata"` -} - -var atomFeed = Feed{ - XMLName: Name{"http://www.w3.org/2005/Atom", "feed"}, - Title: "Code Review - My issues", - Link: []Link{ - {Rel: "alternate", Href: "http://codereview.appspot.com/"}, - {Rel: "self", Href: "http://codereview.appspot.com/rss/mine/rsc"}, - }, - Id: "http://codereview.appspot.com/", - Updated: ParseTime("2009-10-04T01:35:58+00:00"), - Author: Person{ - Name: "rietveld<>", - InnerXML: "<name>rietveld<></name>", - }, - Entry: []Entry{ - { - Title: "rietveld: an attempt at pubsubhubbub\n", - Link: []Link{ - {Rel: "alternate", Href: "http://codereview.appspot.com/126085"}, - }, - Updated: ParseTime("2009-10-04T01:35:58+00:00"), - Author: Person{ - Name: "email-address-removed", - InnerXML: "<name>email-address-removed</name>", - }, - Id: "urn:md5:134d9179c41f806be79b3a5f7877d19a", - Summary: Text{ - Type: "html", - Body: ` - An attempt at adding pubsubhubbub support to Rietveld. -http://code.google.com/p/pubsubhubbub -http://code.google.com/p/rietveld/issues/detail?id=155 - -The server side of the protocol is trivial: - 1. add a <link rel="hub" href="hub-server"> tag to all - feeds that will be pubsubhubbubbed. - 2. every time one of those feeds changes, tell the hub - with a simple POST request. - -I have tested this by adding debug prints to a local hub -server and checking that the server got the right publish -requests. - -I can't quite get the server to work, but I think the bug -is not in my code. I think that the server expects to be -able to grab the feed and see the feed's actual URL in -the link rel="self", but the default value for that drops -the :port from the URL, and I cannot for the life of me -figure out how to get the Atom generator deep inside -django not to do that, or even where it is doing that, -or even what code is running to generate the Atom feed. -(I thought I knew but I added some assert False statements -and it kept running!) - -Ignoring that particular problem, I would appreciate -feedback on the right way to get the two values at -the top of feeds.py marked NOTE(rsc). - - -`, - }, - }, - { - Title: "rietveld: correct tab handling\n", - Link: []Link{ - {Rel: "alternate", Href: "http://codereview.appspot.com/124106"}, - }, - Updated: ParseTime("2009-10-03T23:02:17+00:00"), - Author: Person{ - Name: "email-address-removed", - InnerXML: "<name>email-address-removed</name>", - }, - Id: "urn:md5:0a2a4f19bb815101f0ba2904aed7c35a", - Summary: Text{ - Type: "html", - Body: ` - This fixes the buggy tab rendering that can be seen at -http://codereview.appspot.com/116075/diff/1/2 - -The fundamental problem was that the tab code was -not being told what column the text began in, so it -didn't know where to put the tab stops. Another problem -was that some of the code assumed that string byte -offsets were the same as column offsets, which is only -true if there are no tabs. - -In the process of fixing this, I cleaned up the arguments -to Fold and ExpandTabs and renamed them Break and -_ExpandTabs so that I could be sure that I found all the -call sites. I also wanted to verify that ExpandTabs was -not being used from outside intra_region_diff.py. - - -`, - }, - }, - }, -} - -const pathTestString = ` -<Result> - <Before>1</Before> - <Items> - <Item1> - <Value>A</Value> - </Item1> - <Item2> - <Value>B</Value> - </Item2> - <Item1> - <Value>C</Value> - <Value>D</Value> - </Item1> - <_> - <Value>E</Value> - </_> - </Items> - <After>2</After> -</Result> -` - -type PathTestItem struct { - Value string -} - -type PathTestA struct { - Items []PathTestItem `xml:">Item1"` - Before, After string -} - -type PathTestB struct { - Other []PathTestItem `xml:"Items>Item1"` - Before, After string -} - -type PathTestC struct { - Values1 []string `xml:"Items>Item1>Value"` - Values2 []string `xml:"Items>Item2>Value"` - Before, After string -} - -type PathTestSet struct { - Item1 []PathTestItem -} - -type PathTestD struct { - Other PathTestSet `xml:"Items"` - Before, After string -} - -type PathTestE struct { - Underline string `xml:"Items>_>Value"` - Before, After string -} - -var pathTests = []interface{}{ - &PathTestA{Items: []PathTestItem{{"A"}, {"D"}}, Before: "1", After: "2"}, - &PathTestB{Other: []PathTestItem{{"A"}, {"D"}}, Before: "1", After: "2"}, - &PathTestC{Values1: []string{"A", "C", "D"}, Values2: []string{"B"}, Before: "1", After: "2"}, - &PathTestD{Other: PathTestSet{Item1: []PathTestItem{{"A"}, {"D"}}}, Before: "1", After: "2"}, - &PathTestE{Underline: "E", Before: "1", After: "2"}, -} - -func TestUnmarshalPaths(t *testing.T) { - for _, pt := range pathTests { - v := reflect.New(reflect.TypeOf(pt).Elem()).Interface() - if err := Unmarshal([]byte(pathTestString), v); err != nil { - t.Fatalf("Unmarshal: %s", err) - } - if !reflect.DeepEqual(v, pt) { - t.Fatalf("have %#v\nwant %#v", v, pt) - } - } -} - -type BadPathTestA struct { - First string `xml:"items>item1"` - Other string `xml:"items>item2"` - Second string `xml:"items"` -} - -type BadPathTestB struct { - Other string `xml:"items>item2>value"` - First string `xml:"items>item1"` - Second string `xml:"items>item1>value"` -} - -type BadPathTestC struct { - First string - Second string `xml:"First"` -} - -type BadPathTestD struct { - BadPathEmbeddedA - BadPathEmbeddedB -} - -type BadPathEmbeddedA struct { - First string -} - -type BadPathEmbeddedB struct { - Second string `xml:"First"` -} - -var badPathTests = []struct { - v, e interface{} -}{ - {&BadPathTestA{}, &TagPathError{reflect.TypeOf(BadPathTestA{}), "First", "items>item1", "Second", "items"}}, - {&BadPathTestB{}, &TagPathError{reflect.TypeOf(BadPathTestB{}), "First", "items>item1", "Second", "items>item1>value"}}, - {&BadPathTestC{}, &TagPathError{reflect.TypeOf(BadPathTestC{}), "First", "", "Second", "First"}}, - {&BadPathTestD{}, &TagPathError{reflect.TypeOf(BadPathTestD{}), "First", "", "Second", "First"}}, -} - -func TestUnmarshalBadPaths(t *testing.T) { - for _, tt := range badPathTests { - err := Unmarshal([]byte(pathTestString), tt.v) - if !reflect.DeepEqual(err, tt.e) { - t.Fatalf("Unmarshal with %#v didn't fail properly:\nhave %#v,\nwant %#v", tt.v, err, tt.e) - } - } -} - -const OK = "OK" -const withoutNameTypeData = ` -<?xml version="1.0" charset="utf-8"?> -<Test3 Attr="OK" />` - -type TestThree struct { - XMLName Name `xml:"Test3"` - Attr string `xml:",attr"` -} - -func TestUnmarshalWithoutNameType(t *testing.T) { - var x TestThree - if err := Unmarshal([]byte(withoutNameTypeData), &x); err != nil { - t.Fatalf("Unmarshal: %s", err) - } - if x.Attr != OK { - t.Fatalf("have %v\nwant %v", x.Attr, OK) - } -} - -func TestUnmarshalAttr(t *testing.T) { - type ParamVal struct { - Int int `xml:"int,attr"` - } - - type ParamPtr struct { - Int *int `xml:"int,attr"` - } - - type ParamStringPtr struct { - Int *string `xml:"int,attr"` - } - - x := []byte(`<Param int="1" />`) - - p1 := &ParamPtr{} - if err := Unmarshal(x, p1); err != nil { - t.Fatalf("Unmarshal: %s", err) - } - if p1.Int == nil { - t.Fatalf("Unmarshal failed in to *int field") - } else if *p1.Int != 1 { - t.Fatalf("Unmarshal with %s failed:\nhave %#v,\n want %#v", x, p1.Int, 1) - } - - p2 := &ParamVal{} - if err := Unmarshal(x, p2); err != nil { - t.Fatalf("Unmarshal: %s", err) - } - if p2.Int != 1 { - t.Fatalf("Unmarshal with %s failed:\nhave %#v,\n want %#v", x, p2.Int, 1) - } - - p3 := &ParamStringPtr{} - if err := Unmarshal(x, p3); err != nil { - t.Fatalf("Unmarshal: %s", err) - } - if p3.Int == nil { - t.Fatalf("Unmarshal failed in to *string field") - } else if *p3.Int != "1" { - t.Fatalf("Unmarshal with %s failed:\nhave %#v,\n want %#v", x, p3.Int, 1) - } -} - -type Tables struct { - HTable string `xml:"http://www.w3.org/TR/html4/ table"` - FTable string `xml:"http://www.w3schools.com/furniture table"` -} - -var tables = []struct { - xml string - tab Tables - ns string -}{ - { - xml: `<Tables>` + - `<table xmlns="http://www.w3.org/TR/html4/">hello</table>` + - `<table xmlns="http://www.w3schools.com/furniture">world</table>` + - `</Tables>`, - tab: Tables{"hello", "world"}, - }, - { - xml: `<Tables>` + - `<table xmlns="http://www.w3schools.com/furniture">world</table>` + - `<table xmlns="http://www.w3.org/TR/html4/">hello</table>` + - `</Tables>`, - tab: Tables{"hello", "world"}, - }, - { - xml: `<Tables xmlns:f="http://www.w3schools.com/furniture" xmlns:h="http://www.w3.org/TR/html4/">` + - `<f:table>world</f:table>` + - `<h:table>hello</h:table>` + - `</Tables>`, - tab: Tables{"hello", "world"}, - }, - { - xml: `<Tables>` + - `<table>bogus</table>` + - `</Tables>`, - tab: Tables{}, - }, - { - xml: `<Tables>` + - `<table>only</table>` + - `</Tables>`, - tab: Tables{HTable: "only"}, - ns: "http://www.w3.org/TR/html4/", - }, - { - xml: `<Tables>` + - `<table>only</table>` + - `</Tables>`, - tab: Tables{FTable: "only"}, - ns: "http://www.w3schools.com/furniture", - }, - { - xml: `<Tables>` + - `<table>only</table>` + - `</Tables>`, - tab: Tables{}, - ns: "something else entirely", - }, -} - -func TestUnmarshalNS(t *testing.T) { - for i, tt := range tables { - var dst Tables - var err error - if tt.ns != "" { - d := NewDecoder(strings.NewReader(tt.xml)) - d.DefaultSpace = tt.ns - err = d.Decode(&dst) - } else { - err = Unmarshal([]byte(tt.xml), &dst) - } - if err != nil { - t.Errorf("#%d: Unmarshal: %v", i, err) - continue - } - want := tt.tab - if dst != want { - t.Errorf("#%d: dst=%+v, want %+v", i, dst, want) - } - } -} - -func TestRoundTrip(t *testing.T) { - // From issue 7535 - const s = `<ex:element xmlns:ex="http://example.com/schema"></ex:element>` - in := bytes.NewBufferString(s) - for i := 0; i < 10; i++ { - out := &bytes.Buffer{} - d := NewDecoder(in) - e := NewEncoder(out) - - for { - t, err := d.Token() - if err == io.EOF { - break - } - if err != nil { - fmt.Println("failed:", err) - return - } - e.EncodeToken(t) - } - e.Flush() - in = out - } - if got := in.String(); got != s { - t.Errorf("have: %q\nwant: %q\n", got, s) - } -} - -func TestMarshalNS(t *testing.T) { - dst := Tables{"hello", "world"} - data, err := Marshal(&dst) - if err != nil { - t.Fatalf("Marshal: %v", err) - } - want := `<Tables><table xmlns="http://www.w3.org/TR/html4/">hello</table><table xmlns="http://www.w3schools.com/furniture">world</table></Tables>` - str := string(data) - if str != want { - t.Errorf("have: %q\nwant: %q\n", str, want) - } -} - -type TableAttrs struct { - TAttr TAttr -} - -type TAttr struct { - HTable string `xml:"http://www.w3.org/TR/html4/ table,attr"` - FTable string `xml:"http://www.w3schools.com/furniture table,attr"` - Lang string `xml:"http://www.w3.org/XML/1998/namespace lang,attr,omitempty"` - Other1 string `xml:"http://golang.org/xml/ other,attr,omitempty"` - Other2 string `xml:"http://golang.org/xmlfoo/ other,attr,omitempty"` - Other3 string `xml:"http://golang.org/json/ other,attr,omitempty"` - Other4 string `xml:"http://golang.org/2/json/ other,attr,omitempty"` -} - -var tableAttrs = []struct { - xml string - tab TableAttrs - ns string -}{ - { - xml: `<TableAttrs xmlns:f="http://www.w3schools.com/furniture" xmlns:h="http://www.w3.org/TR/html4/"><TAttr ` + - `h:table="hello" f:table="world" ` + - `/></TableAttrs>`, - tab: TableAttrs{TAttr{HTable: "hello", FTable: "world"}}, - }, - { - xml: `<TableAttrs><TAttr xmlns:f="http://www.w3schools.com/furniture" xmlns:h="http://www.w3.org/TR/html4/" ` + - `h:table="hello" f:table="world" ` + - `/></TableAttrs>`, - tab: TableAttrs{TAttr{HTable: "hello", FTable: "world"}}, - }, - { - xml: `<TableAttrs><TAttr ` + - `h:table="hello" f:table="world" xmlns:f="http://www.w3schools.com/furniture" xmlns:h="http://www.w3.org/TR/html4/" ` + - `/></TableAttrs>`, - tab: TableAttrs{TAttr{HTable: "hello", FTable: "world"}}, - }, - { - // Default space does not apply to attribute names. - xml: `<TableAttrs xmlns="http://www.w3schools.com/furniture" xmlns:h="http://www.w3.org/TR/html4/"><TAttr ` + - `h:table="hello" table="world" ` + - `/></TableAttrs>`, - tab: TableAttrs{TAttr{HTable: "hello", FTable: ""}}, - }, - { - // Default space does not apply to attribute names. - xml: `<TableAttrs xmlns:f="http://www.w3schools.com/furniture"><TAttr xmlns="http://www.w3.org/TR/html4/" ` + - `table="hello" f:table="world" ` + - `/></TableAttrs>`, - tab: TableAttrs{TAttr{HTable: "", FTable: "world"}}, - }, - { - xml: `<TableAttrs><TAttr ` + - `table="bogus" ` + - `/></TableAttrs>`, - tab: TableAttrs{}, - }, - { - // Default space does not apply to attribute names. - xml: `<TableAttrs xmlns:h="http://www.w3.org/TR/html4/"><TAttr ` + - `h:table="hello" table="world" ` + - `/></TableAttrs>`, - tab: TableAttrs{TAttr{HTable: "hello", FTable: ""}}, - ns: "http://www.w3schools.com/furniture", - }, - { - // Default space does not apply to attribute names. - xml: `<TableAttrs xmlns:f="http://www.w3schools.com/furniture"><TAttr ` + - `table="hello" f:table="world" ` + - `/></TableAttrs>`, - tab: TableAttrs{TAttr{HTable: "", FTable: "world"}}, - ns: "http://www.w3.org/TR/html4/", - }, - { - xml: `<TableAttrs><TAttr ` + - `table="bogus" ` + - `/></TableAttrs>`, - tab: TableAttrs{}, - ns: "something else entirely", - }, -} - -func TestUnmarshalNSAttr(t *testing.T) { - for i, tt := range tableAttrs { - var dst TableAttrs - var err error - if tt.ns != "" { - d := NewDecoder(strings.NewReader(tt.xml)) - d.DefaultSpace = tt.ns - err = d.Decode(&dst) - } else { - err = Unmarshal([]byte(tt.xml), &dst) - } - if err != nil { - t.Errorf("#%d: Unmarshal: %v", i, err) - continue - } - want := tt.tab - if dst != want { - t.Errorf("#%d: dst=%+v, want %+v", i, dst, want) - } - } -} - -func TestMarshalNSAttr(t *testing.T) { - src := TableAttrs{TAttr{"hello", "world", "en_US", "other1", "other2", "other3", "other4"}} - data, err := Marshal(&src) - if err != nil { - t.Fatalf("Marshal: %v", err) - } - want := `<TableAttrs><TAttr xmlns:json_1="http://golang.org/2/json/" xmlns:json="http://golang.org/json/" xmlns:_xmlfoo="http://golang.org/xmlfoo/" xmlns:_xml="http://golang.org/xml/" xmlns:furniture="http://www.w3schools.com/furniture" xmlns:html4="http://www.w3.org/TR/html4/" html4:table="hello" furniture:table="world" xml:lang="en_US" _xml:other="other1" _xmlfoo:other="other2" json:other="other3" json_1:other="other4"></TAttr></TableAttrs>` - str := string(data) - if str != want { - t.Errorf("Marshal:\nhave: %#q\nwant: %#q\n", str, want) - } - - var dst TableAttrs - if err := Unmarshal(data, &dst); err != nil { - t.Errorf("Unmarshal: %v", err) - } - - if dst != src { - t.Errorf("Unmarshal = %q, want %q", dst, src) - } -} - -type MyCharData struct { - body string -} - -func (m *MyCharData) UnmarshalXML(d *Decoder, start StartElement) error { - for { - t, err := d.Token() - if err == io.EOF { // found end of element - break - } - if err != nil { - return err - } - if char, ok := t.(CharData); ok { - m.body += string(char) - } - } - return nil -} - -var _ Unmarshaler = (*MyCharData)(nil) - -func (m *MyCharData) UnmarshalXMLAttr(attr Attr) error { - panic("must not call") -} - -type MyAttr struct { - attr string -} - -func (m *MyAttr) UnmarshalXMLAttr(attr Attr) error { - m.attr = attr.Value - return nil -} - -var _ UnmarshalerAttr = (*MyAttr)(nil) - -type MyStruct struct { - Data *MyCharData - Attr *MyAttr `xml:",attr"` - - Data2 MyCharData - Attr2 MyAttr `xml:",attr"` -} - -func TestUnmarshaler(t *testing.T) { - xml := `<?xml version="1.0" encoding="utf-8"?> - <MyStruct Attr="attr1" Attr2="attr2"> - <Data>hello <!-- comment -->world</Data> - <Data2>howdy <!-- comment -->world</Data2> - </MyStruct> - ` - - var m MyStruct - if err := Unmarshal([]byte(xml), &m); err != nil { - t.Fatal(err) - } - - if m.Data == nil || m.Attr == nil || m.Data.body != "hello world" || m.Attr.attr != "attr1" || m.Data2.body != "howdy world" || m.Attr2.attr != "attr2" { - t.Errorf("m=%#+v\n", m) - } -} - -type Pea struct { - Cotelydon string -} - -type Pod struct { - Pea interface{} `xml:"Pea"` -} - -// https://golang.org/issue/6836 -func TestUnmarshalIntoInterface(t *testing.T) { - pod := new(Pod) - pod.Pea = new(Pea) - xml := `<Pod><Pea><Cotelydon>Green stuff</Cotelydon></Pea></Pod>` - err := Unmarshal([]byte(xml), pod) - if err != nil { - t.Fatalf("failed to unmarshal %q: %v", xml, err) - } - pea, ok := pod.Pea.(*Pea) - if !ok { - t.Fatalf("unmarshalled into wrong type: have %T want *Pea", pod.Pea) - } - have, want := pea.Cotelydon, "Green stuff" - if have != want { - t.Errorf("failed to unmarshal into interface, have %q want %q", have, want) - } -} diff --git a/vendor/golang.org/x/net/webdav/internal/xml/typeinfo.go b/vendor/golang.org/x/net/webdav/internal/xml/typeinfo.go deleted file mode 100644 index fdde288bc..000000000 --- a/vendor/golang.org/x/net/webdav/internal/xml/typeinfo.go +++ /dev/null @@ -1,371 +0,0 @@ -// Copyright 2011 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 - -import ( - "fmt" - "reflect" - "strings" - "sync" -) - -// typeInfo holds details for the xml representation of a type. -type typeInfo struct { - xmlname *fieldInfo - fields []fieldInfo -} - -// fieldInfo holds details for the xml representation of a single field. -type fieldInfo struct { - idx []int - name string - xmlns string - flags fieldFlags - parents []string -} - -type fieldFlags int - -const ( - fElement fieldFlags = 1 << iota - fAttr - fCharData - fInnerXml - fComment - fAny - - fOmitEmpty - - fMode = fElement | fAttr | fCharData | fInnerXml | fComment | fAny -) - -var tinfoMap = make(map[reflect.Type]*typeInfo) -var tinfoLock sync.RWMutex - -var nameType = reflect.TypeOf(Name{}) - -// getTypeInfo returns the typeInfo structure with details necessary -// for marshalling and unmarshalling typ. -func getTypeInfo(typ reflect.Type) (*typeInfo, error) { - tinfoLock.RLock() - tinfo, ok := tinfoMap[typ] - tinfoLock.RUnlock() - if ok { - return tinfo, nil - } - tinfo = &typeInfo{} - if typ.Kind() == reflect.Struct && typ != nameType { - n := typ.NumField() - for i := 0; i < n; i++ { - f := typ.Field(i) - if f.PkgPath != "" || f.Tag.Get("xml") == "-" { - continue // Private field - } - - // For embedded structs, embed its fields. - if f.Anonymous { - t := f.Type - if t.Kind() == reflect.Ptr { - t = t.Elem() - } - if t.Kind() == reflect.Struct { - inner, err := getTypeInfo(t) - if err != nil { - return nil, err - } - if tinfo.xmlname == nil { - tinfo.xmlname = inner.xmlname - } - for _, finfo := range inner.fields { - finfo.idx = append([]int{i}, finfo.idx...) - if err := addFieldInfo(typ, tinfo, &finfo); err != nil { - return nil, err - } - } - continue - } - } - - finfo, err := structFieldInfo(typ, &f) - if err != nil { - return nil, err - } - - if f.Name == "XMLName" { - tinfo.xmlname = finfo - continue - } - - // Add the field if it doesn't conflict with other fields. - if err := addFieldInfo(typ, tinfo, finfo); err != nil { - return nil, err - } - } - } - tinfoLock.Lock() - tinfoMap[typ] = tinfo - tinfoLock.Unlock() - return tinfo, nil -} - -// structFieldInfo builds and returns a fieldInfo for f. -func structFieldInfo(typ reflect.Type, f *reflect.StructField) (*fieldInfo, error) { - finfo := &fieldInfo{idx: f.Index} - - // Split the tag from the xml namespace if necessary. - tag := f.Tag.Get("xml") - if i := strings.Index(tag, " "); i >= 0 { - finfo.xmlns, tag = tag[:i], tag[i+1:] - } - - // Parse flags. - tokens := strings.Split(tag, ",") - if len(tokens) == 1 { - finfo.flags = fElement - } else { - tag = tokens[0] - for _, flag := range tokens[1:] { - switch flag { - case "attr": - finfo.flags |= fAttr - case "chardata": - finfo.flags |= fCharData - case "innerxml": - finfo.flags |= fInnerXml - case "comment": - finfo.flags |= fComment - case "any": - finfo.flags |= fAny - case "omitempty": - finfo.flags |= fOmitEmpty - } - } - - // Validate the flags used. - valid := true - switch mode := finfo.flags & fMode; mode { - case 0: - finfo.flags |= fElement - case fAttr, fCharData, fInnerXml, fComment, fAny: - if f.Name == "XMLName" || tag != "" && mode != fAttr { - valid = false - } - default: - // This will also catch multiple modes in a single field. - valid = false - } - if finfo.flags&fMode == fAny { - finfo.flags |= fElement - } - if finfo.flags&fOmitEmpty != 0 && finfo.flags&(fElement|fAttr) == 0 { - valid = false - } - if !valid { - return nil, fmt.Errorf("xml: invalid tag in field %s of type %s: %q", - f.Name, typ, f.Tag.Get("xml")) - } - } - - // Use of xmlns without a name is not allowed. - if finfo.xmlns != "" && tag == "" { - return nil, fmt.Errorf("xml: namespace without name in field %s of type %s: %q", - f.Name, typ, f.Tag.Get("xml")) - } - - if f.Name == "XMLName" { - // The XMLName field records the XML element name. Don't - // process it as usual because its name should default to - // empty rather than to the field name. - finfo.name = tag - return finfo, nil - } - - if tag == "" { - // If the name part of the tag is completely empty, get - // default from XMLName of underlying struct if feasible, - // or field name otherwise. - if xmlname := lookupXMLName(f.Type); xmlname != nil { - finfo.xmlns, finfo.name = xmlname.xmlns, xmlname.name - } else { - finfo.name = f.Name - } - return finfo, nil - } - - if finfo.xmlns == "" && finfo.flags&fAttr == 0 { - // If it's an element no namespace specified, get the default - // from the XMLName of enclosing struct if possible. - if xmlname := lookupXMLName(typ); xmlname != nil { - finfo.xmlns = xmlname.xmlns - } - } - - // Prepare field name and parents. - parents := strings.Split(tag, ">") - if parents[0] == "" { - parents[0] = f.Name - } - if parents[len(parents)-1] == "" { - return nil, fmt.Errorf("xml: trailing '>' in field %s of type %s", f.Name, typ) - } - finfo.name = parents[len(parents)-1] - if len(parents) > 1 { - if (finfo.flags & fElement) == 0 { - return nil, fmt.Errorf("xml: %s chain not valid with %s flag", tag, strings.Join(tokens[1:], ",")) - } - finfo.parents = parents[:len(parents)-1] - } - - // If the field type has an XMLName field, the names must match - // so that the behavior of both marshalling and unmarshalling - // is straightforward and unambiguous. - if finfo.flags&fElement != 0 { - ftyp := f.Type - xmlname := lookupXMLName(ftyp) - if xmlname != nil && xmlname.name != finfo.name { - return nil, fmt.Errorf("xml: name %q in tag of %s.%s conflicts with name %q in %s.XMLName", - finfo.name, typ, f.Name, xmlname.name, ftyp) - } - } - return finfo, nil -} - -// lookupXMLName returns the fieldInfo for typ's XMLName field -// in case it exists and has a valid xml field tag, otherwise -// it returns nil. -func lookupXMLName(typ reflect.Type) (xmlname *fieldInfo) { - for typ.Kind() == reflect.Ptr { - typ = typ.Elem() - } - if typ.Kind() != reflect.Struct { - return nil - } - for i, n := 0, typ.NumField(); i < n; i++ { - f := typ.Field(i) - if f.Name != "XMLName" { - continue - } - finfo, err := structFieldInfo(typ, &f) - if finfo.name != "" && err == nil { - return finfo - } - // Also consider errors as a non-existent field tag - // and let getTypeInfo itself report the error. - break - } - return nil -} - -func min(a, b int) int { - if a <= b { - return a - } - return b -} - -// addFieldInfo adds finfo to tinfo.fields if there are no -// conflicts, or if conflicts arise from previous fields that were -// obtained from deeper embedded structures than finfo. In the latter -// case, the conflicting entries are dropped. -// A conflict occurs when the path (parent + name) to a field is -// itself a prefix of another path, or when two paths match exactly. -// It is okay for field paths to share a common, shorter prefix. -func addFieldInfo(typ reflect.Type, tinfo *typeInfo, newf *fieldInfo) error { - var conflicts []int -Loop: - // First, figure all conflicts. Most working code will have none. - for i := range tinfo.fields { - oldf := &tinfo.fields[i] - if oldf.flags&fMode != newf.flags&fMode { - continue - } - if oldf.xmlns != "" && newf.xmlns != "" && oldf.xmlns != newf.xmlns { - continue - } - minl := min(len(newf.parents), len(oldf.parents)) - for p := 0; p < minl; p++ { - if oldf.parents[p] != newf.parents[p] { - continue Loop - } - } - if len(oldf.parents) > len(newf.parents) { - if oldf.parents[len(newf.parents)] == newf.name { - conflicts = append(conflicts, i) - } - } else if len(oldf.parents) < len(newf.parents) { - if newf.parents[len(oldf.parents)] == oldf.name { - conflicts = append(conflicts, i) - } - } else { - if newf.name == oldf.name { - conflicts = append(conflicts, i) - } - } - } - // Without conflicts, add the new field and return. - if conflicts == nil { - tinfo.fields = append(tinfo.fields, *newf) - return nil - } - - // If any conflict is shallower, ignore the new field. - // This matches the Go field resolution on embedding. - for _, i := range conflicts { - if len(tinfo.fields[i].idx) < len(newf.idx) { - return nil - } - } - - // Otherwise, if any of them is at the same depth level, it's an error. - for _, i := range conflicts { - oldf := &tinfo.fields[i] - if len(oldf.idx) == len(newf.idx) { - f1 := typ.FieldByIndex(oldf.idx) - f2 := typ.FieldByIndex(newf.idx) - return &TagPathError{typ, f1.Name, f1.Tag.Get("xml"), f2.Name, f2.Tag.Get("xml")} - } - } - - // Otherwise, the new field is shallower, and thus takes precedence, - // so drop the conflicting fields from tinfo and append the new one. - for c := len(conflicts) - 1; c >= 0; c-- { - i := conflicts[c] - copy(tinfo.fields[i:], tinfo.fields[i+1:]) - tinfo.fields = tinfo.fields[:len(tinfo.fields)-1] - } - tinfo.fields = append(tinfo.fields, *newf) - return nil -} - -// A TagPathError represents an error in the unmarshalling process -// caused by the use of field tags with conflicting paths. -type TagPathError struct { - Struct reflect.Type - Field1, Tag1 string - Field2, Tag2 string -} - -func (e *TagPathError) Error() string { - return fmt.Sprintf("%s field %q with tag %q conflicts with field %q with tag %q", e.Struct, e.Field1, e.Tag1, e.Field2, e.Tag2) -} - -// value returns v's field value corresponding to finfo. -// It's equivalent to v.FieldByIndex(finfo.idx), but initializes -// and dereferences pointers as necessary. -func (finfo *fieldInfo) value(v reflect.Value) reflect.Value { - for i, x := range finfo.idx { - if i > 0 { - t := v.Type() - if t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct { - if v.IsNil() { - v.Set(reflect.New(v.Type().Elem())) - } - v = v.Elem() - } - } - v = v.Field(x) - } - return v -} diff --git a/vendor/golang.org/x/net/webdav/internal/xml/xml.go b/vendor/golang.org/x/net/webdav/internal/xml/xml.go deleted file mode 100644 index 5b79cbecb..000000000 --- a/vendor/golang.org/x/net/webdav/internal/xml/xml.go +++ /dev/null @@ -1,1998 +0,0 @@ -// Copyright 2009 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 implements a simple XML 1.0 parser that -// understands XML name spaces. -package xml - -// References: -// Annotated XML spec: http://www.xml.com/axml/testaxml.htm -// XML name spaces: http://www.w3.org/TR/REC-xml-names/ - -// TODO(rsc): -// Test error handling. - -import ( - "bufio" - "bytes" - "errors" - "fmt" - "io" - "strconv" - "strings" - "unicode" - "unicode/utf8" -) - -// A SyntaxError represents a syntax error in the XML input stream. -type SyntaxError struct { - Msg string - Line int -} - -func (e *SyntaxError) Error() string { - return "XML syntax error on line " + strconv.Itoa(e.Line) + ": " + e.Msg -} - -// A Name represents an XML name (Local) annotated with a name space -// identifier (Space). In tokens returned by Decoder.Token, the Space -// identifier is given as a canonical URL, not the short prefix used in -// the document being parsed. -// -// As a special case, XML namespace declarations will use the literal -// string "xmlns" for the Space field instead of the fully resolved URL. -// See Encoder.EncodeToken for more information on namespace encoding -// behaviour. -type Name struct { - Space, Local string -} - -// isNamespace reports whether the name is a namespace-defining name. -func (name Name) isNamespace() bool { - return name.Local == "xmlns" || name.Space == "xmlns" -} - -// An Attr represents an attribute in an XML element (Name=Value). -type Attr struct { - Name Name - Value string -} - -// A Token is an interface holding one of the token types: -// StartElement, EndElement, CharData, Comment, ProcInst, or Directive. -type Token interface{} - -// A StartElement represents an XML start element. -type StartElement struct { - Name Name - Attr []Attr -} - -func (e StartElement) Copy() StartElement { - attrs := make([]Attr, len(e.Attr)) - copy(attrs, e.Attr) - e.Attr = attrs - return e -} - -// End returns the corresponding XML end element. -func (e StartElement) End() EndElement { - return EndElement{e.Name} -} - -// setDefaultNamespace sets the namespace of the element -// as the default for all elements contained within it. -func (e *StartElement) setDefaultNamespace() { - if e.Name.Space == "" { - // If there's no namespace on the element, don't - // set the default. Strictly speaking this might be wrong, as - // we can't tell if the element had no namespace set - // or was just using the default namespace. - return - } - // Don't add a default name space if there's already one set. - for _, attr := range e.Attr { - if attr.Name.Space == "" && attr.Name.Local == "xmlns" { - return - } - } - e.Attr = append(e.Attr, Attr{ - Name: Name{ - Local: "xmlns", - }, - Value: e.Name.Space, - }) -} - -// An EndElement represents an XML end element. -type EndElement struct { - Name Name -} - -// A CharData represents XML character data (raw text), -// in which XML escape sequences have been replaced by -// the characters they represent. -type CharData []byte - -func makeCopy(b []byte) []byte { - b1 := make([]byte, len(b)) - copy(b1, b) - return b1 -} - -func (c CharData) Copy() CharData { return CharData(makeCopy(c)) } - -// A Comment represents an XML comment of the form <!--comment-->. -// The bytes do not include the <!-- and --> comment markers. -type Comment []byte - -func (c Comment) Copy() Comment { return Comment(makeCopy(c)) } - -// A ProcInst represents an XML processing instruction of the form <?target inst?> -type ProcInst struct { - Target string - Inst []byte -} - -func (p ProcInst) Copy() ProcInst { - p.Inst = makeCopy(p.Inst) - return p -} - -// A Directive represents an XML directive of the form <!text>. -// The bytes do not include the <! and > markers. -type Directive []byte - -func (d Directive) Copy() Directive { return Directive(makeCopy(d)) } - -// CopyToken returns a copy of a Token. -func CopyToken(t Token) Token { - switch v := t.(type) { - case CharData: - return v.Copy() - case Comment: - return v.Copy() - case Directive: - return v.Copy() - case ProcInst: - return v.Copy() - case StartElement: - return v.Copy() - } - return t -} - -// A Decoder represents an XML parser reading a particular input stream. -// The parser assumes that its input is encoded in UTF-8. -type Decoder struct { - // Strict defaults to true, enforcing the requirements - // of the XML specification. - // If set to false, the parser allows input containing common - // mistakes: - // * If an element is missing an end tag, the parser invents - // end tags as necessary to keep the return values from Token - // properly balanced. - // * In attribute values and character data, unknown or malformed - // character entities (sequences beginning with &) are left alone. - // - // Setting: - // - // d.Strict = false; - // d.AutoClose = HTMLAutoClose; - // d.Entity = HTMLEntity - // - // creates a parser that can handle typical HTML. - // - // Strict mode does not enforce the requirements of the XML name spaces TR. - // In particular it does not reject name space tags using undefined prefixes. - // Such tags are recorded with the unknown prefix as the name space URL. - Strict bool - - // When Strict == false, AutoClose indicates a set of elements to - // consider closed immediately after they are opened, regardless - // of whether an end element is present. - AutoClose []string - - // Entity can be used to map non-standard entity names to string replacements. - // The parser behaves as if these standard mappings are present in the map, - // regardless of the actual map content: - // - // "lt": "<", - // "gt": ">", - // "amp": "&", - // "apos": "'", - // "quot": `"`, - Entity map[string]string - - // CharsetReader, if non-nil, defines a function to generate - // charset-conversion readers, converting from the provided - // non-UTF-8 charset into UTF-8. If CharsetReader is nil or - // returns an error, parsing stops with an error. One of the - // the CharsetReader's result values must be non-nil. - CharsetReader func(charset string, input io.Reader) (io.Reader, error) - - // DefaultSpace sets the default name space used for unadorned tags, - // as if the entire XML stream were wrapped in an element containing - // the attribute xmlns="DefaultSpace". - DefaultSpace string - - r io.ByteReader - buf bytes.Buffer - saved *bytes.Buffer - stk *stack - free *stack - needClose bool - toClose Name - nextToken Token - nextByte int - ns map[string]string - err error - line int - offset int64 - unmarshalDepth int -} - -// NewDecoder creates a new XML parser reading from r. -// If r does not implement io.ByteReader, NewDecoder will -// do its own buffering. -func NewDecoder(r io.Reader) *Decoder { - d := &Decoder{ - ns: make(map[string]string), - nextByte: -1, - line: 1, - Strict: true, - } - d.switchToReader(r) - return d -} - -// Token returns the next XML token in the input stream. -// At the end of the input stream, Token returns nil, io.EOF. -// -// Slices of bytes in the returned token data refer to the -// parser's internal buffer and remain valid only until the next -// call to Token. To acquire a copy of the bytes, call CopyToken -// or the token's Copy method. -// -// Token expands self-closing elements such as <br/> -// into separate start and end elements returned by successive calls. -// -// Token guarantees that the StartElement and EndElement -// tokens it returns are properly nested and matched: -// if Token encounters an unexpected end element, -// it will return an error. -// -// Token implements XML name spaces as described by -// http://www.w3.org/TR/REC-xml-names/. Each of the -// Name structures contained in the Token has the Space -// set to the URL identifying its name space when known. -// If Token encounters an unrecognized name space prefix, -// it uses the prefix as the Space rather than report an error. -func (d *Decoder) Token() (t Token, err error) { - if d.stk != nil && d.stk.kind == stkEOF { - err = io.EOF - return - } - if d.nextToken != nil { - t = d.nextToken - d.nextToken = nil - } else if t, err = d.rawToken(); err != nil { - return - } - - if !d.Strict { - if t1, ok := d.autoClose(t); ok { - d.nextToken = t - t = t1 - } - } - switch t1 := t.(type) { - case StartElement: - // In XML name spaces, the translations listed in the - // attributes apply to the element name and - // to the other attribute names, so process - // the translations first. - for _, a := range t1.Attr { - if a.Name.Space == "xmlns" { - v, ok := d.ns[a.Name.Local] - d.pushNs(a.Name.Local, v, ok) - d.ns[a.Name.Local] = a.Value - } - if a.Name.Space == "" && a.Name.Local == "xmlns" { - // Default space for untagged names - v, ok := d.ns[""] - d.pushNs("", v, ok) - d.ns[""] = a.Value - } - } - - d.translate(&t1.Name, true) - for i := range t1.Attr { - d.translate(&t1.Attr[i].Name, false) - } - d.pushElement(t1.Name) - t = t1 - - case EndElement: - d.translate(&t1.Name, true) - if !d.popElement(&t1) { - return nil, d.err - } - t = t1 - } - return -} - -const xmlURL = "http://www.w3.org/XML/1998/namespace" - -// Apply name space translation to name n. -// The default name space (for Space=="") -// applies only to element names, not to attribute names. -func (d *Decoder) translate(n *Name, isElementName bool) { - switch { - case n.Space == "xmlns": - return - case n.Space == "" && !isElementName: - return - case n.Space == "xml": - n.Space = xmlURL - case n.Space == "" && n.Local == "xmlns": - return - } - if v, ok := d.ns[n.Space]; ok { - n.Space = v - } else if n.Space == "" { - n.Space = d.DefaultSpace - } -} - -func (d *Decoder) switchToReader(r io.Reader) { - // Get efficient byte at a time reader. - // Assume that if reader has its own - // ReadByte, it's efficient enough. - // Otherwise, use bufio. - if rb, ok := r.(io.ByteReader); ok { - d.r = rb - } else { - d.r = bufio.NewReader(r) - } -} - -// Parsing state - stack holds old name space translations -// and the current set of open elements. The translations to pop when -// ending a given tag are *below* it on the stack, which is -// more work but forced on us by XML. -type stack struct { - next *stack - kind int - name Name - ok bool -} - -const ( - stkStart = iota - stkNs - stkEOF -) - -func (d *Decoder) push(kind int) *stack { - s := d.free - if s != nil { - d.free = s.next - } else { - s = new(stack) - } - s.next = d.stk - s.kind = kind - d.stk = s - return s -} - -func (d *Decoder) pop() *stack { - s := d.stk - if s != nil { - d.stk = s.next - s.next = d.free - d.free = s - } - return s -} - -// Record that after the current element is finished -// (that element is already pushed on the stack) -// Token should return EOF until popEOF is called. -func (d *Decoder) pushEOF() { - // Walk down stack to find Start. - // It might not be the top, because there might be stkNs - // entries above it. - start := d.stk - for start.kind != stkStart { - start = start.next - } - // The stkNs entries below a start are associated with that - // element too; skip over them. - for start.next != nil && start.next.kind == stkNs { - start = start.next - } - s := d.free - if s != nil { - d.free = s.next - } else { - s = new(stack) - } - s.kind = stkEOF - s.next = start.next - start.next = s -} - -// Undo a pushEOF. -// The element must have been finished, so the EOF should be at the top of the stack. -func (d *Decoder) popEOF() bool { - if d.stk == nil || d.stk.kind != stkEOF { - return false - } - d.pop() - return true -} - -// Record that we are starting an element with the given name. -func (d *Decoder) pushElement(name Name) { - s := d.push(stkStart) - s.name = name -} - -// Record that we are changing the value of ns[local]. -// The old value is url, ok. -func (d *Decoder) pushNs(local string, url string, ok bool) { - s := d.push(stkNs) - s.name.Local = local - s.name.Space = url - s.ok = ok -} - -// Creates a SyntaxError with the current line number. -func (d *Decoder) syntaxError(msg string) error { - return &SyntaxError{Msg: msg, Line: d.line} -} - -// Record that we are ending an element with the given name. -// The name must match the record at the top of the stack, -// which must be a pushElement record. -// After popping the element, apply any undo records from -// the stack to restore the name translations that existed -// before we saw this element. -func (d *Decoder) popElement(t *EndElement) bool { - s := d.pop() - name := t.Name - switch { - case s == nil || s.kind != stkStart: - d.err = d.syntaxError("unexpected end element </" + name.Local + ">") - return false - case s.name.Local != name.Local: - if !d.Strict { - d.needClose = true - d.toClose = t.Name - t.Name = s.name - return true - } - d.err = d.syntaxError("element <" + s.name.Local + "> closed by </" + name.Local + ">") - return false - case s.name.Space != name.Space: - d.err = d.syntaxError("element <" + s.name.Local + "> in space " + s.name.Space + - "closed by </" + name.Local + "> in space " + name.Space) - return false - } - - // Pop stack until a Start or EOF is on the top, undoing the - // translations that were associated with the element we just closed. - for d.stk != nil && d.stk.kind != stkStart && d.stk.kind != stkEOF { - s := d.pop() - if s.ok { - d.ns[s.name.Local] = s.name.Space - } else { - delete(d.ns, s.name.Local) - } - } - - return true -} - -// If the top element on the stack is autoclosing and -// t is not the end tag, invent the end tag. -func (d *Decoder) autoClose(t Token) (Token, bool) { - if d.stk == nil || d.stk.kind != stkStart { - return nil, false - } - name := strings.ToLower(d.stk.name.Local) - for _, s := range d.AutoClose { - if strings.ToLower(s) == name { - // This one should be auto closed if t doesn't close it. - et, ok := t.(EndElement) - if !ok || et.Name.Local != name { - return EndElement{d.stk.name}, true - } - break - } - } - return nil, false -} - -var errRawToken = errors.New("xml: cannot use RawToken from UnmarshalXML method") - -// RawToken is like Token but does not verify that -// start and end elements match and does not translate -// name space prefixes to their corresponding URLs. -func (d *Decoder) RawToken() (Token, error) { - if d.unmarshalDepth > 0 { - return nil, errRawToken - } - return d.rawToken() -} - -func (d *Decoder) rawToken() (Token, error) { - if d.err != nil { - return nil, d.err - } - if d.needClose { - // The last element we read was self-closing and - // we returned just the StartElement half. - // Return the EndElement half now. - d.needClose = false - return EndElement{d.toClose}, nil - } - - b, ok := d.getc() - if !ok { - return nil, d.err - } - - if b != '<' { - // Text section. - d.ungetc(b) - data := d.text(-1, false) - if data == nil { - return nil, d.err - } - return CharData(data), nil - } - - if b, ok = d.mustgetc(); !ok { - return nil, d.err - } - switch b { - case '/': - // </: End element - var name Name - if name, ok = d.nsname(); !ok { - if d.err == nil { - d.err = d.syntaxError("expected element name after </") - } - return nil, d.err - } - d.space() - if b, ok = d.mustgetc(); !ok { - return nil, d.err - } - if b != '>' { - d.err = d.syntaxError("invalid characters between </" + name.Local + " and >") - return nil, d.err - } - return EndElement{name}, nil - - case '?': - // <?: Processing instruction. - var target string - if target, ok = d.name(); !ok { - if d.err == nil { - d.err = d.syntaxError("expected target name after <?") - } - return nil, d.err - } - d.space() - d.buf.Reset() - var b0 byte - for { - if b, ok = d.mustgetc(); !ok { - return nil, d.err - } - d.buf.WriteByte(b) - if b0 == '?' && b == '>' { - break - } - b0 = b - } - data := d.buf.Bytes() - data = data[0 : len(data)-2] // chop ?> - - if target == "xml" { - content := string(data) - ver := procInst("version", content) - if ver != "" && ver != "1.0" { - d.err = fmt.Errorf("xml: unsupported version %q; only version 1.0 is supported", ver) - return nil, d.err - } - enc := procInst("encoding", content) - if enc != "" && enc != "utf-8" && enc != "UTF-8" { - if d.CharsetReader == nil { - d.err = fmt.Errorf("xml: encoding %q declared but Decoder.CharsetReader is nil", enc) - return nil, d.err - } - newr, err := d.CharsetReader(enc, d.r.(io.Reader)) - if err != nil { - d.err = fmt.Errorf("xml: opening charset %q: %v", enc, err) - return nil, d.err - } - if newr == nil { - panic("CharsetReader returned a nil Reader for charset " + enc) - } - d.switchToReader(newr) - } - } - return ProcInst{target, data}, nil - - case '!': - // <!: Maybe comment, maybe CDATA. - if b, ok = d.mustgetc(); !ok { - return nil, d.err - } - switch b { - case '-': // <!- - // Probably <!-- for a comment. - if b, ok = d.mustgetc(); !ok { - return nil, d.err - } - if b != '-' { - d.err = d.syntaxError("invalid sequence <!- not part of <!--") - return nil, d.err - } - // Look for terminator. - d.buf.Reset() - var b0, b1 byte - for { - if b, ok = d.mustgetc(); !ok { - return nil, d.err - } - d.buf.WriteByte(b) - if b0 == '-' && b1 == '-' && b == '>' { - break - } - b0, b1 = b1, b - } - data := d.buf.Bytes() - data = data[0 : len(data)-3] // chop --> - return Comment(data), nil - - case '[': // <![ - // Probably <![CDATA[. - for i := 0; i < 6; i++ { - if b, ok = d.mustgetc(); !ok { - return nil, d.err - } - if b != "CDATA["[i] { - d.err = d.syntaxError("invalid <![ sequence") - return nil, d.err - } - } - // Have <![CDATA[. Read text until ]]>. - data := d.text(-1, true) - if data == nil { - return nil, d.err - } - return CharData(data), nil - } - - // Probably a directive: <!DOCTYPE ...>, <!ENTITY ...>, etc. - // We don't care, but accumulate for caller. Quoted angle - // brackets do not count for nesting. - d.buf.Reset() - d.buf.WriteByte(b) - inquote := uint8(0) - depth := 0 - for { - if b, ok = d.mustgetc(); !ok { - return nil, d.err - } - if inquote == 0 && b == '>' && depth == 0 { - break - } - HandleB: - d.buf.WriteByte(b) - switch { - case b == inquote: - inquote = 0 - - case inquote != 0: - // in quotes, no special action - - case b == '\'' || b == '"': - inquote = b - - case b == '>' && inquote == 0: - depth-- - - case b == '<' && inquote == 0: - // Look for <!-- to begin comment. - s := "!--" - for i := 0; i < len(s); i++ { - if b, ok = d.mustgetc(); !ok { - return nil, d.err - } - if b != s[i] { - for j := 0; j < i; j++ { - d.buf.WriteByte(s[j]) - } - depth++ - goto HandleB - } - } - - // Remove < that was written above. - d.buf.Truncate(d.buf.Len() - 1) - - // Look for terminator. - var b0, b1 byte - for { - if b, ok = d.mustgetc(); !ok { - return nil, d.err - } - if b0 == '-' && b1 == '-' && b == '>' { - break - } - b0, b1 = b1, b - } - } - } - return Directive(d.buf.Bytes()), nil - } - - // Must be an open element like <a href="foo"> - d.ungetc(b) - - var ( - name Name - empty bool - attr []Attr - ) - if name, ok = d.nsname(); !ok { - if d.err == nil { - d.err = d.syntaxError("expected element name after <") - } - return nil, d.err - } - - attr = []Attr{} - for { - d.space() - if b, ok = d.mustgetc(); !ok { - return nil, d.err - } - if b == '/' { - empty = true - if b, ok = d.mustgetc(); !ok { - return nil, d.err - } - if b != '>' { - d.err = d.syntaxError("expected /> in element") - return nil, d.err - } - break - } - if b == '>' { - break - } - d.ungetc(b) - - n := len(attr) - if n >= cap(attr) { - nCap := 2 * cap(attr) - if nCap == 0 { - nCap = 4 - } - nattr := make([]Attr, n, nCap) - copy(nattr, attr) - attr = nattr - } - attr = attr[0 : n+1] - a := &attr[n] - if a.Name, ok = d.nsname(); !ok { - if d.err == nil { - d.err = d.syntaxError("expected attribute name in element") - } - return nil, d.err - } - d.space() - if b, ok = d.mustgetc(); !ok { - return nil, d.err - } - if b != '=' { - if d.Strict { - d.err = d.syntaxError("attribute name without = in element") - return nil, d.err - } else { - d.ungetc(b) - a.Value = a.Name.Local - } - } else { - d.space() - data := d.attrval() - if data == nil { - return nil, d.err - } - a.Value = string(data) - } - } - if empty { - d.needClose = true - d.toClose = name - } - return StartElement{name, attr}, nil -} - -func (d *Decoder) attrval() []byte { - b, ok := d.mustgetc() - if !ok { - return nil - } - // Handle quoted attribute values - if b == '"' || b == '\'' { - return d.text(int(b), false) - } - // Handle unquoted attribute values for strict parsers - if d.Strict { - d.err = d.syntaxError("unquoted or missing attribute value in element") - return nil - } - // Handle unquoted attribute values for unstrict parsers - d.ungetc(b) - d.buf.Reset() - for { - b, ok = d.mustgetc() - if !ok { - return nil - } - // http://www.w3.org/TR/REC-html40/intro/sgmltut.html#h-3.2.2 - if 'a' <= b && b <= 'z' || 'A' <= b && b <= 'Z' || - '0' <= b && b <= '9' || b == '_' || b == ':' || b == '-' { - d.buf.WriteByte(b) - } else { - d.ungetc(b) - break - } - } - return d.buf.Bytes() -} - -// Skip spaces if any -func (d *Decoder) space() { - for { - b, ok := d.getc() - if !ok { - return - } - switch b { - case ' ', '\r', '\n', '\t': - default: - d.ungetc(b) - return - } - } -} - -// Read a single byte. -// If there is no byte to read, return ok==false -// and leave the error in d.err. -// Maintain line number. -func (d *Decoder) getc() (b byte, ok bool) { - if d.err != nil { - return 0, false - } - if d.nextByte >= 0 { - b = byte(d.nextByte) - d.nextByte = -1 - } else { - b, d.err = d.r.ReadByte() - if d.err != nil { - return 0, false - } - if d.saved != nil { - d.saved.WriteByte(b) - } - } - if b == '\n' { - d.line++ - } - d.offset++ - return b, true -} - -// InputOffset returns the input stream byte offset of the current decoder position. -// The offset gives the location of the end of the most recently returned token -// and the beginning of the next token. -func (d *Decoder) InputOffset() int64 { - return d.offset -} - -// Return saved offset. -// If we did ungetc (nextByte >= 0), have to back up one. -func (d *Decoder) savedOffset() int { - n := d.saved.Len() - if d.nextByte >= 0 { - n-- - } - return n -} - -// Must read a single byte. -// If there is no byte to read, -// set d.err to SyntaxError("unexpected EOF") -// and return ok==false -func (d *Decoder) mustgetc() (b byte, ok bool) { - if b, ok = d.getc(); !ok { - if d.err == io.EOF { - d.err = d.syntaxError("unexpected EOF") - } - } - return -} - -// Unread a single byte. -func (d *Decoder) ungetc(b byte) { - if b == '\n' { - d.line-- - } - d.nextByte = int(b) - d.offset-- -} - -var entity = map[string]int{ - "lt": '<', - "gt": '>', - "amp": '&', - "apos": '\'', - "quot": '"', -} - -// Read plain text section (XML calls it character data). -// If quote >= 0, we are in a quoted string and need to find the matching quote. -// If cdata == true, we are in a <![CDATA[ section and need to find ]]>. -// On failure return nil and leave the error in d.err. -func (d *Decoder) text(quote int, cdata bool) []byte { - var b0, b1 byte - var trunc int - d.buf.Reset() -Input: - for { - b, ok := d.getc() - if !ok { - if cdata { - if d.err == io.EOF { - d.err = d.syntaxError("unexpected EOF in CDATA section") - } - return nil - } - break Input - } - - // <![CDATA[ section ends with ]]>. - // It is an error for ]]> to appear in ordinary text. - if b0 == ']' && b1 == ']' && b == '>' { - if cdata { - trunc = 2 - break Input - } - d.err = d.syntaxError("unescaped ]]> not in CDATA section") - return nil - } - - // Stop reading text if we see a <. - if b == '<' && !cdata { - if quote >= 0 { - d.err = d.syntaxError("unescaped < inside quoted string") - return nil - } - d.ungetc('<') - break Input - } - if quote >= 0 && b == byte(quote) { - break Input - } - if b == '&' && !cdata { - // Read escaped character expression up to semicolon. - // XML in all its glory allows a document to define and use - // its own character names with <!ENTITY ...> directives. - // Parsers are required to recognize lt, gt, amp, apos, and quot - // even if they have not been declared. - before := d.buf.Len() - d.buf.WriteByte('&') - var ok bool - var text string - var haveText bool - if b, ok = d.mustgetc(); !ok { - return nil - } - if b == '#' { - d.buf.WriteByte(b) - if b, ok = d.mustgetc(); !ok { - return nil - } - base := 10 - if b == 'x' { - base = 16 - d.buf.WriteByte(b) - if b, ok = d.mustgetc(); !ok { - return nil - } - } - start := d.buf.Len() - for '0' <= b && b <= '9' || - base == 16 && 'a' <= b && b <= 'f' || - base == 16 && 'A' <= b && b <= 'F' { - d.buf.WriteByte(b) - if b, ok = d.mustgetc(); !ok { - return nil - } - } - if b != ';' { - d.ungetc(b) - } else { - s := string(d.buf.Bytes()[start:]) - d.buf.WriteByte(';') - n, err := strconv.ParseUint(s, base, 64) - if err == nil && n <= unicode.MaxRune { - text = string(n) - haveText = true - } - } - } else { - d.ungetc(b) - if !d.readName() { - if d.err != nil { - return nil - } - ok = false - } - if b, ok = d.mustgetc(); !ok { - return nil - } - if b != ';' { - d.ungetc(b) - } else { - name := d.buf.Bytes()[before+1:] - d.buf.WriteByte(';') - if isName(name) { - s := string(name) - if r, ok := entity[s]; ok { - text = string(r) - haveText = true - } else if d.Entity != nil { - text, haveText = d.Entity[s] - } - } - } - } - - if haveText { - d.buf.Truncate(before) - d.buf.Write([]byte(text)) - b0, b1 = 0, 0 - continue Input - } - if !d.Strict { - b0, b1 = 0, 0 - continue Input - } - ent := string(d.buf.Bytes()[before:]) - if ent[len(ent)-1] != ';' { - ent += " (no semicolon)" - } - d.err = d.syntaxError("invalid character entity " + ent) - return nil - } - - // We must rewrite unescaped \r and \r\n into \n. - if b == '\r' { - d.buf.WriteByte('\n') - } else if b1 == '\r' && b == '\n' { - // Skip \r\n--we already wrote \n. - } else { - d.buf.WriteByte(b) - } - - b0, b1 = b1, b - } - data := d.buf.Bytes() - data = data[0 : len(data)-trunc] - - // Inspect each rune for being a disallowed character. - buf := data - for len(buf) > 0 { - r, size := utf8.DecodeRune(buf) - if r == utf8.RuneError && size == 1 { - d.err = d.syntaxError("invalid UTF-8") - return nil - } - buf = buf[size:] - if !isInCharacterRange(r) { - d.err = d.syntaxError(fmt.Sprintf("illegal character code %U", r)) - return nil - } - } - - return data -} - -// Decide whether the given rune is in the XML Character Range, per -// the Char production of http://www.xml.com/axml/testaxml.htm, -// Section 2.2 Characters. -func isInCharacterRange(r rune) (inrange bool) { - return r == 0x09 || - r == 0x0A || - r == 0x0D || - r >= 0x20 && r <= 0xDF77 || - r >= 0xE000 && r <= 0xFFFD || - r >= 0x10000 && r <= 0x10FFFF -} - -// Get name space name: name with a : stuck in the middle. -// The part before the : is the name space identifier. -func (d *Decoder) nsname() (name Name, ok bool) { - s, ok := d.name() - if !ok { - return - } - i := strings.Index(s, ":") - if i < 0 { - name.Local = s - } else { - name.Space = s[0:i] - name.Local = s[i+1:] - } - return name, true -} - -// Get name: /first(first|second)*/ -// Do not set d.err if the name is missing (unless unexpected EOF is received): -// let the caller provide better context. -func (d *Decoder) name() (s string, ok bool) { - d.buf.Reset() - if !d.readName() { - return "", false - } - - // Now we check the characters. - b := d.buf.Bytes() - if !isName(b) { - d.err = d.syntaxError("invalid XML name: " + string(b)) - return "", false - } - return string(b), true -} - -// Read a name and append its bytes to d.buf. -// The name is delimited by any single-byte character not valid in names. -// All multi-byte characters are accepted; the caller must check their validity. -func (d *Decoder) readName() (ok bool) { - var b byte - if b, ok = d.mustgetc(); !ok { - return - } - if b < utf8.RuneSelf && !isNameByte(b) { - d.ungetc(b) - return false - } - d.buf.WriteByte(b) - - for { - if b, ok = d.mustgetc(); !ok { - return - } - if b < utf8.RuneSelf && !isNameByte(b) { - d.ungetc(b) - break - } - d.buf.WriteByte(b) - } - return true -} - -func isNameByte(c byte) bool { - return 'A' <= c && c <= 'Z' || - 'a' <= c && c <= 'z' || - '0' <= c && c <= '9' || - c == '_' || c == ':' || c == '.' || c == '-' -} - -func isName(s []byte) bool { - if len(s) == 0 { - return false - } - c, n := utf8.DecodeRune(s) - if c == utf8.RuneError && n == 1 { - return false - } - if !unicode.Is(first, c) { - return false - } - for n < len(s) { - s = s[n:] - c, n = utf8.DecodeRune(s) - if c == utf8.RuneError && n == 1 { - return false - } - if !unicode.Is(first, c) && !unicode.Is(second, c) { - return false - } - } - return true -} - -func isNameString(s string) bool { - if len(s) == 0 { - return false - } - c, n := utf8.DecodeRuneInString(s) - if c == utf8.RuneError && n == 1 { - return false - } - if !unicode.Is(first, c) { - return false - } - for n < len(s) { - s = s[n:] - c, n = utf8.DecodeRuneInString(s) - if c == utf8.RuneError && n == 1 { - return false - } - if !unicode.Is(first, c) && !unicode.Is(second, c) { - return false - } - } - return true -} - -// These tables were generated by cut and paste from Appendix B of -// the XML spec at http://www.xml.com/axml/testaxml.htm -// and then reformatting. First corresponds to (Letter | '_' | ':') -// and second corresponds to NameChar. - -var first = &unicode.RangeTable{ - R16: []unicode.Range16{ - {0x003A, 0x003A, 1}, - {0x0041, 0x005A, 1}, - {0x005F, 0x005F, 1}, - {0x0061, 0x007A, 1}, - {0x00C0, 0x00D6, 1}, - {0x00D8, 0x00F6, 1}, - {0x00F8, 0x00FF, 1}, - {0x0100, 0x0131, 1}, - {0x0134, 0x013E, 1}, - {0x0141, 0x0148, 1}, - {0x014A, 0x017E, 1}, - {0x0180, 0x01C3, 1}, - {0x01CD, 0x01F0, 1}, - {0x01F4, 0x01F5, 1}, - {0x01FA, 0x0217, 1}, - {0x0250, 0x02A8, 1}, - {0x02BB, 0x02C1, 1}, - {0x0386, 0x0386, 1}, - {0x0388, 0x038A, 1}, - {0x038C, 0x038C, 1}, - {0x038E, 0x03A1, 1}, - {0x03A3, 0x03CE, 1}, - {0x03D0, 0x03D6, 1}, - {0x03DA, 0x03E0, 2}, - {0x03E2, 0x03F3, 1}, - {0x0401, 0x040C, 1}, - {0x040E, 0x044F, 1}, - {0x0451, 0x045C, 1}, - {0x045E, 0x0481, 1}, - {0x0490, 0x04C4, 1}, - {0x04C7, 0x04C8, 1}, - {0x04CB, 0x04CC, 1}, - {0x04D0, 0x04EB, 1}, - {0x04EE, 0x04F5, 1}, - {0x04F8, 0x04F9, 1}, - {0x0531, 0x0556, 1}, - {0x0559, 0x0559, 1}, - {0x0561, 0x0586, 1}, - {0x05D0, 0x05EA, 1}, - {0x05F0, 0x05F2, 1}, - {0x0621, 0x063A, 1}, - {0x0641, 0x064A, 1}, - {0x0671, 0x06B7, 1}, - {0x06BA, 0x06BE, 1}, - {0x06C0, 0x06CE, 1}, - {0x06D0, 0x06D3, 1}, - {0x06D5, 0x06D5, 1}, - {0x06E5, 0x06E6, 1}, - {0x0905, 0x0939, 1}, - {0x093D, 0x093D, 1}, - {0x0958, 0x0961, 1}, - {0x0985, 0x098C, 1}, - {0x098F, 0x0990, 1}, - {0x0993, 0x09A8, 1}, - {0x09AA, 0x09B0, 1}, - {0x09B2, 0x09B2, 1}, - {0x09B6, 0x09B9, 1}, - {0x09DC, 0x09DD, 1}, - {0x09DF, 0x09E1, 1}, - {0x09F0, 0x09F1, 1}, - {0x0A05, 0x0A0A, 1}, - {0x0A0F, 0x0A10, 1}, - {0x0A13, 0x0A28, 1}, - {0x0A2A, 0x0A30, 1}, - {0x0A32, 0x0A33, 1}, - {0x0A35, 0x0A36, 1}, - {0x0A38, 0x0A39, 1}, - {0x0A59, 0x0A5C, 1}, - {0x0A5E, 0x0A5E, 1}, - {0x0A72, 0x0A74, 1}, - {0x0A85, 0x0A8B, 1}, - {0x0A8D, 0x0A8D, 1}, - {0x0A8F, 0x0A91, 1}, - {0x0A93, 0x0AA8, 1}, - {0x0AAA, 0x0AB0, 1}, - {0x0AB2, 0x0AB3, 1}, - {0x0AB5, 0x0AB9, 1}, - {0x0ABD, 0x0AE0, 0x23}, - {0x0B05, 0x0B0C, 1}, - {0x0B0F, 0x0B10, 1}, - {0x0B13, 0x0B28, 1}, - {0x0B2A, 0x0B30, 1}, - {0x0B32, 0x0B33, 1}, - {0x0B36, 0x0B39, 1}, - {0x0B3D, 0x0B3D, 1}, - {0x0B5C, 0x0B5D, 1}, - {0x0B5F, 0x0B61, 1}, - {0x0B85, 0x0B8A, 1}, - {0x0B8E, 0x0B90, 1}, - {0x0B92, 0x0B95, 1}, - {0x0B99, 0x0B9A, 1}, - {0x0B9C, 0x0B9C, 1}, - {0x0B9E, 0x0B9F, 1}, - {0x0BA3, 0x0BA4, 1}, - {0x0BA8, 0x0BAA, 1}, - {0x0BAE, 0x0BB5, 1}, - {0x0BB7, 0x0BB9, 1}, - {0x0C05, 0x0C0C, 1}, - {0x0C0E, 0x0C10, 1}, - {0x0C12, 0x0C28, 1}, - {0x0C2A, 0x0C33, 1}, - {0x0C35, 0x0C39, 1}, - {0x0C60, 0x0C61, 1}, - {0x0C85, 0x0C8C, 1}, - {0x0C8E, 0x0C90, 1}, - {0x0C92, 0x0CA8, 1}, - {0x0CAA, 0x0CB3, 1}, - {0x0CB5, 0x0CB9, 1}, - {0x0CDE, 0x0CDE, 1}, - {0x0CE0, 0x0CE1, 1}, - {0x0D05, 0x0D0C, 1}, - {0x0D0E, 0x0D10, 1}, - {0x0D12, 0x0D28, 1}, - {0x0D2A, 0x0D39, 1}, - {0x0D60, 0x0D61, 1}, - {0x0E01, 0x0E2E, 1}, - {0x0E30, 0x0E30, 1}, - {0x0E32, 0x0E33, 1}, - {0x0E40, 0x0E45, 1}, - {0x0E81, 0x0E82, 1}, - {0x0E84, 0x0E84, 1}, - {0x0E87, 0x0E88, 1}, - {0x0E8A, 0x0E8D, 3}, - {0x0E94, 0x0E97, 1}, - {0x0E99, 0x0E9F, 1}, - {0x0EA1, 0x0EA3, 1}, - {0x0EA5, 0x0EA7, 2}, - {0x0EAA, 0x0EAB, 1}, - {0x0EAD, 0x0EAE, 1}, - {0x0EB0, 0x0EB0, 1}, - {0x0EB2, 0x0EB3, 1}, - {0x0EBD, 0x0EBD, 1}, - {0x0EC0, 0x0EC4, 1}, - {0x0F40, 0x0F47, 1}, - {0x0F49, 0x0F69, 1}, - {0x10A0, 0x10C5, 1}, - {0x10D0, 0x10F6, 1}, - {0x1100, 0x1100, 1}, - {0x1102, 0x1103, 1}, - {0x1105, 0x1107, 1}, - {0x1109, 0x1109, 1}, - {0x110B, 0x110C, 1}, - {0x110E, 0x1112, 1}, - {0x113C, 0x1140, 2}, - {0x114C, 0x1150, 2}, - {0x1154, 0x1155, 1}, - {0x1159, 0x1159, 1}, - {0x115F, 0x1161, 1}, - {0x1163, 0x1169, 2}, - {0x116D, 0x116E, 1}, - {0x1172, 0x1173, 1}, - {0x1175, 0x119E, 0x119E - 0x1175}, - {0x11A8, 0x11AB, 0x11AB - 0x11A8}, - {0x11AE, 0x11AF, 1}, - {0x11B7, 0x11B8, 1}, - {0x11BA, 0x11BA, 1}, - {0x11BC, 0x11C2, 1}, - {0x11EB, 0x11F0, 0x11F0 - 0x11EB}, - {0x11F9, 0x11F9, 1}, - {0x1E00, 0x1E9B, 1}, - {0x1EA0, 0x1EF9, 1}, - {0x1F00, 0x1F15, 1}, - {0x1F18, 0x1F1D, 1}, - {0x1F20, 0x1F45, 1}, - {0x1F48, 0x1F4D, 1}, - {0x1F50, 0x1F57, 1}, - {0x1F59, 0x1F5B, 0x1F5B - 0x1F59}, - {0x1F5D, 0x1F5D, 1}, - {0x1F5F, 0x1F7D, 1}, - {0x1F80, 0x1FB4, 1}, - {0x1FB6, 0x1FBC, 1}, - {0x1FBE, 0x1FBE, 1}, - {0x1FC2, 0x1FC4, 1}, - {0x1FC6, 0x1FCC, 1}, - {0x1FD0, 0x1FD3, 1}, - {0x1FD6, 0x1FDB, 1}, - {0x1FE0, 0x1FEC, 1}, - {0x1FF2, 0x1FF4, 1}, - {0x1FF6, 0x1FFC, 1}, - {0x2126, 0x2126, 1}, - {0x212A, 0x212B, 1}, - {0x212E, 0x212E, 1}, - {0x2180, 0x2182, 1}, - {0x3007, 0x3007, 1}, - {0x3021, 0x3029, 1}, - {0x3041, 0x3094, 1}, - {0x30A1, 0x30FA, 1}, - {0x3105, 0x312C, 1}, - {0x4E00, 0x9FA5, 1}, - {0xAC00, 0xD7A3, 1}, - }, -} - -var second = &unicode.RangeTable{ - R16: []unicode.Range16{ - {0x002D, 0x002E, 1}, - {0x0030, 0x0039, 1}, - {0x00B7, 0x00B7, 1}, - {0x02D0, 0x02D1, 1}, - {0x0300, 0x0345, 1}, - {0x0360, 0x0361, 1}, - {0x0387, 0x0387, 1}, - {0x0483, 0x0486, 1}, - {0x0591, 0x05A1, 1}, - {0x05A3, 0x05B9, 1}, - {0x05BB, 0x05BD, 1}, - {0x05BF, 0x05BF, 1}, - {0x05C1, 0x05C2, 1}, - {0x05C4, 0x0640, 0x0640 - 0x05C4}, - {0x064B, 0x0652, 1}, - {0x0660, 0x0669, 1}, - {0x0670, 0x0670, 1}, - {0x06D6, 0x06DC, 1}, - {0x06DD, 0x06DF, 1}, - {0x06E0, 0x06E4, 1}, - {0x06E7, 0x06E8, 1}, - {0x06EA, 0x06ED, 1}, - {0x06F0, 0x06F9, 1}, - {0x0901, 0x0903, 1}, - {0x093C, 0x093C, 1}, - {0x093E, 0x094C, 1}, - {0x094D, 0x094D, 1}, - {0x0951, 0x0954, 1}, - {0x0962, 0x0963, 1}, - {0x0966, 0x096F, 1}, - {0x0981, 0x0983, 1}, - {0x09BC, 0x09BC, 1}, - {0x09BE, 0x09BF, 1}, - {0x09C0, 0x09C4, 1}, - {0x09C7, 0x09C8, 1}, - {0x09CB, 0x09CD, 1}, - {0x09D7, 0x09D7, 1}, - {0x09E2, 0x09E3, 1}, - {0x09E6, 0x09EF, 1}, - {0x0A02, 0x0A3C, 0x3A}, - {0x0A3E, 0x0A3F, 1}, - {0x0A40, 0x0A42, 1}, - {0x0A47, 0x0A48, 1}, - {0x0A4B, 0x0A4D, 1}, - {0x0A66, 0x0A6F, 1}, - {0x0A70, 0x0A71, 1}, - {0x0A81, 0x0A83, 1}, - {0x0ABC, 0x0ABC, 1}, - {0x0ABE, 0x0AC5, 1}, - {0x0AC7, 0x0AC9, 1}, - {0x0ACB, 0x0ACD, 1}, - {0x0AE6, 0x0AEF, 1}, - {0x0B01, 0x0B03, 1}, - {0x0B3C, 0x0B3C, 1}, - {0x0B3E, 0x0B43, 1}, - {0x0B47, 0x0B48, 1}, - {0x0B4B, 0x0B4D, 1}, - {0x0B56, 0x0B57, 1}, - {0x0B66, 0x0B6F, 1}, - {0x0B82, 0x0B83, 1}, - {0x0BBE, 0x0BC2, 1}, - {0x0BC6, 0x0BC8, 1}, - {0x0BCA, 0x0BCD, 1}, - {0x0BD7, 0x0BD7, 1}, - {0x0BE7, 0x0BEF, 1}, - {0x0C01, 0x0C03, 1}, - {0x0C3E, 0x0C44, 1}, - {0x0C46, 0x0C48, 1}, - {0x0C4A, 0x0C4D, 1}, - {0x0C55, 0x0C56, 1}, - {0x0C66, 0x0C6F, 1}, - {0x0C82, 0x0C83, 1}, - {0x0CBE, 0x0CC4, 1}, - {0x0CC6, 0x0CC8, 1}, - {0x0CCA, 0x0CCD, 1}, - {0x0CD5, 0x0CD6, 1}, - {0x0CE6, 0x0CEF, 1}, - {0x0D02, 0x0D03, 1}, - {0x0D3E, 0x0D43, 1}, - {0x0D46, 0x0D48, 1}, - {0x0D4A, 0x0D4D, 1}, - {0x0D57, 0x0D57, 1}, - {0x0D66, 0x0D6F, 1}, - {0x0E31, 0x0E31, 1}, - {0x0E34, 0x0E3A, 1}, - {0x0E46, 0x0E46, 1}, - {0x0E47, 0x0E4E, 1}, - {0x0E50, 0x0E59, 1}, - {0x0EB1, 0x0EB1, 1}, - {0x0EB4, 0x0EB9, 1}, - {0x0EBB, 0x0EBC, 1}, - {0x0EC6, 0x0EC6, 1}, - {0x0EC8, 0x0ECD, 1}, - {0x0ED0, 0x0ED9, 1}, - {0x0F18, 0x0F19, 1}, - {0x0F20, 0x0F29, 1}, - {0x0F35, 0x0F39, 2}, - {0x0F3E, 0x0F3F, 1}, - {0x0F71, 0x0F84, 1}, - {0x0F86, 0x0F8B, 1}, - {0x0F90, 0x0F95, 1}, - {0x0F97, 0x0F97, 1}, - {0x0F99, 0x0FAD, 1}, - {0x0FB1, 0x0FB7, 1}, - {0x0FB9, 0x0FB9, 1}, - {0x20D0, 0x20DC, 1}, - {0x20E1, 0x3005, 0x3005 - 0x20E1}, - {0x302A, 0x302F, 1}, - {0x3031, 0x3035, 1}, - {0x3099, 0x309A, 1}, - {0x309D, 0x309E, 1}, - {0x30FC, 0x30FE, 1}, - }, -} - -// HTMLEntity is an entity map containing translations for the -// standard HTML entity characters. -var HTMLEntity = htmlEntity - -var htmlEntity = map[string]string{ - /* - hget http://www.w3.org/TR/html4/sgml/entities.html | - ssam ' - ,y /\>/ x/\<(.|\n)+/ s/\n/ /g - ,x v/^\<!ENTITY/d - ,s/\<!ENTITY ([^ ]+) .*U\+([0-9A-F][0-9A-F][0-9A-F][0-9A-F]) .+/ "\1": "\\u\2",/g - ' - */ - "nbsp": "\u00A0", - "iexcl": "\u00A1", - "cent": "\u00A2", - "pound": "\u00A3", - "curren": "\u00A4", - "yen": "\u00A5", - "brvbar": "\u00A6", - "sect": "\u00A7", - "uml": "\u00A8", - "copy": "\u00A9", - "ordf": "\u00AA", - "laquo": "\u00AB", - "not": "\u00AC", - "shy": "\u00AD", - "reg": "\u00AE", - "macr": "\u00AF", - "deg": "\u00B0", - "plusmn": "\u00B1", - "sup2": "\u00B2", - "sup3": "\u00B3", - "acute": "\u00B4", - "micro": "\u00B5", - "para": "\u00B6", - "middot": "\u00B7", - "cedil": "\u00B8", - "sup1": "\u00B9", - "ordm": "\u00BA", - "raquo": "\u00BB", - "frac14": "\u00BC", - "frac12": "\u00BD", - "frac34": "\u00BE", - "iquest": "\u00BF", - "Agrave": "\u00C0", - "Aacute": "\u00C1", - "Acirc": "\u00C2", - "Atilde": "\u00C3", - "Auml": "\u00C4", - "Aring": "\u00C5", - "AElig": "\u00C6", - "Ccedil": "\u00C7", - "Egrave": "\u00C8", - "Eacute": "\u00C9", - "Ecirc": "\u00CA", - "Euml": "\u00CB", - "Igrave": "\u00CC", - "Iacute": "\u00CD", - "Icirc": "\u00CE", - "Iuml": "\u00CF", - "ETH": "\u00D0", - "Ntilde": "\u00D1", - "Ograve": "\u00D2", - "Oacute": "\u00D3", - "Ocirc": "\u00D4", - "Otilde": "\u00D5", - "Ouml": "\u00D6", - "times": "\u00D7", - "Oslash": "\u00D8", - "Ugrave": "\u00D9", - "Uacute": "\u00DA", - "Ucirc": "\u00DB", - "Uuml": "\u00DC", - "Yacute": "\u00DD", - "THORN": "\u00DE", - "szlig": "\u00DF", - "agrave": "\u00E0", - "aacute": "\u00E1", - "acirc": "\u00E2", - "atilde": "\u00E3", - "auml": "\u00E4", - "aring": "\u00E5", - "aelig": "\u00E6", - "ccedil": "\u00E7", - "egrave": "\u00E8", - "eacute": "\u00E9", - "ecirc": "\u00EA", - "euml": "\u00EB", - "igrave": "\u00EC", - "iacute": "\u00ED", - "icirc": "\u00EE", - "iuml": "\u00EF", - "eth": "\u00F0", - "ntilde": "\u00F1", - "ograve": "\u00F2", - "oacute": "\u00F3", - "ocirc": "\u00F4", - "otilde": "\u00F5", - "ouml": "\u00F6", - "divide": "\u00F7", - "oslash": "\u00F8", - "ugrave": "\u00F9", - "uacute": "\u00FA", - "ucirc": "\u00FB", - "uuml": "\u00FC", - "yacute": "\u00FD", - "thorn": "\u00FE", - "yuml": "\u00FF", - "fnof": "\u0192", - "Alpha": "\u0391", - "Beta": "\u0392", - "Gamma": "\u0393", - "Delta": "\u0394", - "Epsilon": "\u0395", - "Zeta": "\u0396", - "Eta": "\u0397", - "Theta": "\u0398", - "Iota": "\u0399", - "Kappa": "\u039A", - "Lambda": "\u039B", - "Mu": "\u039C", - "Nu": "\u039D", - "Xi": "\u039E", - "Omicron": "\u039F", - "Pi": "\u03A0", - "Rho": "\u03A1", - "Sigma": "\u03A3", - "Tau": "\u03A4", - "Upsilon": "\u03A5", - "Phi": "\u03A6", - "Chi": "\u03A7", - "Psi": "\u03A8", - "Omega": "\u03A9", - "alpha": "\u03B1", - "beta": "\u03B2", - "gamma": "\u03B3", - "delta": "\u03B4", - "epsilon": "\u03B5", - "zeta": "\u03B6", - "eta": "\u03B7", - "theta": "\u03B8", - "iota": "\u03B9", - "kappa": "\u03BA", - "lambda": "\u03BB", - "mu": "\u03BC", - "nu": "\u03BD", - "xi": "\u03BE", - "omicron": "\u03BF", - "pi": "\u03C0", - "rho": "\u03C1", - "sigmaf": "\u03C2", - "sigma": "\u03C3", - "tau": "\u03C4", - "upsilon": "\u03C5", - "phi": "\u03C6", - "chi": "\u03C7", - "psi": "\u03C8", - "omega": "\u03C9", - "thetasym": "\u03D1", - "upsih": "\u03D2", - "piv": "\u03D6", - "bull": "\u2022", - "hellip": "\u2026", - "prime": "\u2032", - "Prime": "\u2033", - "oline": "\u203E", - "frasl": "\u2044", - "weierp": "\u2118", - "image": "\u2111", - "real": "\u211C", - "trade": "\u2122", - "alefsym": "\u2135", - "larr": "\u2190", - "uarr": "\u2191", - "rarr": "\u2192", - "darr": "\u2193", - "harr": "\u2194", - "crarr": "\u21B5", - "lArr": "\u21D0", - "uArr": "\u21D1", - "rArr": "\u21D2", - "dArr": "\u21D3", - "hArr": "\u21D4", - "forall": "\u2200", - "part": "\u2202", - "exist": "\u2203", - "empty": "\u2205", - "nabla": "\u2207", - "isin": "\u2208", - "notin": "\u2209", - "ni": "\u220B", - "prod": "\u220F", - "sum": "\u2211", - "minus": "\u2212", - "lowast": "\u2217", - "radic": "\u221A", - "prop": "\u221D", - "infin": "\u221E", - "ang": "\u2220", - "and": "\u2227", - "or": "\u2228", - "cap": "\u2229", - "cup": "\u222A", - "int": "\u222B", - "there4": "\u2234", - "sim": "\u223C", - "cong": "\u2245", - "asymp": "\u2248", - "ne": "\u2260", - "equiv": "\u2261", - "le": "\u2264", - "ge": "\u2265", - "sub": "\u2282", - "sup": "\u2283", - "nsub": "\u2284", - "sube": "\u2286", - "supe": "\u2287", - "oplus": "\u2295", - "otimes": "\u2297", - "perp": "\u22A5", - "sdot": "\u22C5", - "lceil": "\u2308", - "rceil": "\u2309", - "lfloor": "\u230A", - "rfloor": "\u230B", - "lang": "\u2329", - "rang": "\u232A", - "loz": "\u25CA", - "spades": "\u2660", - "clubs": "\u2663", - "hearts": "\u2665", - "diams": "\u2666", - "quot": "\u0022", - "amp": "\u0026", - "lt": "\u003C", - "gt": "\u003E", - "OElig": "\u0152", - "oelig": "\u0153", - "Scaron": "\u0160", - "scaron": "\u0161", - "Yuml": "\u0178", - "circ": "\u02C6", - "tilde": "\u02DC", - "ensp": "\u2002", - "emsp": "\u2003", - "thinsp": "\u2009", - "zwnj": "\u200C", - "zwj": "\u200D", - "lrm": "\u200E", - "rlm": "\u200F", - "ndash": "\u2013", - "mdash": "\u2014", - "lsquo": "\u2018", - "rsquo": "\u2019", - "sbquo": "\u201A", - "ldquo": "\u201C", - "rdquo": "\u201D", - "bdquo": "\u201E", - "dagger": "\u2020", - "Dagger": "\u2021", - "permil": "\u2030", - "lsaquo": "\u2039", - "rsaquo": "\u203A", - "euro": "\u20AC", -} - -// HTMLAutoClose is the set of HTML elements that -// should be considered to close automatically. -var HTMLAutoClose = htmlAutoClose - -var htmlAutoClose = []string{ - /* - hget http://www.w3.org/TR/html4/loose.dtd | - 9 sed -n 's/<!ELEMENT ([^ ]*) +- O EMPTY.+/ "\1",/p' | tr A-Z a-z - */ - "basefont", - "br", - "area", - "link", - "img", - "param", - "hr", - "input", - "col", - "frame", - "isindex", - "base", - "meta", -} - -var ( - esc_quot = []byte(""") // shorter than """ - esc_apos = []byte("'") // shorter than "'" - esc_amp = []byte("&") - esc_lt = []byte("<") - esc_gt = []byte(">") - esc_tab = []byte("	") - esc_nl = []byte("
") - esc_cr = []byte("
") - esc_fffd = []byte("\uFFFD") // Unicode replacement character -) - -// EscapeText writes to w the properly escaped XML equivalent -// of the plain text data s. -func EscapeText(w io.Writer, s []byte) error { - return escapeText(w, s, true) -} - -// escapeText writes to w the properly escaped XML equivalent -// of the plain text data s. If escapeNewline is true, newline -// characters will be escaped. -func escapeText(w io.Writer, s []byte, escapeNewline bool) error { - var esc []byte - last := 0 - for i := 0; i < len(s); { - r, width := utf8.DecodeRune(s[i:]) - i += width - switch r { - case '"': - esc = esc_quot - case '\'': - esc = esc_apos - case '&': - esc = esc_amp - case '<': - esc = esc_lt - case '>': - esc = esc_gt - case '\t': - esc = esc_tab - case '\n': - if !escapeNewline { - continue - } - esc = esc_nl - case '\r': - esc = esc_cr - default: - if !isInCharacterRange(r) || (r == 0xFFFD && width == 1) { - esc = esc_fffd - break - } - continue - } - if _, err := w.Write(s[last : i-width]); err != nil { - return err - } - if _, err := w.Write(esc); err != nil { - return err - } - last = i - } - if _, err := w.Write(s[last:]); err != nil { - return err - } - return nil -} - -// EscapeString writes to p the properly escaped XML equivalent -// of the plain text data s. -func (p *printer) EscapeString(s string) { - var esc []byte - last := 0 - for i := 0; i < len(s); { - r, width := utf8.DecodeRuneInString(s[i:]) - i += width - switch r { - case '"': - esc = esc_quot - case '\'': - esc = esc_apos - case '&': - esc = esc_amp - case '<': - esc = esc_lt - case '>': - esc = esc_gt - case '\t': - esc = esc_tab - case '\n': - esc = esc_nl - case '\r': - esc = esc_cr - default: - if !isInCharacterRange(r) || (r == 0xFFFD && width == 1) { - esc = esc_fffd - break - } - continue - } - p.WriteString(s[last : i-width]) - p.Write(esc) - last = i - } - p.WriteString(s[last:]) -} - -// Escape is like EscapeText but omits the error return value. -// It is provided for backwards compatibility with Go 1.0. -// Code targeting Go 1.1 or later should use EscapeText. -func Escape(w io.Writer, s []byte) { - EscapeText(w, s) -} - -// procInst parses the `param="..."` or `param='...'` -// value out of the provided string, returning "" if not found. -func procInst(param, s string) string { - // TODO: this parsing is somewhat lame and not exact. - // It works for all actual cases, though. - param = param + "=" - idx := strings.Index(s, param) - if idx == -1 { - return "" - } - v := s[idx+len(param):] - if v == "" { - return "" - } - if v[0] != '\'' && v[0] != '"' { - return "" - } - idx = strings.IndexRune(v[1:], rune(v[0])) - if idx == -1 { - return "" - } - return v[1 : idx+1] -} diff --git a/vendor/golang.org/x/net/webdav/internal/xml/xml_test.go b/vendor/golang.org/x/net/webdav/internal/xml/xml_test.go deleted file mode 100644 index af4cf8ea8..000000000 --- a/vendor/golang.org/x/net/webdav/internal/xml/xml_test.go +++ /dev/null @@ -1,752 +0,0 @@ -// Copyright 2009 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 - -import ( - "bytes" - "fmt" - "io" - "reflect" - "strings" - "testing" - "unicode/utf8" -) - -const testInput = ` -<?xml version="1.0" encoding="UTF-8"?> -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> -<body xmlns:foo="ns1" xmlns="ns2" xmlns:tag="ns3" ` + - "\r\n\t" + ` > - <hello lang="en">World <>'" 白鵬翔</hello> - <query>&何; &is-it;</query> - <goodbye /> - <outer foo:attr="value" xmlns:tag="ns4"> - <inner/> - </outer> - <tag:name> - <![CDATA[Some text here.]]> - </tag:name> -</body><!-- missing final newline -->` - -var testEntity = map[string]string{"何": "What", "is-it": "is it?"} - -var rawTokens = []Token{ - CharData("\n"), - ProcInst{"xml", []byte(`version="1.0" encoding="UTF-8"`)}, - CharData("\n"), - Directive(`DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"`), - CharData("\n"), - StartElement{Name{"", "body"}, []Attr{{Name{"xmlns", "foo"}, "ns1"}, {Name{"", "xmlns"}, "ns2"}, {Name{"xmlns", "tag"}, "ns3"}}}, - CharData("\n "), - StartElement{Name{"", "hello"}, []Attr{{Name{"", "lang"}, "en"}}}, - CharData("World <>'\" 白鵬翔"), - EndElement{Name{"", "hello"}}, - CharData("\n "), - StartElement{Name{"", "query"}, []Attr{}}, - CharData("What is it?"), - EndElement{Name{"", "query"}}, - CharData("\n "), - StartElement{Name{"", "goodbye"}, []Attr{}}, - EndElement{Name{"", "goodbye"}}, - CharData("\n "), - StartElement{Name{"", "outer"}, []Attr{{Name{"foo", "attr"}, "value"}, {Name{"xmlns", "tag"}, "ns4"}}}, - CharData("\n "), - StartElement{Name{"", "inner"}, []Attr{}}, - EndElement{Name{"", "inner"}}, - CharData("\n "), - EndElement{Name{"", "outer"}}, - CharData("\n "), - StartElement{Name{"tag", "name"}, []Attr{}}, - CharData("\n "), - CharData("Some text here."), - CharData("\n "), - EndElement{Name{"tag", "name"}}, - CharData("\n"), - EndElement{Name{"", "body"}}, - Comment(" missing final newline "), -} - -var cookedTokens = []Token{ - CharData("\n"), - ProcInst{"xml", []byte(`version="1.0" encoding="UTF-8"`)}, - CharData("\n"), - Directive(`DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" - "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"`), - CharData("\n"), - StartElement{Name{"ns2", "body"}, []Attr{{Name{"xmlns", "foo"}, "ns1"}, {Name{"", "xmlns"}, "ns2"}, {Name{"xmlns", "tag"}, "ns3"}}}, - CharData("\n "), - StartElement{Name{"ns2", "hello"}, []Attr{{Name{"", "lang"}, "en"}}}, - CharData("World <>'\" 白鵬翔"), - EndElement{Name{"ns2", "hello"}}, - CharData("\n "), - StartElement{Name{"ns2", "query"}, []Attr{}}, - CharData("What is it?"), - EndElement{Name{"ns2", "query"}}, - CharData("\n "), - StartElement{Name{"ns2", "goodbye"}, []Attr{}}, - EndElement{Name{"ns2", "goodbye"}}, - CharData("\n "), - StartElement{Name{"ns2", "outer"}, []Attr{{Name{"ns1", "attr"}, "value"}, {Name{"xmlns", "tag"}, "ns4"}}}, - CharData("\n "), - StartElement{Name{"ns2", "inner"}, []Attr{}}, - EndElement{Name{"ns2", "inner"}}, - CharData("\n "), - EndElement{Name{"ns2", "outer"}}, - CharData("\n "), - StartElement{Name{"ns3", "name"}, []Attr{}}, - CharData("\n "), - CharData("Some text here."), - CharData("\n "), - EndElement{Name{"ns3", "name"}}, - CharData("\n"), - EndElement{Name{"ns2", "body"}}, - Comment(" missing final newline "), -} - -const testInputAltEncoding = ` -<?xml version="1.0" encoding="x-testing-uppercase"?> -<TAG>VALUE</TAG>` - -var rawTokensAltEncoding = []Token{ - CharData("\n"), - ProcInst{"xml", []byte(`version="1.0" encoding="x-testing-uppercase"`)}, - CharData("\n"), - StartElement{Name{"", "tag"}, []Attr{}}, - CharData("value"), - EndElement{Name{"", "tag"}}, -} - -var xmlInput = []string{ - // unexpected EOF cases - "<", - "<t", - "<t ", - "<t/", - "<!", - "<!-", - "<!--", - "<!--c-", - "<!--c--", - "<!d", - "<t></", - "<t></t", - "<?", - "<?p", - "<t a", - "<t a=", - "<t a='", - "<t a=''", - "<t/><![", - "<t/><![C", - "<t/><![CDATA[d", - "<t/><![CDATA[d]", - "<t/><![CDATA[d]]", - - // other Syntax errors - "<>", - "<t/a", - "<0 />", - "<?0 >", - // "<!0 >", // let the Token() caller handle - "</0>", - "<t 0=''>", - "<t a='&'>", - "<t a='<'>", - "<t> c;</t>", - "<t a>", - "<t a=>", - "<t a=v>", - // "<![CDATA[d]]>", // let the Token() caller handle - "<t></e>", - "<t></>", - "<t></t!", - "<t>cdata]]></t>", -} - -func TestRawToken(t *testing.T) { - d := NewDecoder(strings.NewReader(testInput)) - d.Entity = testEntity - testRawToken(t, d, testInput, rawTokens) -} - -const nonStrictInput = ` -<tag>non&entity</tag> -<tag>&unknown;entity</tag> -<tag>{</tag> -<tag>&#zzz;</tag> -<tag>&なまえ3;</tag> -<tag><-gt;</tag> -<tag>&;</tag> -<tag>&0a;</tag> -` - -var nonStringEntity = map[string]string{"": "oops!", "0a": "oops!"} - -var nonStrictTokens = []Token{ - CharData("\n"), - StartElement{Name{"", "tag"}, []Attr{}}, - CharData("non&entity"), - EndElement{Name{"", "tag"}}, - CharData("\n"), - StartElement{Name{"", "tag"}, []Attr{}}, - CharData("&unknown;entity"), - EndElement{Name{"", "tag"}}, - CharData("\n"), - StartElement{Name{"", "tag"}, []Attr{}}, - CharData("{"), - EndElement{Name{"", "tag"}}, - CharData("\n"), - StartElement{Name{"", "tag"}, []Attr{}}, - CharData("&#zzz;"), - EndElement{Name{"", "tag"}}, - CharData("\n"), - StartElement{Name{"", "tag"}, []Attr{}}, - CharData("&なまえ3;"), - EndElement{Name{"", "tag"}}, - CharData("\n"), - StartElement{Name{"", "tag"}, []Attr{}}, - CharData("<-gt;"), - EndElement{Name{"", "tag"}}, - CharData("\n"), - StartElement{Name{"", "tag"}, []Attr{}}, - CharData("&;"), - EndElement{Name{"", "tag"}}, - CharData("\n"), - StartElement{Name{"", "tag"}, []Attr{}}, - CharData("&0a;"), - EndElement{Name{"", "tag"}}, - CharData("\n"), -} - -func TestNonStrictRawToken(t *testing.T) { - d := NewDecoder(strings.NewReader(nonStrictInput)) - d.Strict = false - testRawToken(t, d, nonStrictInput, nonStrictTokens) -} - -type downCaser struct { - t *testing.T - r io.ByteReader -} - -func (d *downCaser) ReadByte() (c byte, err error) { - c, err = d.r.ReadByte() - if c >= 'A' && c <= 'Z' { - c += 'a' - 'A' - } - return -} - -func (d *downCaser) Read(p []byte) (int, error) { - d.t.Fatalf("unexpected Read call on downCaser reader") - panic("unreachable") -} - -func TestRawTokenAltEncoding(t *testing.T) { - d := NewDecoder(strings.NewReader(testInputAltEncoding)) - d.CharsetReader = func(charset string, input io.Reader) (io.Reader, error) { - if charset != "x-testing-uppercase" { - t.Fatalf("unexpected charset %q", charset) - } - return &downCaser{t, input.(io.ByteReader)}, nil - } - testRawToken(t, d, testInputAltEncoding, rawTokensAltEncoding) -} - -func TestRawTokenAltEncodingNoConverter(t *testing.T) { - d := NewDecoder(strings.NewReader(testInputAltEncoding)) - token, err := d.RawToken() - if token == nil { - t.Fatalf("expected a token on first RawToken call") - } - if err != nil { - t.Fatal(err) - } - token, err = d.RawToken() - if token != nil { - t.Errorf("expected a nil token; got %#v", token) - } - if err == nil { - t.Fatalf("expected an error on second RawToken call") - } - const encoding = "x-testing-uppercase" - if !strings.Contains(err.Error(), encoding) { - t.Errorf("expected error to contain %q; got error: %v", - encoding, err) - } -} - -func testRawToken(t *testing.T, d *Decoder, raw string, rawTokens []Token) { - lastEnd := int64(0) - for i, want := range rawTokens { - start := d.InputOffset() - have, err := d.RawToken() - end := d.InputOffset() - if err != nil { - t.Fatalf("token %d: unexpected error: %s", i, err) - } - if !reflect.DeepEqual(have, want) { - var shave, swant string - if _, ok := have.(CharData); ok { - shave = fmt.Sprintf("CharData(%q)", have) - } else { - shave = fmt.Sprintf("%#v", have) - } - if _, ok := want.(CharData); ok { - swant = fmt.Sprintf("CharData(%q)", want) - } else { - swant = fmt.Sprintf("%#v", want) - } - t.Errorf("token %d = %s, want %s", i, shave, swant) - } - - // Check that InputOffset returned actual token. - switch { - case start < lastEnd: - t.Errorf("token %d: position [%d,%d) for %T is before previous token", i, start, end, have) - case start >= end: - // Special case: EndElement can be synthesized. - if start == end && end == lastEnd { - break - } - t.Errorf("token %d: position [%d,%d) for %T is empty", i, start, end, have) - case end > int64(len(raw)): - t.Errorf("token %d: position [%d,%d) for %T extends beyond input", i, start, end, have) - default: - text := raw[start:end] - if strings.ContainsAny(text, "<>") && (!strings.HasPrefix(text, "<") || !strings.HasSuffix(text, ">")) { - t.Errorf("token %d: misaligned raw token %#q for %T", i, text, have) - } - } - lastEnd = end - } -} - -// Ensure that directives (specifically !DOCTYPE) include the complete -// text of any nested directives, noting that < and > do not change -// nesting depth if they are in single or double quotes. - -var nestedDirectivesInput = ` -<!DOCTYPE [<!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#">]> -<!DOCTYPE [<!ENTITY xlt ">">]> -<!DOCTYPE [<!ENTITY xlt "<">]> -<!DOCTYPE [<!ENTITY xlt '>'>]> -<!DOCTYPE [<!ENTITY xlt '<'>]> -<!DOCTYPE [<!ENTITY xlt '">'>]> -<!DOCTYPE [<!ENTITY xlt "'<">]> -` - -var nestedDirectivesTokens = []Token{ - CharData("\n"), - Directive(`DOCTYPE [<!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#">]`), - CharData("\n"), - Directive(`DOCTYPE [<!ENTITY xlt ">">]`), - CharData("\n"), - Directive(`DOCTYPE [<!ENTITY xlt "<">]`), - CharData("\n"), - Directive(`DOCTYPE [<!ENTITY xlt '>'>]`), - CharData("\n"), - Directive(`DOCTYPE [<!ENTITY xlt '<'>]`), - CharData("\n"), - Directive(`DOCTYPE [<!ENTITY xlt '">'>]`), - CharData("\n"), - Directive(`DOCTYPE [<!ENTITY xlt "'<">]`), - CharData("\n"), -} - -func TestNestedDirectives(t *testing.T) { - d := NewDecoder(strings.NewReader(nestedDirectivesInput)) - - for i, want := range nestedDirectivesTokens { - have, err := d.Token() - if err != nil { - t.Fatalf("token %d: unexpected error: %s", i, err) - } - if !reflect.DeepEqual(have, want) { - t.Errorf("token %d = %#v want %#v", i, have, want) - } - } -} - -func TestToken(t *testing.T) { - d := NewDecoder(strings.NewReader(testInput)) - d.Entity = testEntity - - for i, want := range cookedTokens { - have, err := d.Token() - if err != nil { - t.Fatalf("token %d: unexpected error: %s", i, err) - } - if !reflect.DeepEqual(have, want) { - t.Errorf("token %d = %#v want %#v", i, have, want) - } - } -} - -func TestSyntax(t *testing.T) { - for i := range xmlInput { - d := NewDecoder(strings.NewReader(xmlInput[i])) - var err error - for _, err = d.Token(); err == nil; _, err = d.Token() { - } - if _, ok := err.(*SyntaxError); !ok { - t.Fatalf(`xmlInput "%s": expected SyntaxError not received`, xmlInput[i]) - } - } -} - -type allScalars struct { - True1 bool - True2 bool - False1 bool - False2 bool - Int int - Int8 int8 - Int16 int16 - Int32 int32 - Int64 int64 - Uint int - Uint8 uint8 - Uint16 uint16 - Uint32 uint32 - Uint64 uint64 - Uintptr uintptr - Float32 float32 - Float64 float64 - String string - PtrString *string -} - -var all = allScalars{ - True1: true, - True2: true, - False1: false, - False2: false, - Int: 1, - Int8: -2, - Int16: 3, - Int32: -4, - Int64: 5, - Uint: 6, - Uint8: 7, - Uint16: 8, - Uint32: 9, - Uint64: 10, - Uintptr: 11, - Float32: 13.0, - Float64: 14.0, - String: "15", - PtrString: &sixteen, -} - -var sixteen = "16" - -const testScalarsInput = `<allscalars> - <True1>true</True1> - <True2>1</True2> - <False1>false</False1> - <False2>0</False2> - <Int>1</Int> - <Int8>-2</Int8> - <Int16>3</Int16> - <Int32>-4</Int32> - <Int64>5</Int64> - <Uint>6</Uint> - <Uint8>7</Uint8> - <Uint16>8</Uint16> - <Uint32>9</Uint32> - <Uint64>10</Uint64> - <Uintptr>11</Uintptr> - <Float>12.0</Float> - <Float32>13.0</Float32> - <Float64>14.0</Float64> - <String>15</String> - <PtrString>16</PtrString> -</allscalars>` - -func TestAllScalars(t *testing.T) { - var a allScalars - err := Unmarshal([]byte(testScalarsInput), &a) - - if err != nil { - t.Fatal(err) - } - if !reflect.DeepEqual(a, all) { - t.Errorf("have %+v want %+v", a, all) - } -} - -type item struct { - Field_a string -} - -func TestIssue569(t *testing.T) { - data := `<item><Field_a>abcd</Field_a></item>` - var i item - err := Unmarshal([]byte(data), &i) - - if err != nil || i.Field_a != "abcd" { - t.Fatal("Expecting abcd") - } -} - -func TestUnquotedAttrs(t *testing.T) { - data := "<tag attr=azAZ09:-_\t>" - d := NewDecoder(strings.NewReader(data)) - d.Strict = false - token, err := d.Token() - if _, ok := err.(*SyntaxError); ok { - t.Errorf("Unexpected error: %v", err) - } - if token.(StartElement).Name.Local != "tag" { - t.Errorf("Unexpected tag name: %v", token.(StartElement).Name.Local) - } - attr := token.(StartElement).Attr[0] - if attr.Value != "azAZ09:-_" { - t.Errorf("Unexpected attribute value: %v", attr.Value) - } - if attr.Name.Local != "attr" { - t.Errorf("Unexpected attribute name: %v", attr.Name.Local) - } -} - -func TestValuelessAttrs(t *testing.T) { - tests := [][3]string{ - {"<p nowrap>", "p", "nowrap"}, - {"<p nowrap >", "p", "nowrap"}, - {"<input checked/>", "input", "checked"}, - {"<input checked />", "input", "checked"}, - } - for _, test := range tests { - d := NewDecoder(strings.NewReader(test[0])) - d.Strict = false - token, err := d.Token() - if _, ok := err.(*SyntaxError); ok { - t.Errorf("Unexpected error: %v", err) - } - if token.(StartElement).Name.Local != test[1] { - t.Errorf("Unexpected tag name: %v", token.(StartElement).Name.Local) - } - attr := token.(StartElement).Attr[0] - if attr.Value != test[2] { - t.Errorf("Unexpected attribute value: %v", attr.Value) - } - if attr.Name.Local != test[2] { - t.Errorf("Unexpected attribute name: %v", attr.Name.Local) - } - } -} - -func TestCopyTokenCharData(t *testing.T) { - data := []byte("same data") - var tok1 Token = CharData(data) - tok2 := CopyToken(tok1) - if !reflect.DeepEqual(tok1, tok2) { - t.Error("CopyToken(CharData) != CharData") - } - data[1] = 'o' - if reflect.DeepEqual(tok1, tok2) { - t.Error("CopyToken(CharData) uses same buffer.") - } -} - -func TestCopyTokenStartElement(t *testing.T) { - elt := StartElement{Name{"", "hello"}, []Attr{{Name{"", "lang"}, "en"}}} - var tok1 Token = elt - tok2 := CopyToken(tok1) - if tok1.(StartElement).Attr[0].Value != "en" { - t.Error("CopyToken overwrote Attr[0]") - } - if !reflect.DeepEqual(tok1, tok2) { - t.Error("CopyToken(StartElement) != StartElement") - } - tok1.(StartElement).Attr[0] = Attr{Name{"", "lang"}, "de"} - if reflect.DeepEqual(tok1, tok2) { - t.Error("CopyToken(CharData) uses same buffer.") - } -} - -func TestSyntaxErrorLineNum(t *testing.T) { - testInput := "<P>Foo<P>\n\n<P>Bar</>\n" - d := NewDecoder(strings.NewReader(testInput)) - var err error - for _, err = d.Token(); err == nil; _, err = d.Token() { - } - synerr, ok := err.(*SyntaxError) - if !ok { - t.Error("Expected SyntaxError.") - } - if synerr.Line != 3 { - t.Error("SyntaxError didn't have correct line number.") - } -} - -func TestTrailingRawToken(t *testing.T) { - input := `<FOO></FOO> ` - d := NewDecoder(strings.NewReader(input)) - var err error - for _, err = d.RawToken(); err == nil; _, err = d.RawToken() { - } - if err != io.EOF { - t.Fatalf("d.RawToken() = _, %v, want _, io.EOF", err) - } -} - -func TestTrailingToken(t *testing.T) { - input := `<FOO></FOO> ` - d := NewDecoder(strings.NewReader(input)) - var err error - for _, err = d.Token(); err == nil; _, err = d.Token() { - } - if err != io.EOF { - t.Fatalf("d.Token() = _, %v, want _, io.EOF", err) - } -} - -func TestEntityInsideCDATA(t *testing.T) { - input := `<test><![CDATA[ &val=foo ]]></test>` - d := NewDecoder(strings.NewReader(input)) - var err error - for _, err = d.Token(); err == nil; _, err = d.Token() { - } - if err != io.EOF { - t.Fatalf("d.Token() = _, %v, want _, io.EOF", err) - } -} - -var characterTests = []struct { - in string - err string -}{ - {"\x12<doc/>", "illegal character code U+0012"}, - {"<?xml version=\"1.0\"?>\x0b<doc/>", "illegal character code U+000B"}, - {"\xef\xbf\xbe<doc/>", "illegal character code U+FFFE"}, - {"<?xml version=\"1.0\"?><doc>\r\n<hiya/>\x07<toots/></doc>", "illegal character code U+0007"}, - {"<?xml version=\"1.0\"?><doc \x12='value'>what's up</doc>", "expected attribute name in element"}, - {"<doc>&abc\x01;</doc>", "invalid character entity &abc (no semicolon)"}, - {"<doc>&\x01;</doc>", "invalid character entity & (no semicolon)"}, - {"<doc>&\xef\xbf\xbe;</doc>", "invalid character entity &\uFFFE;"}, - {"<doc>&hello;</doc>", "invalid character entity &hello;"}, -} - -func TestDisallowedCharacters(t *testing.T) { - - for i, tt := range characterTests { - d := NewDecoder(strings.NewReader(tt.in)) - var err error - - for err == nil { - _, err = d.Token() - } - synerr, ok := err.(*SyntaxError) - if !ok { - t.Fatalf("input %d d.Token() = _, %v, want _, *SyntaxError", i, err) - } - if synerr.Msg != tt.err { - t.Fatalf("input %d synerr.Msg wrong: want %q, got %q", i, tt.err, synerr.Msg) - } - } -} - -type procInstEncodingTest struct { - expect, got string -} - -var procInstTests = []struct { - input string - expect [2]string -}{ - {`version="1.0" encoding="utf-8"`, [2]string{"1.0", "utf-8"}}, - {`version="1.0" encoding='utf-8'`, [2]string{"1.0", "utf-8"}}, - {`version="1.0" encoding='utf-8' `, [2]string{"1.0", "utf-8"}}, - {`version="1.0" encoding=utf-8`, [2]string{"1.0", ""}}, - {`encoding="FOO" `, [2]string{"", "FOO"}}, -} - -func TestProcInstEncoding(t *testing.T) { - for _, test := range procInstTests { - if got := procInst("version", test.input); got != test.expect[0] { - t.Errorf("procInst(version, %q) = %q; want %q", test.input, got, test.expect[0]) - } - if got := procInst("encoding", test.input); got != test.expect[1] { - t.Errorf("procInst(encoding, %q) = %q; want %q", test.input, got, test.expect[1]) - } - } -} - -// Ensure that directives with comments include the complete -// text of any nested directives. - -var directivesWithCommentsInput = ` -<!DOCTYPE [<!-- a comment --><!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#">]> -<!DOCTYPE [<!ENTITY go "Golang"><!-- a comment-->]> -<!DOCTYPE <!-> <!> <!----> <!-->--> <!--->--> [<!ENTITY go "Golang"><!-- a comment-->]> -` - -var directivesWithCommentsTokens = []Token{ - CharData("\n"), - Directive(`DOCTYPE [<!ENTITY rdf "http://www.w3.org/1999/02/22-rdf-syntax-ns#">]`), - CharData("\n"), - Directive(`DOCTYPE [<!ENTITY go "Golang">]`), - CharData("\n"), - Directive(`DOCTYPE <!-> <!> [<!ENTITY go "Golang">]`), - CharData("\n"), -} - -func TestDirectivesWithComments(t *testing.T) { - d := NewDecoder(strings.NewReader(directivesWithCommentsInput)) - - for i, want := range directivesWithCommentsTokens { - have, err := d.Token() - if err != nil { - t.Fatalf("token %d: unexpected error: %s", i, err) - } - if !reflect.DeepEqual(have, want) { - t.Errorf("token %d = %#v want %#v", i, have, want) - } - } -} - -// Writer whose Write method always returns an error. -type errWriter struct{} - -func (errWriter) Write(p []byte) (n int, err error) { return 0, fmt.Errorf("unwritable") } - -func TestEscapeTextIOErrors(t *testing.T) { - expectErr := "unwritable" - err := EscapeText(errWriter{}, []byte{'A'}) - - if err == nil || err.Error() != expectErr { - t.Errorf("have %v, want %v", err, expectErr) - } -} - -func TestEscapeTextInvalidChar(t *testing.T) { - input := []byte("A \x00 terminated string.") - expected := "A \uFFFD terminated string." - - buff := new(bytes.Buffer) - if err := EscapeText(buff, input); err != nil { - t.Fatalf("have %v, want nil", err) - } - text := buff.String() - - if text != expected { - t.Errorf("have %v, want %v", text, expected) - } -} - -func TestIssue5880(t *testing.T) { - type T []byte - data, err := Marshal(T{192, 168, 0, 1}) - if err != nil { - t.Errorf("Marshal error: %v", err) - } - if !utf8.Valid(data) { - t.Errorf("Marshal generated invalid UTF-8: %x", data) - } -} |