Example #1
0
// Walks through the documents elements and populates the buffer.
func (self *Formatter) walk(node xml.Node) {
	for c := node.FirstChild(); c != nil; c = c.NextSibling() {
		self.walk(c)
	}

	if node.NodeType() == xml.XML_ELEMENT_NODE {
		self.handleNode(node)
	}
}
Example #2
0
func (this *Document) walkElements(node xml.Node, f func(xml.Node) error) error {
	f(node)
	for child := node.FirstChild(); child != nil; child = child.NextSibling() {
		err := this.walkElements(child, f)
		if err != nil {
			return err
		}
	}
	return nil
}
Example #3
0
// 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 gokoxml.Node) (err error) {
	recurse := false
	name := start.Name() // For speed

Loop:
	for i := range tinfo.fields {
		finfo := &tinfo.fields[i]
		if finfo.flags&fElement == 0 || len(finfo.parents) < len(parents) {
			continue
		}
		for j := range parents {
			if parents[j] != finfo.parents[j] {
				continue Loop
			}
		}
		if len(finfo.parents) == len(parents) && finfo.name == name {
			// It's a perfect match, unmarshal the field.
			return p.unmarshal(sv.FieldByIndex(finfo.idx), start)
		}
		if len(finfo.parents) > len(parents) && finfo.parents[len(parents)] == name {
			// 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 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 cur_node := start.FirstChild(); cur_node != nil; cur_node = cur_node.NextSibling() {
		if cur_node.NodeType() != gokoxml.XML_ELEMENT_NODE {
			continue
		}

		if err := p.unmarshalPath(tinfo, sv, parents, cur_node); err != nil {
			return err
		}
	}

	// No more XML Nodes.
	return nil
}
Example #4
0
func removeNonAnchorElements(node xml.Node) {
	var next xml.Node
	for n := node.FirstChild(); n != nil; n = next {
		next = n.NextSibling()

		if n.NodeType() == xml.XML_ELEMENT_NODE {
			removeNonAnchorElements(n)

			if strings.ToLower(n.Name()) != "a" {
				var chNext xml.Node
				for ch := n.FirstChild(); ch != nil; ch = chNext {
					chNext = ch.NextSibling()
					ch.Unlink()
					n.InsertBefore(ch)
				}
				n.Remove()
			}
		}
	}
}
Example #5
0
func (p *Decoder) unmarshal(val reflect.Value, start gokoxml.Node) error {
	// Find first xml node.
	if start == nil {
		start = p.doc.Root().XmlNode
	}

	// Unpacks a pointer
	if pv := val; pv.Kind() == reflect.Ptr {
		if pv.IsNil() {
			pv.Set(reflect.New(pv.Type().Elem()))
		}
		val = pv.Elem()
	}

	var (
		sv    reflect.Value
		tinfo *typeInfo
		err   error
	)

	switch v := val; v.Kind() {
	default:
		return errors.New("unknown type " + v.Type().String())

		// TODO: Implement this once i understand Skip()
		// case reflect.Interface:
		// 	return p.Skip()

	case reflect.Slice:
		typ := v.Type()
		if typ.Elem().Kind() == reflect.Uint8 {
			// []byte
			if err := copyValue(v, start.Content()); err != nil {
				return err
			}
			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:
		if err := copyValue(v, start.Content()); err != nil {
			return err
		}

	case reflect.Struct:
		typ := v.Type()
		if typ == nameType {
			v.Set(reflect.ValueOf(xml.Name{Local: start.Name()}))
			break
		}
		if typ == timeType {
			if err := copyValue(v, start.Content()); err != nil {
				return err
			}
			break
		}

		sv = v
		tinfo, err = getTypeInfo(typ)
		if err != nil {
			return err
		}

		// Validate and assign element name.
		if tinfo.xmlname != nil {
			// var space string
			finfo := tinfo.xmlname
			if finfo.name != "" && finfo.name != start.Name() {
				return UnmarshalError("expected element type <" + finfo.name + "> but have <" + start.Name() + ">")
			}

			fv := sv.FieldByIndex(finfo.idx)
			if _, ok := fv.Interface().(xml.Name); ok {
				fv.Set(reflect.ValueOf(xml.Name{Local: start.Name()}))
			}
		}

		var saveComment reflect.Value
		var doSaveComment = false
		_ = saveComment

		for i := range tinfo.fields {
			finfo := &tinfo.fields[i]
			switch finfo.flags & fMode {
			case fAttr:
				strv := sv.FieldByIndex(finfo.idx)
				for name, a := range start.Attributes() {
					if name == finfo.name {
						copyValue(strv, a.Content())
					}
				}
			case fCharData:
				strv := sv.FieldByIndex(finfo.idx)
				copyValue(strv, start.Content())

			case fInnerXml:
				strv := sv.FieldByIndex(finfo.idx)
				// TODO: Not sure why i need to call FirstChild() here.
				copyValue(strv, start.FirstChild().String())

			case fComment:
				if !doSaveComment {
					doSaveComment = true
					saveComment = sv.FieldByIndex(finfo.idx)
				}
			}
		}

		for cur_node := start.FirstChild(); cur_node != nil; cur_node = cur_node.NextSibling() {
			if sv.IsValid() {
				if cur_node.NodeType() != gokoxml.XML_ELEMENT_NODE {
					if doSaveComment && cur_node.NodeType() == gokoxml.XML_COMMENT_NODE {
						copyValue(saveComment, cur_node.Content())
					}
					continue
				}

				err = p.unmarshalPath(tinfo, sv, nil, cur_node)
				if err != nil {
					return err
				}
			}
		}

	} // switch v := val; v.Kind() {

	return nil
}