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: https://www.xml.com/axml/testaxml.htm XML name spaces: https://www.w3.org/TR/REC-xml-names/
TODO(rsc): Test error handling.

import (
	
	
	
	
	
	
	
	
	
)
A SyntaxError represents a syntax error in the XML input stream.
type SyntaxError struct {
	Msg  string
	Line int
}

func ( *SyntaxError) () string {
	return "XML syntax error on line " + strconv.Itoa(.Line) + ": " + .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.
type Name struct {
	Space, Local string
}
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
}
Copy creates a new copy of StartElement.
func ( StartElement) () StartElement {
	 := make([]Attr, len(.Attr))
	copy(, .Attr)
	.Attr = 
	return 
}
End returns the corresponding XML end element.
func ( StartElement) () EndElement {
	return EndElement{.Name}
}
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 ( []byte) []byte {
	 := make([]byte, len())
	copy(, )
	return 
}
Copy creates a new copy of CharData.
func ( CharData) () CharData { return CharData(makeCopy()) }
A Comment represents an XML comment of the form <!--comment-->. The bytes do not include the <!-- and --> comment markers.
type Comment []byte
Copy creates a new copy of Comment.
func ( Comment) () Comment { return Comment(makeCopy()) }
A ProcInst represents an XML processing instruction of the form <?target inst?>
type ProcInst struct {
	Target string
	Inst   []byte
}
Copy creates a new copy of ProcInst.
func ( ProcInst) () ProcInst {
	.Inst = makeCopy(.Inst)
	return 
}
A Directive represents an XML directive of the form <!text>. The bytes do not include the <! and > markers.
type Directive []byte
Copy creates a new copy of Directive.
func ( Directive) () Directive { return Directive(makeCopy()) }
CopyToken returns a copy of a Token.
func ( Token) Token {
	switch v := .(type) {
	case CharData:
		return .Copy()
	case Comment:
		return .Copy()
	case Directive:
		return .Copy()
	case ProcInst:
		return .Copy()
	case StartElement:
		return .Copy()
	}
	return 
}
A TokenReader is anything that can decode a stream of XML tokens, including a Decoder. When Token encounters an error or end-of-file condition after successfully reading a token, it returns the token. It may return the (non-nil) error from the same call or return the error (and a nil token) from a subsequent call. An instance of this general case is that a TokenReader returning a non-nil token at the end of the token stream may return either io.EOF or a nil error. The next Read should return nil, io.EOF. Implementations of Token are discouraged from returning a nil token with a nil error. Callers should treat a return of nil, nil as indicating that nothing happened; in particular it does not indicate EOF.
type TokenReader interface {
	Token() (Token, error)
}
A Decoder represents an XML parser reading a particular input stream. The parser assumes that its input is encoded in UTF-8.
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 = xml.HTMLAutoClose d.Entity = xml.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.
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.
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": `"`,
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 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".
NewDecoder creates a new XML parser reading from r. If r does not implement io.ByteReader, NewDecoder will do its own buffering.
func ( io.Reader) *Decoder {
	 := &Decoder{
		ns:       make(map[string]string),
		nextByte: -1,
		line:     1,
		Strict:   true,
	}
	.switchToReader()
	return 
}
NewTokenDecoder creates a new XML parser using an underlying token stream.
Is it already a Decoder?
	if ,  := .(*Decoder);  {
		return 
	}
	 := &Decoder{
		ns:       make(map[string]string),
		t:        ,
		nextByte: -1,
		line:     1,
		Strict:   true,
	}
	return 
}
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 or EOF before all expected end elements, it will return an error. Token implements XML name spaces as described by https://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 ( *Decoder) () (Token, error) {
	var  Token
	var  error
	if .stk != nil && .stk.kind == stkEOF {
		return nil, io.EOF
	}
	if .nextToken != nil {
		 = .nextToken
		.nextToken = nil
	} else {
		if ,  = .rawToken();  == nil &&  != nil {
			if  == io.EOF && .stk != nil && .stk.kind != stkEOF {
				 = .syntaxError("unexpected EOF")
			}
			return nil, 
We still have a token to process, so clear any errors (e.g. EOF) and proceed.
		 = nil
	}
	if !.Strict {
		if ,  := .autoClose();  {
			.nextToken = 
			 = 
		}
	}
	switch t1 := .(type) {
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 ,  := range .Attr {
			if .Name.Space == xmlnsPrefix {
				,  := .ns[.Name.Local]
				.pushNs(.Name.Local, , )
				.ns[.Name.Local] = .Value
			}
Default space for untagged names
				,  := .ns[""]
				.pushNs("", , )
				.ns[""] = .Value
			}
		}

		.translate(&.Name, true)
		for  := range .Attr {
			.translate(&.Attr[].Name, false)
		}
		.pushElement(.Name)
		 = 

	case EndElement:
		.translate(&.Name, true)
		if !.popElement(&) {
			return nil, .err
		}
		 = 
	}
	return , 
}

const (
	xmlURL      = "http://www.w3.org/XML/1998/namespace"
	xmlnsPrefix = "xmlns"
	xmlPrefix   = "xml"
)
Apply name space translation to name n. The default name space (for Space=="") applies only to element names, not to attribute names.
func ( *Decoder) ( *Name,  bool) {
	switch {
	case .Space == xmlnsPrefix:
		return
	case .Space == "" && !:
		return
	case .Space == xmlPrefix:
		.Space = xmlURL
	case .Space == "" && .Local == xmlnsPrefix:
		return
	}
	if ,  := .ns[.Space];  {
		.Space = 
	} else if .Space == "" {
		.Space = .DefaultSpace
	}
}

Get efficient byte at a time reader. Assume that if reader has its own ReadByte, it's efficient enough. Otherwise, use bufio.
	if ,  := .(io.ByteReader);  {
		.r = 
	} else {
		.r = bufio.NewReader()
	}
}
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 ( *Decoder) ( int) *stack {
	 := .free
	if  != nil {
		.free = .next
	} else {
		 = new(stack)
	}
	.next = .stk
	.kind = 
	.stk = 
	return 
}

func ( *Decoder) () *stack {
	 := .stk
	if  != nil {
		.stk = .next
		.next = .free
		.free = 
	}
	return 
}
Record that after the current element is finished (that element is already pushed on the stack) Token should return EOF until popEOF is called.
Walk down stack to find Start. It might not be the top, because there might be stkNs entries above it.
	 := .stk
	for .kind != stkStart {
		 = .next
The stkNs entries below a start are associated with that element too; skip over them.
	for .next != nil && .next.kind == stkNs {
		 = .next
	}
	 := .free
	if  != nil {
		.free = .next
	} else {
		 = new(stack)
	}
	.kind = stkEOF
	.next = .next
	.next = 
}
Undo a pushEOF. The element must have been finished, so the EOF should be at the top of the stack.
func ( *Decoder) () bool {
	if .stk == nil || .stk.kind != stkEOF {
		return false
	}
	.pop()
	return true
}
Record that we are starting an element with the given name.
func ( *Decoder) ( Name) {
	 := .push(stkStart)
	.name = 
}
Record that we are changing the value of ns[local]. The old value is url, ok.
func ( *Decoder) ( string,  string,  bool) {
	 := .push(stkNs)
	.name.Local = 
	.name.Space = 
	.ok = 
}
Creates a SyntaxError with the current line number.
func ( *Decoder) ( string) error {
	return &SyntaxError{Msg: , Line: .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 ( *Decoder) ( *EndElement) bool {
	 := .pop()
	 := .Name
	switch {
	case  == nil || .kind != stkStart:
		.err = .syntaxError("unexpected end element </" + .Local + ">")
		return false
	case .name.Local != .Local:
		if !.Strict {
			.needClose = true
			.toClose = .Name
			.Name = .name
			return true
		}
		.err = .syntaxError("element <" + .name.Local + "> closed by </" + .Local + ">")
		return false
	case .name.Space != .Space:
		.err = .syntaxError("element <" + .name.Local + "> in space " + .name.Space +
			"closed by </" + .Local + "> in space " + .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 .stk != nil && .stk.kind != stkStart && .stk.kind != stkEOF {
		 := .pop()
		if .ok {
			.ns[.name.Local] = .name.Space
		} else {
			delete(.ns, .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 ( *Decoder) ( Token) (Token, bool) {
	if .stk == nil || .stk.kind != stkStart {
		return nil, false
	}
	 := strings.ToLower(.stk.name.Local)
	for ,  := range .AutoClose {
This one should be auto closed if t doesn't close it.
			,  := .(EndElement)
			if ! || .Name.Local !=  {
				return EndElement{.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 ( *Decoder) () (Token, error) {
	if .unmarshalDepth > 0 {
		return nil, errRawToken
	}
	return .rawToken()
}

func ( *Decoder) () (Token, error) {
	if .t != nil {
		return .t.Token()
	}
	if .err != nil {
		return nil, .err
	}
The last element we read was self-closing and we returned just the StartElement half. Return the EndElement half now.
		.needClose = false
		return EndElement{.toClose}, nil
	}

	,  := .getc()
	if ! {
		return nil, .err
	}

Text section.
		.ungetc()
		 := .text(-1, false)
		if  == nil {
			return nil, .err
		}
		return CharData(), nil
	}

	if ,  = .mustgetc(); ! {
		return nil, .err
	}
	switch  {
</: End element
		var  Name
		if ,  = .nsname(); ! {
			if .err == nil {
				.err = .syntaxError("expected element name after </")
			}
			return nil, .err
		}
		.space()
		if ,  = .mustgetc(); ! {
			return nil, .err
		}
		if  != '>' {
			.err = .syntaxError("invalid characters between </" + .Local + " and >")
			return nil, .err
		}
		return EndElement{}, nil

<?: Processing instruction.
		var  string
		if ,  = .name(); ! {
			if .err == nil {
				.err = .syntaxError("expected target name after <?")
			}
			return nil, .err
		}
		.space()
		.buf.Reset()
		var  byte
		for {
			if ,  = .mustgetc(); ! {
				return nil, .err
			}
			.buf.WriteByte()
			if  == '?' &&  == '>' {
				break
			}
			 = 
		}
		 := .buf.Bytes()
		 = [0 : len()-2] // chop ?>

		if  == "xml" {
			 := string()
			 := procInst("version", )
			if  != "" &&  != "1.0" {
				.err = fmt.Errorf("xml: unsupported version %q; only version 1.0 is supported", )
				return nil, .err
			}
			 := procInst("encoding", )
			if  != "" &&  != "utf-8" &&  != "UTF-8" && !strings.EqualFold(, "utf-8") {
				if .CharsetReader == nil {
					.err = fmt.Errorf("xml: encoding %q declared but Decoder.CharsetReader is nil", )
					return nil, .err
				}
				,  := .CharsetReader(, .r.(io.Reader))
				if  != nil {
					.err = fmt.Errorf("xml: opening charset %q: %v", , )
					return nil, .err
				}
				if  == nil {
					panic("CharsetReader returned a nil Reader for charset " + )
				}
				.switchToReader()
			}
		}
		return ProcInst{, }, nil

<!: Maybe comment, maybe CDATA.
		if ,  = .mustgetc(); ! {
			return nil, .err
		}
		switch  {
Probably <!-- for a comment.
			if ,  = .mustgetc(); ! {
				return nil, .err
			}
			if  != '-' {
				.err = .syntaxError("invalid sequence <!- not part of <!--")
				return nil, .err
Look for terminator.
			.buf.Reset()
			var ,  byte
			for {
				if ,  = .mustgetc(); ! {
					return nil, .err
				}
				.buf.WriteByte()
				if  == '-' &&  == '-' {
					if  != '>' {
						.err = .syntaxError(
							`invalid sequence "--" not allowed in comments`)
						return nil, .err
					}
					break
				}
				,  = , 
			}
			 := .buf.Bytes()
			 = [0 : len()-3] // chop -->
			return Comment(), nil

Probably <![CDATA[.
			for  := 0;  < 6; ++ {
				if ,  = .mustgetc(); ! {
					return nil, .err
				}
				if  != "CDATA["[] {
					.err = .syntaxError("invalid <![ sequence")
					return nil, .err
				}
Have <![CDATA[. Read text until ]]>.
			 := .text(-1, true)
			if  == nil {
				return nil, .err
			}
			return CharData(), nil
		}
Probably a directive: <!DOCTYPE ...>, <!ENTITY ...>, etc. We don't care, but accumulate for caller. Quoted angle brackets do not count for nesting.
		.buf.Reset()
		.buf.WriteByte()
		 := uint8(0)
		 := 0
		for {
			if ,  = .mustgetc(); ! {
				return nil, .err
			}
			if  == 0 &&  == '>' &&  == 0 {
				break
			}
		:
			.buf.WriteByte()
			switch {
			case  == :
				 = 0

in quotes, no special action

			case  == '\'' ||  == '"':
				 = 

			case  == '>' &&  == 0:
				--

Look for <!-- to begin comment.
				 := "!--"
				for  := 0;  < len(); ++ {
					if ,  = .mustgetc(); ! {
						return nil, .err
					}
					if  != [] {
						for  := 0;  < ; ++ {
							.buf.WriteByte([])
						}
						++
						goto 
					}
				}
Remove < that was written above.
				.buf.Truncate(.buf.Len() - 1)
Look for terminator.
				var ,  byte
				for {
					if ,  = .mustgetc(); ! {
						return nil, .err
					}
					if  == '-' &&  == '-' &&  == '>' {
						break
					}
					,  = , 
				}
			}
		}
		return Directive(.buf.Bytes()), nil
	}
Must be an open element like <a href="foo">
	.ungetc()

	var (
		  Name
		 bool
		  []Attr
	)
	if ,  = .nsname(); ! {
		if .err == nil {
			.err = .syntaxError("expected element name after <")
		}
		return nil, .err
	}

	 = []Attr{}
	for {
		.space()
		if ,  = .mustgetc(); ! {
			return nil, .err
		}
		if  == '/' {
			 = true
			if ,  = .mustgetc(); ! {
				return nil, .err
			}
			if  != '>' {
				.err = .syntaxError("expected /> in element")
				return nil, .err
			}
			break
		}
		if  == '>' {
			break
		}
		.ungetc()

		 := Attr{}
		if .Name,  = .nsname(); ! {
			if .err == nil {
				.err = .syntaxError("expected attribute name in element")
			}
			return nil, .err
		}
		.space()
		if ,  = .mustgetc(); ! {
			return nil, .err
		}
		if  != '=' {
			if .Strict {
				.err = .syntaxError("attribute name without = in element")
				return nil, .err
			}
			.ungetc()
			.Value = .Name.Local
		} else {
			.space()
			 := .attrval()
			if  == nil {
				return nil, .err
			}
			.Value = string()
		}
		 = append(, )
	}
	if  {
		.needClose = true
		.toClose = 
	}
	return StartElement{, }, nil
}

func ( *Decoder) () []byte {
	,  := .mustgetc()
	if ! {
		return nil
Handle quoted attribute values
	if  == '"' ||  == '\'' {
		return .text(int(), false)
Handle unquoted attribute values for strict parsers
	if .Strict {
		.err = .syntaxError("unquoted or missing attribute value in element")
		return nil
Handle unquoted attribute values for unstrict parsers
	.ungetc()
	.buf.Reset()
	for {
		,  = .mustgetc()
		if ! {
			return nil
https://www.w3.org/TR/REC-html40/intro/sgmltut.html#h-3.2.2
		if 'a' <=  &&  <= 'z' || 'A' <=  &&  <= 'Z' ||
			'0' <=  &&  <= '9' ||  == '_' ||  == ':' ||  == '-' {
			.buf.WriteByte()
		} else {
			.ungetc()
			break
		}
	}
	return .buf.Bytes()
}
Skip spaces if any
func ( *Decoder) () {
	for {
		,  := .getc()
		if ! {
			return
		}
		switch  {
		case ' ', '\r', '\n', '\t':
		default:
			.ungetc()
			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 ( *Decoder) () ( byte,  bool) {
	if .err != nil {
		return 0, false
	}
	if .nextByte >= 0 {
		 = byte(.nextByte)
		.nextByte = -1
	} else {
		, .err = .r.ReadByte()
		if .err != nil {
			return 0, false
		}
		if .saved != nil {
			.saved.WriteByte()
		}
	}
	if  == '\n' {
		.line++
	}
	.offset++
	return , 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 ( *Decoder) () int64 {
	return .offset
}
Return saved offset. If we did ungetc (nextByte >= 0), have to back up one.
func ( *Decoder) () int {
	 := .saved.Len()
	if .nextByte >= 0 {
		--
	}
	return 
}
Must read a single byte. If there is no byte to read, set d.err to SyntaxError("unexpected EOF") and return ok==false
func ( *Decoder) () ( byte,  bool) {
	if ,  = .getc(); ! {
		if .err == io.EOF {
			.err = .syntaxError("unexpected EOF")
		}
	}
	return
}
Unread a single byte.
func ( *Decoder) ( byte) {
	if  == '\n' {
		.line--
	}
	.nextByte = int()
	.offset--
}

var entity = map[string]rune{
	"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 ( *Decoder) ( int,  bool) []byte {
	var ,  byte
	var  int
	.buf.Reset()
:
	for {
		,  := .getc()
		if ! {
			if  {
				if .err == io.EOF {
					.err = .syntaxError("unexpected EOF in CDATA section")
				}
				return nil
			}
			break 
		}
<![CDATA[ section ends with ]]>. It is an error for ]]> to appear in ordinary text.
		if  == ']' &&  == ']' &&  == '>' {
			if  {
				 = 2
				break 
			}
			.err = .syntaxError("unescaped ]]> not in CDATA section")
			return nil
		}
Stop reading text if we see a <.
		if  == '<' && ! {
			if  >= 0 {
				.err = .syntaxError("unescaped < inside quoted string")
				return nil
			}
			.ungetc('<')
			break 
		}
		if  >= 0 &&  == byte() {
			break 
		}
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.
			 := .buf.Len()
			.buf.WriteByte('&')
			var  bool
			var  string
			var  bool
			if ,  = .mustgetc(); ! {
				return nil
			}
			if  == '#' {
				.buf.WriteByte()
				if ,  = .mustgetc(); ! {
					return nil
				}
				 := 10
				if  == 'x' {
					 = 16
					.buf.WriteByte()
					if ,  = .mustgetc(); ! {
						return nil
					}
				}
				 := .buf.Len()
				for '0' <=  &&  <= '9' ||
					 == 16 && 'a' <=  &&  <= 'f' ||
					 == 16 && 'A' <=  &&  <= 'F' {
					.buf.WriteByte()
					if ,  = .mustgetc(); ! {
						return nil
					}
				}
				if  != ';' {
					.ungetc()
				} else {
					 := string(.buf.Bytes()[:])
					.buf.WriteByte(';')
					,  := strconv.ParseUint(, , 64)
					if  == nil &&  <= unicode.MaxRune {
						 = string(rune())
						 = true
					}
				}
			} else {
				.ungetc()
				if !.readName() {
					if .err != nil {
						return nil
					}
				}
				if ,  = .mustgetc(); ! {
					return nil
				}
				if  != ';' {
					.ungetc()
				} else {
					 := .buf.Bytes()[+1:]
					.buf.WriteByte(';')
					if isName() {
						 := string()
						if ,  := entity[];  {
							 = string()
							 = true
						} else if .Entity != nil {
							,  = .Entity[]
						}
					}
				}
			}

			if  {
				.buf.Truncate()
				.buf.Write([]byte())
				,  = 0, 0
				continue 
			}
			if !.Strict {
				,  = 0, 0
				continue 
			}
			 := string(.buf.Bytes()[:])
			if [len()-1] != ';' {
				 += " (no semicolon)"
			}
			.err = .syntaxError("invalid character entity " + )
			return nil
		}
We must rewrite unescaped \r and \r\n into \n.
		if  == '\r' {
			.buf.WriteByte('\n')
Skip \r\n--we already wrote \n.
		} else {
			.buf.WriteByte()
		}

		,  = , 
	}
	 := .buf.Bytes()
	 = [0 : len()-]
Inspect each rune for being a disallowed character.
	 := 
	for len() > 0 {
		,  := utf8.DecodeRune()
		if  == utf8.RuneError &&  == 1 {
			.err = .syntaxError("invalid UTF-8")
			return nil
		}
		 = [:]
		if !isInCharacterRange() {
			.err = .syntaxError(fmt.Sprintf("illegal character code %U", ))
			return nil
		}
	}

	return 
}
Decide whether the given rune is in the XML Character Range, per the Char production of https://www.xml.com/axml/testaxml.htm, Section 2.2 Characters.
func ( rune) ( bool) {
	return  == 0x09 ||
		 == 0x0A ||
		 == 0x0D ||
		 >= 0x20 &&  <= 0xD7FF ||
		 >= 0xE000 &&  <= 0xFFFD ||
		 >= 0x10000 &&  <= 0x10FFFF
}
Get name space name: name with a : stuck in the middle. The part before the : is the name space identifier.
func ( *Decoder) () ( Name,  bool) {
	,  := .name()
	if ! {
		return
	}
	 := strings.Index(, ":")
	if  < 0 {
		.Local = 
	} else {
		.Space = [0:]
		.Local = [+1:]
	}
	return , 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 ( *Decoder) () ( string,  bool) {
	.buf.Reset()
	if !.readName() {
		return "", false
	}
Now we check the characters.
	 := .buf.Bytes()
	if !isName() {
		.err = .syntaxError("invalid XML name: " + string())
		return "", false
	}
	return string(), 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 ( *Decoder) () ( bool) {
	var  byte
	if ,  = .mustgetc(); ! {
		return
	}
	if  < utf8.RuneSelf && !isNameByte() {
		.ungetc()
		return false
	}
	.buf.WriteByte()

	for {
		if ,  = .mustgetc(); ! {
			return
		}
		if  < utf8.RuneSelf && !isNameByte() {
			.ungetc()
			break
		}
		.buf.WriteByte()
	}
	return true
}

func ( byte) bool {
	return 'A' <=  &&  <= 'Z' ||
		'a' <=  &&  <= 'z' ||
		'0' <=  &&  <= '9' ||
		 == '_' ||  == ':' ||  == '.' ||  == '-'
}

func ( []byte) bool {
	if len() == 0 {
		return false
	}
	,  := utf8.DecodeRune()
	if  == utf8.RuneError &&  == 1 {
		return false
	}
	if !unicode.Is(first, ) {
		return false
	}
	for  < len() {
		 = [:]
		,  = utf8.DecodeRune()
		if  == utf8.RuneError &&  == 1 {
			return false
		}
		if !unicode.Is(first, ) && !unicode.Is(second, ) {
			return false
		}
	}
	return true
}

func ( string) bool {
	if len() == 0 {
		return false
	}
	,  := utf8.DecodeRuneInString()
	if  == utf8.RuneError &&  == 1 {
		return false
	}
	if !unicode.Is(first, ) {
		return false
	}
	for  < len() {
		 = [:]
		,  = utf8.DecodeRuneInString()
		if  == utf8.RuneError &&  == 1 {
			return false
		}
		if !unicode.Is(first, ) && !unicode.Is(second, ) {
			return false
		}
	}
	return true
}
These tables were generated by cut and paste from Appendix B of the XML spec at https://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. See the Decoder.Strict and Decoder.Entity fields' documentation.
hget http:www.w3.org/TR/html4/sgml/entities.html | ssam ' ,y /\&gt;/ x/\&lt;(.|\n)+/ s/\n/ /g ,x v/^\&lt;!ENTITY/d ,s/\&lt;!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. See the Decoder.Strict and Decoder.Entity fields' documentation.
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 (
	escQuot = []byte("&#34;") // shorter than "&quot;"
	escApos = []byte("&#39;") // shorter than "&apos;"
	escAmp  = []byte("&amp;")
	escLT   = []byte("&lt;")
	escGT   = []byte("&gt;")
	escTab  = []byte("&#x9;")
	escNL   = []byte("&#xA;")
	escCR   = []byte("&#xD;")
	escFFFD = []byte("\uFFFD") // Unicode replacement character
)
EscapeText writes to w the properly escaped XML equivalent of the plain text data s.
func ( io.Writer,  []byte) error {
	return escapeText(, , 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 ( io.Writer,  []byte,  bool) error {
	var  []byte
	 := 0
	for  := 0;  < len(); {
		,  := utf8.DecodeRune([:])
		 += 
		switch  {
		case '"':
			 = escQuot
		case '\'':
			 = escApos
		case '&':
			 = escAmp
		case '<':
			 = escLT
		case '>':
			 = escGT
		case '\t':
			 = escTab
		case '\n':
			if ! {
				continue
			}
			 = escNL
		case '\r':
			 = escCR
		default:
			if !isInCharacterRange() || ( == 0xFFFD &&  == 1) {
				 = escFFFD
				break
			}
			continue
		}
		if ,  := .Write([ : -]);  != nil {
			return 
		}
		if ,  := .Write();  != nil {
			return 
		}
		 = 
	}
	,  := .Write([:])
	return 
}
EscapeString writes to p the properly escaped XML equivalent of the plain text data s.
func ( *printer) ( string) {
	var  []byte
	 := 0
	for  := 0;  < len(); {
		,  := utf8.DecodeRuneInString([:])
		 += 
		switch  {
		case '"':
			 = escQuot
		case '\'':
			 = escApos
		case '&':
			 = escAmp
		case '<':
			 = escLT
		case '>':
			 = escGT
		case '\t':
			 = escTab
		case '\n':
			 = escNL
		case '\r':
			 = escCR
		default:
			if !isInCharacterRange() || ( == 0xFFFD &&  == 1) {
				 = escFFFD
				break
			}
			continue
		}
		.WriteString([ : -])
		.Write()
		 = 
	}
	.WriteString([:])
}
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 ( io.Writer,  []byte) {
	EscapeText(, )
}

var (
	cdataStart  = []byte("<![CDATA[")
	cdataEnd    = []byte("]]>")
	cdataEscape = []byte("]]]]><![CDATA[>")
)
emitCDATA writes to w the CDATA-wrapped plain text data s. It escapes CDATA directives nested in s.
func ( io.Writer,  []byte) error {
	if len() == 0 {
		return nil
	}
	if ,  := .Write(cdataStart);  != nil {
		return 
	}
	for {
		 := bytes.Index(, cdataEnd)
Found a nested CDATA directive end.
			if ,  := .Write([:]);  != nil {
				return 
			}
			if ,  := .Write(cdataEscape);  != nil {
				return 
			}
			 += len(cdataEnd)
		} else {
			if ,  := .Write();  != nil {
				return 
			}
			break
		}
		 = [:]
	}
	,  := .Write(cdataEnd)
	return 
}
procInst parses the `param="..."` or `param='...'` value out of the provided string, returning "" if not found.
TODO: this parsing is somewhat lame and not exact. It works for all actual cases, though.
	 =  + "="
	 := strings.Index(, )
	if  == -1 {
		return ""
	}
	 := [+len():]
	if  == "" {
		return ""
	}
	if [0] != '\'' && [0] != '"' {
		return ""
	}
	 = strings.IndexRune([1:], rune([0]))
	if  == -1 {
		return ""
	}
	return [1 : +1]