func (parser *Parser) parseAttribute() *Attribute {
	attrNSIdx := parser.getLEWord(parser.ParserOffset)
	attrNameIdx := parser.getLEWord(parser.ParserOffset + (1 * WORD_SIZE))
	attrValueIdx := parser.getLEWord(parser.ParserOffset + (2 * WORD_SIZE))
	attrType := parser.getLEWord(parser.ParserOffset + (3 * WORD_SIZE))
	attrData := parser.getLEWord(parser.ParserOffset + (4 * WORD_SIZE))
	attr := new(Attribute)
	attr.Name = parser.getString(attrNameIdx)
	if int64(attrNSIdx) == 0xFFFFFFFF {
		attr.Namespace = ""
		attr.Prefix = ""
	} else {
		uri := parser.getString(attrNSIdx)
		if v, ok := parser.Namespaces[uri]; ok {
			attr.Namespace = uri
			attr.Prefix = v
		}
	}
	if int64(attrValueIdx) == 0xFFFFFFFF {
		attr.Value = parser.getAttributeValue(attrType, attrData)
	} else {
		attr.Value = parser.getString(attrValueIdx)
	}
	return attr
}
An attribute will have the following 4bytes words :
<ul>
<li>0th word : index of namespace uri in StringIndexTable, or 0xFFFFFFFF
for default NS</li>
<li>1st word : index of attribute name in StringIndexTable</li>
<li>2nd word : index of attribute value, or 0xFFFFFFFF if value is a
typed value</li>
<li>3rd word : value type</li>
<li>4th word : resource id value</li>
</ul>
package axmlParser
import (
	"bytes"
	"encoding/binary"
	"fmt"
	"strconv"
)
const (
	TAG = "CXP"
	WORD_START_DOCUMENT = 0x00080003
	WORD_STRING_TABLE = 0x001C0001
	WORD_RES_TABLE    = 0x00080180
	WORD_START_NS  = 0x00100100
	WORD_END_NS    = 0x00100101
	WORD_START_TAG = 0x00100102
	WORD_END_TAG   = 0x00100103
	WORD_TEXT      = 0x00100104
	WORD_EOS       = 0xFFFFFFFF
	WORD_SIZE      = 4
	TYPE_ID_REF   = 0x01000008
	TYPE_ATTR_REF = 0x02000008
	TYPE_STRING   = 0x03000008
	TYPE_DIMEN    = 0x05000008
	TYPE_FRACTION = 0x06000008
	TYPE_INT      = 0x10000008
	TYPE_FLOAT    = 0x04000008
	TYPE_FLAGS  = 0x11000008
	TYPE_BOOL   = 0x12000008
	TYPE_COLOR  = 0x1C000008
	TYPE_COLOR2 = 0x1D000008
)
var (
	DIMEN = []string{"px", "dp", "sp",
		"pt", "in", "mm"}
)
type Parser struct {
	listener Listener
	Namespaces map[string]string
	Data       []byte
	StringsTable                        []string
	ResourcesIds                        []int
	StringsCount, StylesCount, ResCount int
	ParserOffset                        int
}
func New(listener Listener) *Parser {
	return &Parser{
		listener:     listener,
		Namespaces:   make(map[string]string),
		Data:         make([]byte, 0),
		StringsTable: make([]string, 0),
		ResourcesIds: make([]int, 0),
	}
}
func (parser *Parser) IsValid(header []byte) bool {
	return (header[0] == 0x03) && (header[1] == 0x00) &&
		(header[2] == 0x08) && (header[3] == 0x00)
}
func (parser *Parser) Parse(data []byte) error {
	var word0 int64
	parser.Data = data
	for parser.ParserOffset < len(parser.Data) {
		word0 = int64(parser.getLEWord(parser.ParserOffset))
		switch word0 {
		case WORD_START_DOCUMENT:
			parser.parseStartDocument()
		case WORD_STRING_TABLE:
			parser.parseStringTable()
		case WORD_RES_TABLE:
			parser.parseResourceTable()
		case WORD_START_NS:
			parser.parseNamespace(true)
		case WORD_END_NS:
			parser.parseNamespace(false)
		case WORD_START_TAG:
			parser.parseStartTag()
		case WORD_END_TAG:
			parser.parseEndTag()
		case WORD_TEXT:
			parser.parseText()
		case WORD_EOS:
			parser.listener.EndDocument()
		default:
			parser.ParserOffset += WORD_SIZE
		}
	}
	parser.listener.EndDocument()
	return nil
}
func (parser *Parser) parseStartDocument() {
	parser.listener.StartDocument()
	parser.ParserOffset += (2 * WORD_SIZE)
}
func (parser *Parser) parseStringTable() {
	chunk := parser.getLEWord(parser.ParserOffset + (1 * WORD_SIZE))
	parser.StringsCount = parser.getLEWord(parser.ParserOffset + (2 * WORD_SIZE))
	parser.StylesCount = parser.getLEWord(parser.ParserOffset + (3 * WORD_SIZE))
	strOffset := parser.ParserOffset + parser.getLEWord(parser.ParserOffset+(5*WORD_SIZE))
	styleOffset := parser.getLEWord(parser.ParserOffset + (6 * WORD_SIZE))
	parser.StringsTable = make([]string, parser.StringsCount)
	var offset int
	for i := 0; i < int(parser.StringsCount); i++ {
		offset = strOffset + parser.getLEWord(parser.ParserOffset+((i+7)*WORD_SIZE))
		parser.StringsTable[i] = parser.getStringFromStringTable(offset)
	}
	if styleOffset > 0 {
		for i := 0; i < parser.StylesCount; i++ {
		}
	}
	parser.ParserOffset += chunk
}
func (parser *Parser) parseResourceTable() {
	chunk := parser.getLEWord(parser.ParserOffset + (1 * WORD_SIZE))
	parser.ResCount = (chunk / 4) - 2
	parser.ResourcesIds = make([]int, parser.ResCount)
	for i := 0; i < parser.ResCount; i++ {
		parser.ResourcesIds[i] = parser.getLEWord(parser.ParserOffset + ((i + 2) * WORD_SIZE))
	}
	parser.ParserOffset += chunk
}
func (parser *Parser) parseNamespace(start bool) {
	prefixIdx := parser.getLEWord(parser.ParserOffset + (4 * WORD_SIZE))
	uriIdx := parser.getLEWord(parser.ParserOffset + (5 * WORD_SIZE))
	uri := parser.getString(uriIdx)
	prefix := parser.getString(prefixIdx)
	if start {
		parser.listener.StartPrefixMapping(prefix, uri)
		parser.Namespaces[uri] = prefix
	} else {
		parser.listener.EndPrefixMapping(prefix, uri)
		delete(parser.Namespaces, uri)
	}
	parser.ParserOffset += (6 * WORD_SIZE)
}
func (parser *Parser) parseStartTag() {
	uriIdx := parser.getLEWord(parser.ParserOffset + (4 * WORD_SIZE))
	nameIdx := parser.getLEWord(parser.ParserOffset + (5 * WORD_SIZE))
	attrCount := parser.getLEWord(parser.ParserOffset + (7 * WORD_SIZE))
	name := parser.getString(nameIdx)
	var uri, qname string
	if int64(uriIdx) == 0xFFFFFFFF {
		uri = ""
		qname = name
	} else {
		uri = parser.getString(uriIdx)
		if v, ok := parser.Namespaces[uri]; ok {
			qname = v + ":" + name
		} else {
			qname = name
		}
	}
	parser.ParserOffset += (9 * WORD_SIZE)
	attrs := make([]*Attribute, attrCount)  
	for a := 0; a < attrCount; a++ {
		attrs[a] = parser.parseAttribute()  
		parser.ParserOffset += (5 * 4)
	}
	parser.listener.StartElement(uri, name, qname, attrs)
}