func ByteDocToMap(doc []byte, recast ...bool) (map[string]interface{}, error) {
	var r bool
	if len(recast) == 1 {
		r = recast[0]
	}
	return xmlToMap(doc, r)
}
ByteDocToMap - convert an XML doc into a map[string]interface{}.
(This is analogous to unmarshalling a JSON string to map[string]interface{} using json.Unmarshal().)
If the optional argument 'recast' is 'true', then values will be converted to boolean or float64 if possible.
Note: recasting is only applied to element values, not attribute values.
package x2j
import (
	"bytes"
	"encoding/json"
	"encoding/xml"
	"errors"
	"fmt"
	"io"
	"regexp"
	"strconv"
	"strings"
)
var X2jCharsetReader func(charset string, input io.Reader)(io.Reader, error)
type Node struct {
	dup   bool    
	attr  bool    
	key   string  
	val   string  
	nodes []*Node
}
func DocToJson(doc string, recast ...bool) (string, error) {
	var r bool
	if len(recast) == 1 {
		r = recast[0]
	}
	m, merr := xmlToMap([]byte(doc), r)
	if m == nil || merr != nil {
		return "", merr
	}
	b, berr := json.Marshal(m)
	if berr != nil {
		return "", berr
	}
	return string(b), nil
}
func DocToJsonIndent(doc string, recast ...bool) (string, error) {
	var r bool
	if len(recast) == 1 {
		r = recast[0]
	}
	m, merr := xmlToMap([]byte(doc), r)
	if m == nil || merr != nil {
		return "", merr
	}
	b, berr := json.MarshalIndent(m, "", "  ")
	if berr != nil {
		return "", berr
	}
	return string(b), nil
}
func DocToMap(doc string, recast ...bool) (map[string]interface{}, error) {
	var r bool
	if len(recast) == 1 {
		r = recast[0]
	}
	return xmlToMap([]byte(doc), r)
}
func DocToTree(doc string) (*Node, error) {
	reg, _ := regexp.Compile("[ \t\n\r]*<")
	doc = reg.ReplaceAllString(doc, "<")
	b := bytes.NewBufferString(doc)
	p := xml.NewDecoder(b)
	p.CharsetReader = X2jCharsetReader
	n, berr := xmlToTree("", nil, p)
	if berr != nil {
		return nil, berr
	}
	return n, nil
}
func (n *Node) WriteTree(padding ...int) string {
	var indent int
	if len(padding) == 1 {
		indent = padding[0]
	}
	var s string
	if n.val != "" {
		for i := 0; i < indent; i++ {
			s += "  "
		}
		s += n.key + " : " + n.val + "\n"
	} else {
		for i := 0; i < indent; i++ {
			s += "  "
		}
		s += n.key + " :" + "\n"
		for _, nn := range n.nodes {
			s += nn.WriteTree(indent + 1)
		}
	}
	return s
}
func xmlToTree(skey string, a []xml.Attr, p *xml.Decoder) (*Node, error) {
	n := new(Node)
	n.nodes = make([]*Node, 0)
	if skey != "" {
		n.key = skey
		if len(a) > 0 {
			for _, v := range a {
				na := new(Node)
				na.attr = true
				na.key = `-` + v.Name.Local
				na.val = v.Value
				n.nodes = append(n.nodes, na)
			}
		}
	}
	for {
		t, err := p.Token()
		if err != nil {
			return nil, err
		}
		switch t.(type) {
		case xml.StartElement:
			tt := t.(xml.StartElement)
			if n.key == "" {
				n.key = tt.Name.Local
				if len(tt.Attr) > 0 {
					for _, v := range tt.Attr {
						na := new(Node)
						na.attr = true
						na.key = `-` + v.Name.Local
						na.val = v.Value
						n.nodes = append(n.nodes, na)
					}
				}
			} else {
				nn, nnerr := xmlToTree(tt.Name.Local, tt.Attr, p)
				if nnerr != nil {
					return nil, nnerr
				}
				n.nodes = append(n.nodes, nn)
			}
		case xml.EndElement:
			n.markDuplicateKeys()
			return n, nil
		case xml.CharData:
			tt := string(t.(xml.CharData))
			tt = strings.Trim(tt,"\t\r\b\n ")
			if len(n.nodes) > 0 && len(tt) > 0 {
				nn := new(Node)
				nn.key = "#text"
				nn.val = tt
				n.nodes = append(n.nodes, nn)
			} else {
				n.val = tt
			}
		default:
		}
	}
	return nil, errors.New("Unknown parse error in xmlToTree() for: " + n.key)
}
func (n *Node) markDuplicateKeys() {
	l := len(n.nodes)
	for i := 0; i < l; i++ {
		if n.nodes[i].dup {
			continue
		}
		for j := i + 1; j < l; j++ {
			if n.nodes[i].key == n.nodes[j].key {
				n.nodes[i].dup = true
				n.nodes[j].dup = true
			}
		}
	}
}
func (n *Node) treeToMap(r bool) interface{} {
	if len(n.nodes) == 0 {
		return recast(n.val, r)
	}
	m := make(map[string]interface{}, 0)
	for _, v := range n.nodes {
		if !v.dup && len(v.nodes) == 0 {
			m[v.key] = recast(v.val, r)
			continue
		}
		if v.dup {
			var a []interface{}
			if vv, ok := m[v.key]; ok {
				a = vv.([]interface{})
			} else {
				a = make([]interface{}, 0)
			}
			a = append(a, v.treeToMap(r))
			m[v.key] = interface{}(a)
			continue
		}
		m[v.key] = v.treeToMap(r)
	}
	return interface{}(m)
}
func recast(s string, r bool) interface{} {
	if r {
		if f, err := strconv.ParseFloat(s, 64); err == nil {
			return interface{}(f)
		}
		if b, err := strconv.ParseBool(s); err == nil {
			return interface{}(b)
		}
	}
	return interface{}(s)
}
func WriteMap(m interface{}, offset ...int) string {
	var indent int
	if len(offset) == 1 {
		indent = offset[0]
	}
	var s string
	switch m.(type) {
	case nil:
		return "[nil] nil"
	case string:
		return "[string] " + m.(string)
	case float64:
		return "[float64] " + strconv.FormatFloat(m.(float64), 'e', 2, 64)
	case bool:
		return "[bool] " + strconv.FormatBool(m.(bool))
	case []interface{}:
		s += "[[]interface{}]"
		for i, v := range m.([]interface{}) {
			s += "\n"
			for i := 0; i < indent; i++ {
				s += "  "
			}
			s += "[item: " + strconv.FormatInt(int64(i), 10) + "]"
			switch v.(type) {
			case string, float64, bool:
				s += "\n"
			default:
			}
			for i := 0; i < indent; i++ {
				s += "  "
			}
			s += WriteMap(v, indent+1)
		}
	case map[string]interface{}:
		for k, v := range m.(map[string]interface{}) {
			s += "\n"
			for i := 0; i < indent; i++ {
				s += "  "
			}
			s += k + " :" + WriteMap(v, indent+1)
		}
	default:
		s += fmt.Sprintf("unknown type for: %v", m)
	}
	return s
}
func DocValue(doc, path string, attrs ...string) (interface{}, error) {
	m, err := xmlToMap([]byte(doc), false)
	if err != nil {
		return nil, err
	}
	a, err := NewAttributeMap(attrs...)
	if err != nil {
		return nil, err
	}
	v, verr := MapValue(m, path, a)
	if verr != nil {
		return nil, verr
	}
	return v, nil
}
func MapValue(m map[string]interface{}, path string, attr map[string]interface{}, r ...bool) (interface{}, error) {
	if len(r) == 1 && r[0] == true {
		for k, v := range attr {
			attr[k] = recast(v.(string), true)
		}
	}
	keys := strings.Split(path, ".")
	var v interface{} = m
	var ok bool
	var okey string
	var isMap bool = true
	if keys[0] == "" && len(attr) == 0 {
		return v, nil
	}
	for _, key := range keys {
		if !isMap {
			return nil, errors.New("no keys beyond: " + okey)
		}
		if v, ok = m[key]; !ok {
			return nil, errors.New("no key in map: " + key)
		} else {
			switch v.(type) {
			case map[string]interface{}:
				m = v.(map[string]interface{})
				isMap = true
			default:
				isMap = false
			}
		}
		okey = key
	}
	if attr == nil {
		return v, nil
	}
	return hasAttributes(v, attr)
}
func hasAttributes(v interface{}, a map[string]interface{}) (interface{}, error) {
	switch v.(type) {
	case []interface{}:
		for _, vv := range v.([]interface{}) {
			if vvv, vvverr := hasAttributes(vv, a); vvverr == nil {
				return vvv, nil
			}
		}
		return nil, errors.New("no list member with matching attributes")
	case map[string]interface{}:
		nv := v.(map[string]interface{})
		for key, val := range a {
			if vv, ok := nv[key]; !ok {
				return nil, errors.New("no attribute with name: " + key[1:])
			} else if val != vv {
				return nil, errors.New("no attribute key:value pair: " + fmt.Sprintf("%s:%v", key[1:], val))
			}
		}
		if vv, ok := nv["#text"]; ok {
			return vv, nil
		} else {
			return nv, nil
		}
	}
	return nil, errors.New("no match for attributes")
}
func NewAttributeMap(kv ...string) (map[string]interface{}, error) {
	if len(kv) == 0 {
		return nil, nil
	}
	m := make(map[string]interface{}, 0)
	for _, v := range kv {
		vv := strings.Split(v, ":")
		if len(vv) != 2 {
			return nil, errors.New("attribute not \"name:value\" pair: " + v)
		}
		m["-"+vv[0]] = interface{}(vv[1])
	}
	return m, nil
}
func ValuesForTag(doc, tag string) ([]interface{}, error) {
	m, err := DocToMap(doc)
	if err != nil {
		return nil, err
	}
	return ValuesForKey(m, tag), nil
}
func ValuesForKey(m map[string]interface{}, key string) []interface{} {
	ret := make([]interface{}, 0)
	hasKey(m, key, &ret)
	if len(ret) > 0 {
		return ret
	}
	return nil
}
func hasKey(iv interface{}, key string, ret *[]interface{}) {
	switch iv.(type) {
	case map[string]interface{}:
		vv := iv.(map[string]interface{})
		if v, ok := vv[key]; ok {
			*ret = append(*ret, v)
		}
		for _, v := range iv.(map[string]interface{}) {
			hasKey(v, key, ret)
		}
	case []interface{}:
		for _, v := range iv.([]interface{}) {
			hasKey(v, key, ret)
		}
	}
}
func Unmarshal(doc []byte, v interface{}) error {
	switch v.(type) {
	case *map[string]interface{}:
		m, err := ByteDocToMap(doc)
		vv := *v.(*map[string]interface{})
		for k, v := range m {
			vv[k] = v
		}
		return err
	case *string:
		s, err := ByteDocToJson(doc)
		*(v.(*string)) = s
		return err
	default:
		b := bytes.NewBuffer(doc)
		p := xml.NewDecoder(b)
		p.CharsetReader = X2jCharsetReader
		return p.Decode(v)
	}
	return nil
}
func ByteDocToJson(doc []byte, recast ...bool) (string, error) {
	var r bool
	if len(recast) == 1 {
		r = recast[0]
	}
	m, merr := ByteDocToMap(doc, r)
	if m == nil || merr != nil {
		return "", merr
	}
	b, berr := json.Marshal(m)
	if berr != nil {
		return "", berr
	}
	return string(b), nil
}