2009-11-23 04:16:27 +00:00
|
|
|
package xmlx
|
|
|
|
|
2009-12-02 18:38:35 +00:00
|
|
|
import "os"
|
|
|
|
import "strings"
|
2009-11-23 04:16:27 +00:00
|
|
|
import "xml"
|
|
|
|
import "fmt"
|
2009-11-23 05:15:40 +00:00
|
|
|
import "strconv"
|
2009-11-23 04:16:27 +00:00
|
|
|
|
|
|
|
const (
|
2010-05-06 03:36:48 +00:00
|
|
|
NT_ROOT = 0x00
|
|
|
|
NT_DIRECTIVE = 0x01
|
|
|
|
NT_PROCINST = 0x02
|
|
|
|
NT_COMMENT = 0x03
|
|
|
|
NT_ELEMENT = 0x04
|
2009-11-23 04:16:27 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type Attr struct {
|
2010-05-06 03:36:48 +00:00
|
|
|
Name xml.Name
|
|
|
|
Value string
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type Node struct {
|
2010-05-06 03:36:48 +00:00
|
|
|
Type byte
|
|
|
|
Name xml.Name
|
|
|
|
Children []*Node
|
|
|
|
Attributes []Attr
|
|
|
|
Parent *Node
|
|
|
|
Value string
|
|
|
|
Target string // procinst field
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|
|
|
|
|
2010-05-06 03:36:48 +00:00
|
|
|
func NewNode(tid byte) *Node { return &Node{Type: tid} }
|
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.
|
|
|
|
func (this *Node) Unmarshal(obj interface{}) os.Error {
|
2010-05-06 03:36:48 +00:00
|
|
|
return xml.Unmarshal(strings.NewReader(this.String()), obj)
|
2009-12-02 18:38:35 +00:00
|
|
|
}
|
|
|
|
|
2009-11-23 05:40:57 +00:00
|
|
|
// Get node value as string
|
|
|
|
func (this *Node) GetValue(namespace, name string) string {
|
2010-05-06 03:36:48 +00:00
|
|
|
node := rec_SelectNode(this, namespace, name)
|
|
|
|
if node == nil {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
return node.Value
|
2009-11-23 05:40:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get node value as int
|
|
|
|
func (this *Node) GetValuei(namespace, name string) int {
|
2010-05-06 03:36:48 +00:00
|
|
|
node := rec_SelectNode(this, namespace, name)
|
|
|
|
if node == nil {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
if node.Value == "" {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
n, _ := strconv.Atoi(node.Value)
|
|
|
|
return n
|
2009-11-23 05:40:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get node value as int64
|
|
|
|
func (this *Node) GetValuei64(namespace, name string) int64 {
|
2010-05-06 03:36:48 +00:00
|
|
|
node := rec_SelectNode(this, namespace, name)
|
|
|
|
if node == nil {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
if node.Value == "" {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
n, _ := strconv.Atoi64(node.Value)
|
|
|
|
return n
|
2009-11-23 05:40:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get node value as uint
|
|
|
|
func (this *Node) GetValueui(namespace, name string) uint {
|
2010-05-06 03:36:48 +00:00
|
|
|
node := rec_SelectNode(this, namespace, name)
|
|
|
|
if node == nil {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
if node.Value == "" {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
n, _ := strconv.Atoui(node.Value)
|
|
|
|
return n
|
2009-11-23 05:40:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get node value as uint64
|
|
|
|
func (this *Node) GetValueui64(namespace, name string) uint64 {
|
2010-05-06 03:36:48 +00:00
|
|
|
node := rec_SelectNode(this, namespace, name)
|
|
|
|
if node == nil {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
if node.Value == "" {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
n, _ := strconv.Atoui64(node.Value)
|
|
|
|
return n
|
2009-11-23 05:40:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get node value as float
|
|
|
|
func (this *Node) GetValuef(namespace, name string) float {
|
2010-05-06 03:36:48 +00:00
|
|
|
node := rec_SelectNode(this, namespace, name)
|
|
|
|
if node == nil {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
if node.Value == "" {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
n, _ := strconv.Atof(node.Value)
|
|
|
|
return n
|
2009-11-23 05:40:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get node value as float32
|
|
|
|
func (this *Node) GetValuef32(namespace, name string) float32 {
|
2010-05-06 03:36:48 +00:00
|
|
|
node := rec_SelectNode(this, namespace, name)
|
|
|
|
if node == nil {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
if node.Value == "" {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
n, _ := strconv.Atof32(node.Value)
|
|
|
|
return n
|
2009-11-23 05:40:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get node value as float64
|
|
|
|
func (this *Node) GetValuef64(namespace, name string) float64 {
|
2010-05-06 03:36:48 +00:00
|
|
|
node := rec_SelectNode(this, namespace, name)
|
|
|
|
if node == nil {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
if node.Value == "" {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
n, _ := strconv.Atof64(node.Value)
|
|
|
|
return n
|
2009-11-23 05:40:57 +00:00
|
|
|
}
|
|
|
|
|
2009-11-23 05:15:40 +00:00
|
|
|
// Get attribute value as string
|
|
|
|
func (this *Node) GetAttr(namespace, name string) string {
|
2010-05-06 03:36:48 +00:00
|
|
|
for _, v := range this.Attributes {
|
2009-11-23 05:15:40 +00:00
|
|
|
if 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
|
|
|
|
func (this *Node) GetAttri(namespace, name string) int {
|
2010-05-06 03:36:48 +00:00
|
|
|
s := this.GetAttr(namespace, name)
|
|
|
|
if s == "" {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
n, _ := strconv.Atoi(s)
|
|
|
|
return n
|
2009-11-23 05:15:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get attribute value as uint
|
|
|
|
func (this *Node) GetAttrui(namespace, name string) uint {
|
2010-05-06 03:36:48 +00:00
|
|
|
s := this.GetAttr(namespace, name)
|
|
|
|
if s == "" {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
n, _ := strconv.Atoui(s)
|
|
|
|
return n
|
2009-11-23 05:15:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get attribute value as uint64
|
|
|
|
func (this *Node) GetAttrui64(namespace, name string) uint64 {
|
2010-05-06 03:36:48 +00:00
|
|
|
s := this.GetAttr(namespace, name)
|
|
|
|
if s == "" {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
n, _ := strconv.Atoui64(s)
|
|
|
|
return n
|
2009-11-23 05:15:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get attribute value as int64
|
|
|
|
func (this *Node) GetAttri64(namespace, name string) int64 {
|
2010-05-06 03:36:48 +00:00
|
|
|
s := this.GetAttr(namespace, name)
|
|
|
|
if s == "" {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
n, _ := strconv.Atoi64(s)
|
|
|
|
return n
|
2009-11-23 05:15:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get attribute value as float
|
|
|
|
func (this *Node) GetAttrf(namespace, name string) float {
|
2010-05-06 03:36:48 +00:00
|
|
|
s := this.GetAttr(namespace, name)
|
|
|
|
if s == "" {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
n, _ := strconv.Atof(s)
|
|
|
|
return n
|
2009-11-23 05:15:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get attribute value as float32
|
|
|
|
func (this *Node) GetAttrf32(namespace, name string) float32 {
|
2010-05-06 03:36:48 +00:00
|
|
|
s := this.GetAttr(namespace, name)
|
|
|
|
if s == "" {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
n, _ := strconv.Atof32(s)
|
|
|
|
return n
|
2009-11-23 05:15:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get attribute value as float64
|
|
|
|
func (this *Node) GetAttrf64(namespace, name string) float64 {
|
2010-05-06 03:36:48 +00:00
|
|
|
s := this.GetAttr(namespace, name)
|
|
|
|
if s == "" {
|
|
|
|
return 0
|
|
|
|
}
|
|
|
|
n, _ := strconv.Atof64(s)
|
|
|
|
return n
|
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 {
|
2009-11-23 05:15:40 +00:00
|
|
|
if namespace == v.Name.Space && name == v.Name.Local {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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 {
|
|
|
|
if cn.Name.Space == namespace && cn.Name.Local == name {
|
2010-05-06 03:36:48 +00:00
|
|
|
return cn
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, v := range cn.Children {
|
2010-05-06 03:36:48 +00:00
|
|
|
tn := rec_SelectNode(v, namespace, name)
|
|
|
|
if tn != nil {
|
|
|
|
return tn
|
|
|
|
}
|
2009-11-23 04:16:27 +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-05-06 03:36:48 +00:00
|
|
|
list := make([]*Node, 0)
|
|
|
|
rec_SelectNodes(this, namespace, name, &list)
|
|
|
|
return list
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func rec_SelectNodes(cn *Node, namespace, name string, list *[]*Node) {
|
|
|
|
if cn.Name.Space == namespace && cn.Name.Local == name {
|
2010-05-06 03:36:48 +00:00
|
|
|
c := make([]*Node, len(*list)+1)
|
|
|
|
copy(c, *list)
|
|
|
|
c[len(c)-1] = cn
|
|
|
|
*list = c
|
2009-11-23 04:16:27 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, v := range cn.Children {
|
2010-05-06 03:36:48 +00:00
|
|
|
rec_SelectNodes(v, namespace, name, list)
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-23 05:15:40 +00:00
|
|
|
// Convert node to appropriate string 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.
|
2009-11-23 04:16:27 +00:00
|
|
|
func (this *Node) String() (s string) {
|
|
|
|
switch this.Type {
|
|
|
|
case NT_PROCINST:
|
|
|
|
s = this.printProcInst()
|
|
|
|
case NT_COMMENT:
|
|
|
|
s = this.printComment()
|
|
|
|
case NT_DIRECTIVE:
|
|
|
|
s = this.printDirective()
|
|
|
|
case NT_ELEMENT:
|
|
|
|
s = this.printElement()
|
|
|
|
case NT_ROOT:
|
|
|
|
s = this.printRoot()
|
|
|
|
}
|
2010-05-06 03:36:48 +00:00
|
|
|
return
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (this *Node) printRoot() (s string) {
|
|
|
|
for _, v := range this.Children {
|
|
|
|
s += v.String()
|
|
|
|
}
|
2010-05-06 03:36:48 +00:00
|
|
|
return
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (this *Node) printProcInst() (s string) {
|
2010-05-06 03:36:48 +00:00
|
|
|
s = "<?" + this.Target + " " + this.Value + "?>"
|
|
|
|
return
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (this *Node) printComment() (s string) {
|
2010-05-06 03:36:48 +00:00
|
|
|
s = "<!-- " + this.Value + " -->"
|
|
|
|
return
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (this *Node) printDirective() (s string) {
|
2010-05-06 03:36:48 +00:00
|
|
|
s = "<!" + this.Value + "!>"
|
|
|
|
return
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (this *Node) printElement() (s string) {
|
|
|
|
if len(this.Name.Space) > 0 {
|
|
|
|
s = "<" + this.Name.Space + ":" + this.Name.Local
|
|
|
|
} else {
|
|
|
|
s = "<" + this.Name.Local
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, v := range this.Attributes {
|
|
|
|
if len(v.Name.Space) > 0 {
|
|
|
|
s += fmt.Sprintf(` %s:%s="%s"`, v.Name.Space, v.Name.Local, v.Value)
|
|
|
|
} else {
|
|
|
|
s += fmt.Sprintf(` %s="%s"`, v.Name.Local, v.Value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(this.Children) == 0 && len(this.Value) == 0 {
|
2010-05-06 03:36:48 +00:00
|
|
|
s += " />"
|
|
|
|
return
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|
|
|
|
|
2010-05-06 03:36:48 +00:00
|
|
|
s += ">"
|
2009-11-23 04:16:27 +00:00
|
|
|
|
|
|
|
for _, v := range this.Children {
|
|
|
|
s += v.String()
|
|
|
|
}
|
|
|
|
|
2010-05-06 03:36:48 +00:00
|
|
|
s += this.Value
|
2009-11-23 04:16:27 +00:00
|
|
|
if len(this.Name.Space) > 0 {
|
|
|
|
s += "</" + this.Name.Space + ":" + this.Name.Local + ">"
|
|
|
|
} else {
|
|
|
|
s += "</" + this.Name.Local + ">"
|
|
|
|
}
|
2010-05-06 03:36:48 +00:00
|
|
|
return
|
2009-11-23 04:16:27 +00:00
|
|
|
}
|
|
|
|
|
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
|
2009-11-23 04:16:27 +00:00
|
|
|
|
2010-05-06 03:36:48 +00:00
|
|
|
c := make([]*Node, len(this.Children)+1)
|
|
|
|
copy(c, this.Children)
|
|
|
|
c[len(c)-1] = t
|
|
|
|
this.Children = c
|
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-05-06 03:36:48 +00:00
|
|
|
c := make([]*Node, len(this.Children)-1)
|
|
|
|
copy(c, this.Children[0:p])
|
|
|
|
copy(c[p:], this.Children[p+1:])
|
|
|
|
this.Children = c
|
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
|
|
|
}
|