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 (
	
	
	
	
)
typeInfo holds details for the xml representation of a type.
fieldInfo holds details for the xml representation of a single field.
getTypeInfo returns the typeInfo structure with details necessary for marshaling and unmarshaling typ.
func ( reflect.Type) (*typeInfo, error) {
	if ,  := tinfoMap.Load();  {
		return .(*typeInfo), nil
	}

	 := &typeInfo{}
	if .Kind() == reflect.Struct &&  != nameType {
		 := .NumField()
		for  := 0;  < ; ++ {
			 := .Field()
			if (.PkgPath != "" && !.Anonymous) || .Tag.Get("xml") == "-" {
				continue // Private field
			}
For embedded structs, embed its fields.
			if .Anonymous {
				 := .Type
				if .Kind() == reflect.Ptr {
					 = .Elem()
				}
				if .Kind() == reflect.Struct {
					,  := ()
					if  != nil {
						return nil, 
					}
					if .xmlname == nil {
						.xmlname = .xmlname
					}
					for ,  := range .fields {
						.idx = append([]int{}, .idx...)
						if  := addFieldInfo(, , &);  != nil {
							return nil, 
						}
					}
					continue
				}
			}

			,  := structFieldInfo(, &)
			if  != nil {
				return nil, 
			}

			if .Name == xmlName {
				.xmlname = 
				continue
			}
Add the field if it doesn't conflict with other fields.
			if  := addFieldInfo(, , );  != nil {
				return nil, 
			}
		}
	}

	,  := tinfoMap.LoadOrStore(, )
	return .(*typeInfo), nil
}
structFieldInfo builds and returns a fieldInfo for f.
Split the tag from the xml namespace if necessary.
	 := .Tag.Get("xml")
	if  := strings.Index(, " ");  >= 0 {
		.xmlns,  = [:], [+1:]
	}
Parse flags.
	 := strings.Split(, ",")
	if len() == 1 {
		.flags = fElement
	} else {
		 = [0]
		for ,  := range [1:] {
			switch  {
			case "attr":
				.flags |= fAttr
			case "cdata":
				.flags |= fCDATA
			case "chardata":
				.flags |= fCharData
			case "innerxml":
				.flags |= fInnerXML
			case "comment":
				.flags |= fComment
			case "any":
				.flags |= fAny
			case "omitempty":
				.flags |= fOmitEmpty
			}
		}
Validate the flags used.
		 := true
		switch  := .flags & fMode;  {
		case 0:
			.flags |= fElement
		case fAttr, fCDATA, fCharData, fInnerXML, fComment, fAny, fAny | fAttr:
			if .Name == xmlName ||  != "" &&  != fAttr {
				 = false
			}
This will also catch multiple modes in a single field.
			 = false
		}
		if .flags&fMode == fAny {
			.flags |= fElement
		}
		if .flags&fOmitEmpty != 0 && .flags&(fElement|fAttr) == 0 {
			 = false
		}
		if ! {
			return nil, fmt.Errorf("xml: invalid tag in field %s of type %s: %q",
				.Name, , .Tag.Get("xml"))
		}
	}
Use of xmlns without a name is not allowed.
	if .xmlns != "" &&  == "" {
		return nil, fmt.Errorf("xml: namespace without name in field %s of type %s: %q",
			.Name, , .Tag.Get("xml"))
	}

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.
		.name = 
		return , nil
	}

If the name part of the tag is completely empty, get default from XMLName of underlying struct if feasible, or field name otherwise.
		if  := lookupXMLName(.Type);  != nil {
			.xmlns, .name = .xmlns, .name
		} else {
			.name = .Name
		}
		return , nil
	}
Prepare field name and parents.
	 := strings.Split(, ">")
	if [0] == "" {
		[0] = .Name
	}
	if [len()-1] == "" {
		return nil, fmt.Errorf("xml: trailing '>' in field %s of type %s", .Name, )
	}
	.name = [len()-1]
	if len() > 1 {
		if (.flags & fElement) == 0 {
			return nil, fmt.Errorf("xml: %s chain not valid with %s flag", , strings.Join([1:], ","))
		}
		.parents = [:len()-1]
	}
If the field type has an XMLName field, the names must match so that the behavior of both marshaling and unmarshaling is straightforward and unambiguous.
	if .flags&fElement != 0 {
		 := .Type
		 := lookupXMLName()
		if  != nil && .name != .name {
			return nil, fmt.Errorf("xml: name %q in tag of %s.%s conflicts with name %q in %s.XMLName",
				.name, , .Name, .name, )
		}
	}
	return , 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 ( reflect.Type) ( *fieldInfo) {
	for .Kind() == reflect.Ptr {
		 = .Elem()
	}
	if .Kind() != reflect.Struct {
		return nil
	}
	for ,  := 0, .NumField();  < ; ++ {
		 := .Field()
		if .Name != xmlName {
			continue
		}
		,  := structFieldInfo(, &)
		if  == nil && .name != "" {
			return 
Also consider errors as a non-existent field tag and let getTypeInfo itself report the error.
		break
	}
	return nil
}

func (,  int) int {
	if  <=  {
		return 
	}
	return 
}
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 ( reflect.Type,  *typeInfo,  *fieldInfo) error {
	var  []int
First, figure all conflicts. Most working code will have none.
	for  := range .fields {
		 := &.fields[]
		if .flags&fMode != .flags&fMode {
			continue
		}
		if .xmlns != "" && .xmlns != "" && .xmlns != .xmlns {
			continue
		}
		 := min(len(.parents), len(.parents))
		for  := 0;  < ; ++ {
			if .parents[] != .parents[] {
				continue 
			}
		}
		if len(.parents) > len(.parents) {
			if .parents[len(.parents)] == .name {
				 = append(, )
			}
		} else if len(.parents) < len(.parents) {
			if .parents[len(.parents)] == .name {
				 = append(, )
			}
		} else {
			if .name == .name {
				 = append(, )
			}
		}
Without conflicts, add the new field and return.
	if  == nil {
		.fields = append(.fields, *)
		return nil
	}
If any conflict is shallower, ignore the new field. This matches the Go field resolution on embedding.
	for ,  := range  {
		if len(.fields[].idx) < len(.idx) {
			return nil
		}
	}
Otherwise, if any of them is at the same depth level, it's an error.
	for ,  := range  {
		 := &.fields[]
		if len(.idx) == len(.idx) {
			 := .FieldByIndex(.idx)
			 := .FieldByIndex(.idx)
			return &TagPathError{, .Name, .Tag.Get("xml"), .Name, .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  := len() - 1;  >= 0; -- {
		 := []
		copy(.fields[:], .fields[+1:])
		.fields = .fields[:len(.fields)-1]
	}
	.fields = append(.fields, *)
	return nil
}
A TagPathError represents an error in the unmarshaling process caused by the use of field tags with conflicting paths.
type TagPathError struct {
	Struct       reflect.Type
	Field1, Tag1 string
	Field2, Tag2 string
}

func ( *TagPathError) () string {
	return fmt.Sprintf("%s field %q with tag %q conflicts with field %q with tag %q", .Struct, .Field1, .Tag1, .Field2, .Tag2)
}

const (
	initNilPointers     = true
	dontInitNilPointers = false
)
value returns v's field value corresponding to finfo. It's equivalent to v.FieldByIndex(finfo.idx), but when passed initNilPointers, it initializes and dereferences pointers as necessary. When passed dontInitNilPointers and a nil pointer is reached, the function returns a zero reflect.Value.
func ( *fieldInfo) ( reflect.Value,  bool) reflect.Value {
	for ,  := range .idx {
		if  > 0 {
			 := .Type()
			if .Kind() == reflect.Ptr && .Elem().Kind() == reflect.Struct {
				if .IsNil() {
					if ! {
						return reflect.Value{}
					}
					.Set(reflect.New(.Type().Elem()))
				}
				 = .Elem()
			}
		}
		 = .Field()
	}
	return