2011-03-19 13:50:46 +00:00
|
|
|
// This work is subject to the CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
|
|
|
|
// license. Its contents can be found at:
|
|
|
|
// http://creativecommons.org/publicdomain/zero/1.0/
|
2010-09-26 20:59:14 +00:00
|
|
|
|
2009-11-23 04:16:27 +00:00
|
|
|
package xmlx
|
|
|
|
|
2011-01-18 20:31:56 +00:00
|
|
|
import (
|
|
|
|
"bytes"
|
2011-11-09 13:56:55 +00:00
|
|
|
"encoding/xml"
|
2011-01-18 20:31:56 +00:00
|
|
|
"fmt"
|
|
|
|
"strconv"
|
|
|
|
)
|
2009-11-23 04:16:27 +00:00
|
|
|
|
|
|
|
const (
|
2010-08-22 03:07:38 +00:00
|
|
|
NT_ROOT = iota
|
|
|
|
NT_DIRECTIVE
|
|
|
|
NT_PROCINST
|
|
|
|
NT_COMMENT
|
2013-09-10 21:18:13 +00:00
|
|
|
NT_TEXT
|
2010-08-22 03:07:38 +00:00
|
|
|
NT_ELEMENT
|
2009-11-23 04:16:27 +00:00
|
|
|
)
|
|
|
|
|
2012-11-25 22:46:56 +00:00
|
|
|
// IndentPrefix holds the value for a single identation level, if one
|
|
|
|
// chooses to want indentation in the node.String() and node.Bytes() output.
|
|
|
|
// This would normally be set to a single tab, or a number of spaces.
|
|
|
|
var IndentPrefix = ""
|
|
|
|
|
2009-11-23 04:16:27 +00:00
|
|
|
type Attr struct {
|
2011-05-11 15:44:09 +00:00
|
|
|
Name xml.Name // Attribute namespace and name.
|
2013-08-29 21:29:22 +00:00
|
|
|
Value string // Attribute value.
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type Node struct {
|
2011-05-11 15:44:09 +00:00
|
|
|
Type byte // Node type.
|
|
|
|
Name xml.Name // Node namespace and name.
|
|
|
|
Children []*Node // Child nodes.
|
|
|
|
Attributes []*Attr // Node attributes.
|
|
|
|
Parent *Node // Parent node.
|
|
|
|
Value string // Node value.
|
|
|
|
Target string // procinst field.
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|
|
|
|
|
2010-08-22 03:07:38 +00:00
|
|
|
func NewNode(tid byte) *Node {
|
|
|
|
n := new(Node)
|
|
|
|
n.Type = tid
|
|
|
|
n.Children = make([]*Node, 0, 10)
|
|
|
|
n.Attributes = make([]*Attr, 0, 10)
|
|
|
|
return n
|
|
|
|
}
|
2009-11-23 04:16:27 +00:00
|
|
|
|
2010-05-06 03:36:48 +00:00
|
|
|
// This wraps the standard xml.Unmarshal function and supplies this particular
|
2009-12-02 18:38:35 +00:00
|
|
|
// node as the content to be unmarshalled.
|
2011-11-02 15:50:45 +00:00
|
|
|
func (this *Node) Unmarshal(obj interface{}) error {
|
2013-09-10 21:18:13 +00:00
|
|
|
return xml.NewDecoder(bytes.NewBuffer(this.bytes())).Decode(obj)
|
2009-12-02 18:38:35 +00:00
|
|
|
}
|
|
|
|
|
2009-11-23 05:40:57 +00:00
|
|
|
// Get node value as string
|
2010-12-19 20:45:42 +00:00
|
|
|
func (this *Node) S(namespace, name string) string {
|
2012-12-11 11:36:39 +00:00
|
|
|
node := rec_SelectNode(this, namespace, name)
|
|
|
|
if node != nil {
|
2010-12-19 20:45:42 +00:00
|
|
|
return node.Value
|
2010-05-06 03:36:48 +00:00
|
|
|
}
|
2010-12-19 20:45:42 +00:00
|
|
|
return ""
|
2009-11-23 05:40:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get node value as int
|
2010-12-19 20:45:42 +00:00
|
|
|
func (this *Node) I(namespace, name string) int {
|
2012-12-11 11:36:39 +00:00
|
|
|
node := rec_SelectNode(this, namespace, name)
|
|
|
|
if node != nil && node.Value != "" {
|
|
|
|
n, _ := strconv.ParseInt(node.Value, 10, 0)
|
|
|
|
return int(n)
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get node value as int8
|
|
|
|
func (this *Node) I8(namespace, name string) int8 {
|
|
|
|
node := rec_SelectNode(this, namespace, name)
|
|
|
|
if node != nil && node.Value != "" {
|
|
|
|
n, _ := strconv.ParseInt(node.Value, 10, 8)
|
|
|
|
return int8(n)
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get node value as int16
|
|
|
|
func (this *Node) I16(namespace, name string) int16 {
|
|
|
|
node := rec_SelectNode(this, namespace, name)
|
|
|
|
if node != nil && node.Value != "" {
|
|
|
|
n, _ := strconv.ParseInt(node.Value, 10, 16)
|
|
|
|
return int16(n)
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get node value as int32
|
|
|
|
func (this *Node) I32(namespace, name string) int32 {
|
|
|
|
node := rec_SelectNode(this, namespace, name)
|
|
|
|
if node != nil && node.Value != "" {
|
|
|
|
n, _ := strconv.ParseInt(node.Value, 10, 32)
|
|
|
|
return int32(n)
|
2010-05-06 03:36:48 +00:00
|
|
|
}
|
2010-12-19 20:45:42 +00:00
|
|
|
return 0
|
2009-11-23 05:40:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get node value as int64
|
2010-12-19 20:45:42 +00:00
|
|
|
func (this *Node) I64(namespace, name string) int64 {
|
2012-12-11 11:36:39 +00:00
|
|
|
node := rec_SelectNode(this, namespace, name)
|
|
|
|
if node != nil && node.Value != "" {
|
2011-12-07 12:53:17 +00:00
|
|
|
n, _ := strconv.ParseInt(node.Value, 10, 64)
|
2010-12-19 20:45:42 +00:00
|
|
|
return n
|
2010-05-06 03:36:48 +00:00
|
|
|
}
|
2010-12-19 20:45:42 +00:00
|
|
|
return 0
|
2009-11-23 05:40:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get node value as uint
|
2010-12-19 20:45:42 +00:00
|
|
|
func (this *Node) U(namespace, name string) uint {
|
2012-12-11 11:36:39 +00:00
|
|
|
node := rec_SelectNode(this, namespace, name)
|
|
|
|
if node != nil && node.Value != "" {
|
2011-12-07 12:53:17 +00:00
|
|
|
n, _ := strconv.ParseUint(node.Value, 10, 0)
|
2011-12-07 12:57:00 +00:00
|
|
|
return uint(n)
|
2010-05-06 03:36:48 +00:00
|
|
|
}
|
2010-12-19 20:45:42 +00:00
|
|
|
return 0
|
2009-11-23 05:40:57 +00:00
|
|
|
}
|
|
|
|
|
2012-12-11 11:36:39 +00:00
|
|
|
// Get node value as uint8
|
|
|
|
func (this *Node) U8(namespace, name string) uint8 {
|
|
|
|
node := rec_SelectNode(this, namespace, name)
|
|
|
|
if node != nil && node.Value != "" {
|
|
|
|
n, _ := strconv.ParseUint(node.Value, 10, 8)
|
|
|
|
return uint8(n)
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get node value as uint16
|
|
|
|
func (this *Node) U16(namespace, name string) uint16 {
|
|
|
|
node := rec_SelectNode(this, namespace, name)
|
|
|
|
if node != nil && node.Value != "" {
|
|
|
|
n, _ := strconv.ParseUint(node.Value, 10, 16)
|
|
|
|
return uint16(n)
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get node value as uint32
|
|
|
|
func (this *Node) U32(namespace, name string) uint32 {
|
|
|
|
node := rec_SelectNode(this, namespace, name)
|
|
|
|
if node != nil && node.Value != "" {
|
|
|
|
n, _ := strconv.ParseUint(node.Value, 10, 32)
|
|
|
|
return uint32(n)
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
2009-11-23 05:40:57 +00:00
|
|
|
// Get node value as uint64
|
2010-12-19 20:45:42 +00:00
|
|
|
func (this *Node) U64(namespace, name string) uint64 {
|
2012-12-11 11:36:39 +00:00
|
|
|
node := rec_SelectNode(this, namespace, name)
|
|
|
|
if node != nil && node.Value != "" {
|
2011-12-07 12:53:17 +00:00
|
|
|
n, _ := strconv.ParseUint(node.Value, 10, 64)
|
2010-12-19 20:45:42 +00:00
|
|
|
return n
|
2010-05-06 03:36:48 +00:00
|
|
|
}
|
2010-12-19 20:45:42 +00:00
|
|
|
return 0
|
2009-11-23 05:40:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get node value as float32
|
2010-12-19 20:45:42 +00:00
|
|
|
func (this *Node) F32(namespace, name string) float32 {
|
2012-12-11 11:36:39 +00:00
|
|
|
node := rec_SelectNode(this, namespace, name)
|
|
|
|
if node != nil && node.Value != "" {
|
2011-12-07 12:53:17 +00:00
|
|
|
n, _ := strconv.ParseFloat(node.Value, 32)
|
2011-12-07 12:57:00 +00:00
|
|
|
return float32(n)
|
2010-05-06 03:36:48 +00:00
|
|
|
}
|
2010-12-19 20:45:42 +00:00
|
|
|
return 0
|
2009-11-23 05:40:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get node value as float64
|
2010-12-19 20:45:42 +00:00
|
|
|
func (this *Node) F64(namespace, name string) float64 {
|
2012-12-11 11:36:39 +00:00
|
|
|
node := rec_SelectNode(this, namespace, name)
|
|
|
|
if node != nil && node.Value != "" {
|
2011-12-07 12:53:17 +00:00
|
|
|
n, _ := strconv.ParseFloat(node.Value, 64)
|
2010-12-19 20:45:42 +00:00
|
|
|
return n
|
2010-05-06 03:36:48 +00:00
|
|
|
}
|
2010-12-19 20:45:42 +00:00
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get node value as bool
|
|
|
|
func (this *Node) B(namespace, name string) bool {
|
2012-12-11 11:36:39 +00:00
|
|
|
node := rec_SelectNode(this, namespace, name)
|
|
|
|
if node != nil && node.Value != "" {
|
2011-12-07 12:53:17 +00:00
|
|
|
n, _ := strconv.ParseBool(node.Value)
|
2010-12-19 20:45:42 +00:00
|
|
|
return n
|
|
|
|
}
|
|
|
|
return false
|
2009-11-23 05:40:57 +00:00
|
|
|
}
|
|
|
|
|
2009-11-23 05:15:40 +00:00
|
|
|
// Get attribute value as string
|
2010-12-19 20:45:42 +00:00
|
|
|
func (this *Node) As(namespace, name string) string {
|
2010-05-06 03:36:48 +00:00
|
|
|
for _, v := range this.Attributes {
|
2011-02-01 14:29:35 +00:00
|
|
|
if (namespace == "*" || namespace == v.Name.Space) && name == v.Name.Local {
|
2010-05-06 03:36:48 +00:00
|
|
|
return v.Value
|
2009-11-23 05:15:40 +00:00
|
|
|
}
|
|
|
|
}
|
2010-05-06 03:36:48 +00:00
|
|
|
return ""
|
2009-11-23 05:15:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get attribute value as int
|
2010-12-19 20:45:42 +00:00
|
|
|
func (this *Node) Ai(namespace, name string) int {
|
2012-12-11 11:36:39 +00:00
|
|
|
s := this.As(namespace, name)
|
|
|
|
if s != "" {
|
|
|
|
n, _ := strconv.ParseInt(s, 10, 0)
|
|
|
|
return int(n)
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get attribute value as int8
|
|
|
|
func (this *Node) Ai8(namespace, name string) int8 {
|
|
|
|
s := this.As(namespace, name)
|
|
|
|
if s != "" {
|
|
|
|
n, _ := strconv.ParseInt(s, 10, 8)
|
|
|
|
return int8(n)
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get attribute value as int16
|
|
|
|
func (this *Node) Ai16(namespace, name string) int16 {
|
|
|
|
s := this.As(namespace, name)
|
|
|
|
if s != "" {
|
|
|
|
n, _ := strconv.ParseInt(s, 10, 16)
|
|
|
|
return int16(n)
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get attribute value as int32
|
|
|
|
func (this *Node) Ai32(namespace, name string) int32 {
|
|
|
|
s := this.As(namespace, name)
|
|
|
|
if s != "" {
|
|
|
|
n, _ := strconv.ParseInt(s, 10, 32)
|
|
|
|
return int32(n)
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get attribute value as int64
|
|
|
|
func (this *Node) Ai64(namespace, name string) int64 {
|
|
|
|
s := this.As(namespace, name)
|
|
|
|
if s != "" {
|
|
|
|
n, _ := strconv.ParseInt(s, 10, 64)
|
2010-12-19 20:45:42 +00:00
|
|
|
return n
|
2010-05-06 03:36:48 +00:00
|
|
|
}
|
2010-12-19 20:45:42 +00:00
|
|
|
return 0
|
2009-11-23 05:15:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get attribute value as uint
|
2010-12-19 20:45:42 +00:00
|
|
|
func (this *Node) Au(namespace, name string) uint {
|
2012-12-11 11:36:39 +00:00
|
|
|
s := this.As(namespace, name)
|
|
|
|
if s != "" {
|
2011-12-07 12:53:17 +00:00
|
|
|
n, _ := strconv.ParseUint(s, 10, 0)
|
2011-12-07 12:57:00 +00:00
|
|
|
return uint(n)
|
2010-05-06 03:36:48 +00:00
|
|
|
}
|
2010-12-19 20:45:42 +00:00
|
|
|
return 0
|
2009-11-23 05:15:40 +00:00
|
|
|
}
|
|
|
|
|
2012-12-11 11:36:39 +00:00
|
|
|
// Get attribute value as uint8
|
|
|
|
func (this *Node) Au8(namespace, name string) uint8 {
|
|
|
|
s := this.As(namespace, name)
|
|
|
|
if s != "" {
|
|
|
|
n, _ := strconv.ParseUint(s, 10, 8)
|
|
|
|
return uint8(n)
|
2010-05-06 03:36:48 +00:00
|
|
|
}
|
2010-12-19 20:45:42 +00:00
|
|
|
return 0
|
2009-11-23 05:15:40 +00:00
|
|
|
}
|
|
|
|
|
2012-12-11 11:36:39 +00:00
|
|
|
// Get attribute value as uint16
|
|
|
|
func (this *Node) Au16(namespace, name string) uint16 {
|
|
|
|
s := this.As(namespace, name)
|
|
|
|
if s != "" {
|
|
|
|
n, _ := strconv.ParseUint(s, 10, 16)
|
|
|
|
return uint16(n)
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get attribute value as uint32
|
|
|
|
func (this *Node) Au32(namespace, name string) uint32 {
|
|
|
|
s := this.As(namespace, name)
|
|
|
|
if s != "" {
|
|
|
|
n, _ := strconv.ParseUint(s, 10, 32)
|
|
|
|
return uint32(n)
|
|
|
|
}
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get attribute value as uint64
|
|
|
|
func (this *Node) Au64(namespace, name string) uint64 {
|
|
|
|
s := this.As(namespace, name)
|
|
|
|
if s != "" {
|
|
|
|
n, _ := strconv.ParseUint(s, 10, 64)
|
2010-12-19 20:45:42 +00:00
|
|
|
return n
|
2010-05-06 03:36:48 +00:00
|
|
|
}
|
2010-12-19 20:45:42 +00:00
|
|
|
return 0
|
2009-11-23 05:15:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get attribute value as float32
|
2010-12-19 20:45:42 +00:00
|
|
|
func (this *Node) Af32(namespace, name string) float32 {
|
2012-12-11 11:36:39 +00:00
|
|
|
s := this.As(namespace, name)
|
|
|
|
if s != "" {
|
2011-12-07 12:53:17 +00:00
|
|
|
n, _ := strconv.ParseFloat(s, 32)
|
2011-12-07 12:57:00 +00:00
|
|
|
return float32(n)
|
2010-05-06 03:36:48 +00:00
|
|
|
}
|
2010-12-19 20:45:42 +00:00
|
|
|
return 0
|
2009-11-23 05:15:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get attribute value as float64
|
2010-12-19 20:45:42 +00:00
|
|
|
func (this *Node) Af64(namespace, name string) float64 {
|
2012-12-11 11:36:39 +00:00
|
|
|
s := this.As(namespace, name)
|
|
|
|
if s != "" {
|
2011-12-07 12:53:17 +00:00
|
|
|
n, _ := strconv.ParseFloat(s, 64)
|
2010-12-19 20:45:42 +00:00
|
|
|
return n
|
2010-05-06 03:36:48 +00:00
|
|
|
}
|
2010-12-19 20:45:42 +00:00
|
|
|
return 0
|
2009-11-23 05:15:40 +00:00
|
|
|
}
|
|
|
|
|
2010-12-19 20:45:42 +00:00
|
|
|
// Get attribute value as bool
|
|
|
|
func (this *Node) Ab(namespace, name string) bool {
|
2012-12-11 11:36:39 +00:00
|
|
|
s := this.As(namespace, name)
|
|
|
|
if s != "" {
|
2011-12-07 12:53:17 +00:00
|
|
|
n, _ := strconv.ParseBool(s)
|
2010-12-19 20:45:42 +00:00
|
|
|
return n
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2009-11-23 05:15:40 +00:00
|
|
|
// Returns true if this node has the specified attribute. False otherwise.
|
|
|
|
func (this *Node) HasAttr(namespace, name string) bool {
|
2010-05-06 03:36:48 +00:00
|
|
|
for _, v := range this.Attributes {
|
2011-07-13 03:17:00 +00:00
|
|
|
if namespace != "*" && namespace != v.Name.Space {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
if name == "*" || name == v.Name.Local {
|
2009-11-23 05:15:40 +00:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
2011-07-13 03:17:00 +00:00
|
|
|
|
2009-11-23 05:15:40 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// Select single node by name
|
2009-11-23 04:16:27 +00:00
|
|
|
func (this *Node) SelectNode(namespace, name string) *Node {
|
2010-05-06 03:36:48 +00:00
|
|
|
return rec_SelectNode(this, namespace, name)
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func rec_SelectNode(cn *Node, namespace, name string) *Node {
|
2011-07-13 03:17:00 +00:00
|
|
|
if (namespace == "*" || cn.Name.Space == namespace) && (name == "*" || cn.Name.Local == name) {
|
2010-05-06 03:36:48 +00:00
|
|
|
return cn
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|
|
|
|
|
2010-08-22 03:07:38 +00:00
|
|
|
var tn *Node
|
2009-11-23 04:16:27 +00:00
|
|
|
for _, v := range cn.Children {
|
2010-08-22 03:07:38 +00:00
|
|
|
if tn = rec_SelectNode(v, namespace, name); tn != nil {
|
2010-05-06 03:36:48 +00:00
|
|
|
return tn
|
|
|
|
}
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|
2011-07-13 03:17:00 +00:00
|
|
|
|
2010-05-06 03:36:48 +00:00
|
|
|
return nil
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|
|
|
|
|
2009-11-23 05:15:40 +00:00
|
|
|
// Select multiple nodes by name
|
2009-11-23 04:16:27 +00:00
|
|
|
func (this *Node) SelectNodes(namespace, name string) []*Node {
|
2010-08-22 03:07:38 +00:00
|
|
|
list := make([]*Node, 0, 16)
|
2012-07-29 19:28:03 +00:00
|
|
|
rec_SelectNodes(this, namespace, name, &list, false)
|
2010-05-06 03:36:48 +00:00
|
|
|
return list
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|
|
|
|
|
2012-07-29 19:28:03 +00:00
|
|
|
// Select multiple nodes by name
|
|
|
|
func (this *Node) SelectNodesRecursive(namespace, name string) []*Node {
|
|
|
|
list := make([]*Node, 0, 16)
|
|
|
|
rec_SelectNodes(this, namespace, name, &list, true)
|
|
|
|
return list
|
|
|
|
}
|
|
|
|
|
|
|
|
func rec_SelectNodes(cn *Node, namespace, name string, list *[]*Node, recurse bool) {
|
2011-07-13 03:17:00 +00:00
|
|
|
if (namespace == "*" || cn.Name.Space == namespace) && (name == "*" || cn.Name.Local == name) {
|
2010-11-05 00:26:35 +00:00
|
|
|
*list = append(*list, cn)
|
2012-07-29 19:28:03 +00:00
|
|
|
if !recurse {
|
|
|
|
return
|
|
|
|
}
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, v := range cn.Children {
|
2012-07-29 19:28:03 +00:00
|
|
|
rec_SelectNodes(v, namespace, name, list, recurse)
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-29 21:29:22 +00:00
|
|
|
func (this *Node) RemoveNameSpace() {
|
|
|
|
this.Name.Space = ""
|
2013-08-29 22:19:26 +00:00
|
|
|
// this.RemoveAttr("xmlns") //This is questionable
|
|
|
|
|
|
|
|
for _, v := range this.Children {
|
|
|
|
v.RemoveNameSpace()
|
|
|
|
}
|
2013-08-29 21:38:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (this *Node) RemoveAttr(name string) {
|
|
|
|
for i, v := range this.Attributes {
|
|
|
|
if name == v.Name.Local {
|
|
|
|
//Delete it
|
|
|
|
this.Attributes = append(this.Attributes[:i], this.Attributes[i+1:]...)
|
|
|
|
}
|
|
|
|
}
|
2013-08-29 21:29:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (this *Node) SetAttr(name, value string) {
|
|
|
|
for _, v := range this.Attributes {
|
|
|
|
if name == v.Name.Local {
|
|
|
|
v.Value = value
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//Add
|
|
|
|
attr := new(Attr)
|
|
|
|
attr.Name.Local = name
|
|
|
|
attr.Name.Space = ""
|
|
|
|
attr.Value = value
|
|
|
|
this.Attributes = append(this.Attributes, attr)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2011-05-11 15:44:09 +00:00
|
|
|
// Convert node to appropriate []byte representation based on it's @Type.
|
2010-05-06 03:36:48 +00:00
|
|
|
// Note that NT_ROOT is a special-case empty node used as the root for a
|
2009-11-23 05:15:40 +00:00
|
|
|
// Document. This one has no representation by itself. It merely forwards the
|
|
|
|
// String() call to it's child nodes.
|
2013-09-10 21:18:13 +00:00
|
|
|
func (this *Node) Bytes() []byte { return this.bytes() }
|
2012-11-25 22:46:56 +00:00
|
|
|
|
2013-09-10 21:18:13 +00:00
|
|
|
func (this *Node) bytes() (b []byte) {
|
2009-11-23 04:16:27 +00:00
|
|
|
switch this.Type {
|
|
|
|
case NT_PROCINST:
|
2013-09-10 21:18:13 +00:00
|
|
|
b = this.printProcInst()
|
2009-11-23 04:16:27 +00:00
|
|
|
case NT_COMMENT:
|
2013-09-10 21:18:13 +00:00
|
|
|
b = this.printComment()
|
2009-11-23 04:16:27 +00:00
|
|
|
case NT_DIRECTIVE:
|
2013-09-10 21:18:13 +00:00
|
|
|
b = this.printDirective()
|
2009-11-23 04:16:27 +00:00
|
|
|
case NT_ELEMENT:
|
2013-09-10 21:18:13 +00:00
|
|
|
b = this.printElement()
|
|
|
|
case NT_TEXT:
|
|
|
|
b = this.printText()
|
2009-11-23 04:16:27 +00:00
|
|
|
case NT_ROOT:
|
2013-09-10 21:18:13 +00:00
|
|
|
b = this.printRoot()
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|
2010-05-06 03:36:48 +00:00
|
|
|
return
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|
|
|
|
|
2011-05-11 15:44:09 +00:00
|
|
|
// Convert node to appropriate string representation based on it's @Type.
|
|
|
|
// Note that NT_ROOT is a special-case empty node used as the root for a
|
|
|
|
// Document. This one has no representation by itself. It merely forwards the
|
|
|
|
// String() call to it's child nodes.
|
|
|
|
func (this *Node) String() (s string) {
|
2013-09-10 21:18:13 +00:00
|
|
|
return string(this.bytes())
|
2011-05-11 15:44:09 +00:00
|
|
|
}
|
|
|
|
|
2013-09-10 21:18:13 +00:00
|
|
|
func (this *Node) printRoot() []byte {
|
2011-05-11 15:44:09 +00:00
|
|
|
var b bytes.Buffer
|
2009-11-23 04:16:27 +00:00
|
|
|
for _, v := range this.Children {
|
2013-09-10 21:18:13 +00:00
|
|
|
b.Write(v.bytes())
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|
2011-05-11 15:44:09 +00:00
|
|
|
return b.Bytes()
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|
|
|
|
|
2013-09-10 21:18:13 +00:00
|
|
|
func (this *Node) printProcInst() []byte {
|
2011-05-11 15:44:09 +00:00
|
|
|
return []byte("<?" + this.Target + " " + this.Value + "?>")
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|
|
|
|
|
2013-09-10 21:18:13 +00:00
|
|
|
func (this *Node) printComment() []byte {
|
2011-05-11 15:44:09 +00:00
|
|
|
return []byte("<!-- " + this.Value + " -->")
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|
|
|
|
|
2013-09-10 21:18:13 +00:00
|
|
|
func (this *Node) printDirective() []byte {
|
2011-05-11 15:44:09 +00:00
|
|
|
return []byte("<!" + this.Value + "!>")
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|
|
|
|
|
2013-09-10 21:18:13 +00:00
|
|
|
func (this *Node) printText() []byte {
|
|
|
|
val := []byte(this.Value)
|
|
|
|
if len(this.Parent.Children) > 1 {
|
|
|
|
return val
|
|
|
|
}
|
2011-05-11 15:44:09 +00:00
|
|
|
var b bytes.Buffer
|
2013-09-10 21:18:13 +00:00
|
|
|
xml.EscapeText(&b, val)
|
|
|
|
return b.Bytes()
|
|
|
|
}
|
2010-08-22 03:07:38 +00:00
|
|
|
|
2013-09-10 21:18:13 +00:00
|
|
|
func (this *Node) printElement() []byte {
|
|
|
|
var b bytes.Buffer
|
2012-11-25 22:46:56 +00:00
|
|
|
|
2009-11-23 04:16:27 +00:00
|
|
|
if len(this.Name.Space) > 0 {
|
2011-05-11 15:44:09 +00:00
|
|
|
b.WriteRune('<')
|
|
|
|
b.WriteString(this.Name.Space)
|
|
|
|
b.WriteRune(':')
|
|
|
|
b.WriteString(this.Name.Local)
|
2009-11-23 04:16:27 +00:00
|
|
|
} else {
|
2011-05-11 15:44:09 +00:00
|
|
|
b.WriteRune('<')
|
|
|
|
b.WriteString(this.Name.Local)
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, v := range this.Attributes {
|
|
|
|
if len(v.Name.Space) > 0 {
|
2013-09-03 22:35:22 +00:00
|
|
|
prefix := this.spacePrefix(v.Name.Space)
|
|
|
|
b.WriteString(fmt.Sprintf(` %s:%s="%s"`, prefix, v.Name.Local, v.Value))
|
2009-11-23 04:16:27 +00:00
|
|
|
} else {
|
2011-05-11 15:44:09 +00:00
|
|
|
b.WriteString(fmt.Sprintf(` %s="%s"`, v.Name.Local, v.Value))
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(this.Children) == 0 && len(this.Value) == 0 {
|
2011-05-11 15:44:09 +00:00
|
|
|
b.WriteString(" />")
|
|
|
|
return b.Bytes()
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|
|
|
|
|
2011-05-11 15:44:09 +00:00
|
|
|
b.WriteRune('>')
|
2009-11-23 04:16:27 +00:00
|
|
|
|
|
|
|
for _, v := range this.Children {
|
2013-09-10 21:18:13 +00:00
|
|
|
b.Write(v.bytes())
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|
|
|
|
|
2013-09-10 21:18:13 +00:00
|
|
|
xml.EscapeText(&b, []byte(this.Value))
|
2009-11-23 04:16:27 +00:00
|
|
|
if len(this.Name.Space) > 0 {
|
2011-05-11 15:44:09 +00:00
|
|
|
b.WriteString("</")
|
|
|
|
b.WriteString(this.Name.Space)
|
|
|
|
b.WriteRune(':')
|
|
|
|
b.WriteString(this.Name.Local)
|
|
|
|
b.WriteRune('>')
|
2009-11-23 04:16:27 +00:00
|
|
|
} else {
|
2011-05-11 15:44:09 +00:00
|
|
|
b.WriteString("</")
|
|
|
|
b.WriteString(this.Name.Local)
|
|
|
|
b.WriteRune('>')
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|
2010-08-22 03:07:38 +00:00
|
|
|
|
2011-05-11 15:44:09 +00:00
|
|
|
return b.Bytes()
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|
|
|
|
|
2013-09-03 22:35:22 +00:00
|
|
|
// spacePrefix resolves the given space (e.g. a url) to the prefix it was
|
|
|
|
// assigned by an attribute by the current node, or one of its parents.
|
|
|
|
func (this *Node) spacePrefix(space string) string {
|
|
|
|
for _, attr := range this.Attributes {
|
|
|
|
if attr.Name.Space == "xmlns" && attr.Value == space {
|
|
|
|
return attr.Name.Local
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if this.Parent == nil {
|
|
|
|
return space
|
|
|
|
}
|
|
|
|
return this.Parent.spacePrefix(space)
|
|
|
|
}
|
|
|
|
|
2009-11-23 05:15:40 +00:00
|
|
|
// Add a child node
|
2009-11-23 04:16:27 +00:00
|
|
|
func (this *Node) AddChild(t *Node) {
|
|
|
|
if t.Parent != nil {
|
|
|
|
t.Parent.RemoveChild(t)
|
|
|
|
}
|
2010-05-06 03:36:48 +00:00
|
|
|
t.Parent = this
|
2010-11-05 00:26:35 +00:00
|
|
|
this.Children = append(this.Children, t)
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|
|
|
|
|
2009-11-23 05:15:40 +00:00
|
|
|
// Remove a child node
|
2009-11-23 04:16:27 +00:00
|
|
|
func (this *Node) RemoveChild(t *Node) {
|
2010-05-06 03:36:48 +00:00
|
|
|
p := -1
|
2009-11-23 04:16:27 +00:00
|
|
|
for i, v := range this.Children {
|
|
|
|
if v == t {
|
2010-05-06 03:36:48 +00:00
|
|
|
p = i
|
|
|
|
break
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-06 03:36:48 +00:00
|
|
|
if p == -1 {
|
2009-11-23 04:16:27 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2010-08-22 03:07:38 +00:00
|
|
|
copy(this.Children[p:], this.Children[p+1:])
|
|
|
|
this.Children = this.Children[0 : len(this.Children)-1]
|
2009-11-23 04:16:27 +00:00
|
|
|
|
2010-05-06 03:36:48 +00:00
|
|
|
t.Parent = nil
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|