fixed some slice copy routines

This commit is contained in:
jim teeuwen 2010-05-06 05:36:48 +02:00
parent 379dfddd5b
commit 6a776b0cda
5 changed files with 602 additions and 558 deletions

View File

@ -14,13 +14,13 @@
The Document currently implements 2 simple search functions which allow you to The Document currently implements 2 simple search functions which allow you to
look for specific nodes. look for specific nodes.
Document.SelectNode(namespace, name string) *Node; Document.SelectNode(namespace, name string) *Node;
Document.SelectNodes(namespace, name string) []*Node; Document.SelectNodes(namespace, name string) []*Node;
SelectNode() returns the first, single node it finds matching the given name SelectNode() returns the first, single node it finds matching the given name
and namespace. SelectNodes() returns a slice containing all the matching nodes. and namespace. SelectNodes() returns a slice containing all the matching nodes.
Note that these search functions can be invoked on individual nodes as well. Note that these search functions can be invoked on individual nodes as well.
This allows you to search only a subset of the entire document. This allows you to search only a subset of the entire document.
@ -35,23 +35,23 @@ import "fmt"
import "http" import "http"
type Document struct { type Document struct {
Version string; Version string
Encoding string; Encoding string
StandAlone string; StandAlone string
SaveDocType bool; SaveDocType bool
Root *Node; Root *Node
Entity map[string]string; Entity map[string]string
Verbose bool; Verbose bool
} }
func New() *Document { func New() *Document {
return &Document{ return &Document{
Version: "1.0", Version: "1.0",
Encoding: "utf-8", Encoding: "utf-8",
StandAlone: "yes", StandAlone: "yes",
SaveDocType: true, SaveDocType: true,
Entity: make(map[string]string), Entity: make(map[string]string),
Verbose: false Verbose: false,
} }
} }
@ -60,89 +60,87 @@ func New() *Document {
// set only those entities needed manually using the document.Entity map, but // set only those entities needed manually using the document.Entity map, but
// if need be, this method can be called to fill the map with the entire set // if need be, this method can be called to fill the map with the entire set
// defined on http://www.w3.org/TR/html4/sgml/entities.html // defined on http://www.w3.org/TR/html4/sgml/entities.html
func (this *Document) LoadExtendedEntityMap() { func (this *Document) LoadExtendedEntityMap() { loadNonStandardEntities(&this.Entity) }
loadNonStandardEntities(&this.Entity);
}
func (this *Document) String() string { func (this *Document) String() string {
s, _ := this.SaveString(); s, _ := this.SaveString()
return s; return s
} }
func (this *Document) SelectNode(namespace, name string) *Node { func (this *Document) SelectNode(namespace, name string) *Node {
return this.Root.SelectNode(namespace, name); return this.Root.SelectNode(namespace, name)
} }
func (this *Document) SelectNodes(namespace, name string) []*Node { func (this *Document) SelectNodes(namespace, name string) []*Node {
return this.Root.SelectNodes(namespace, name); return this.Root.SelectNodes(namespace, name)
} }
// ***************************************************************************** // *****************************************************************************
// *** Satisfy ILoader interface // *** Satisfy ILoader interface
// ***************************************************************************** // *****************************************************************************
func (this *Document) LoadString(s string) (err os.Error) { func (this *Document) LoadString(s string) (err os.Error) {
xp := xml.NewParser(strings.NewReader(s)); xp := xml.NewParser(strings.NewReader(s))
xp.Entity = this.Entity; xp.Entity = this.Entity
this.Root = NewNode(NT_ROOT); this.Root = NewNode(NT_ROOT)
ct := this.Root; ct := this.Root
for { for {
tok, err := xp.Token(); tok, err := xp.Token()
if err != nil { if err != nil {
if err != os.EOF && this.Verbose { if err != os.EOF && this.Verbose {
fmt.Fprintf(os.Stderr, "Xml Error: %s\n", err); fmt.Fprintf(os.Stderr, "Xml Error: %s\n", err)
} }
return return
} }
t1, ok := tok.(xml.SyntaxError); t1, ok := tok.(xml.SyntaxError)
if ok { if ok {
err = os.NewError(t1.String()); err = os.NewError(t1.String())
return return
} }
t2, ok := tok.(xml.CharData); t2, ok := tok.(xml.CharData)
if ok && ct != nil { if ok && ct != nil {
ct.Value = strings.TrimSpace(string(t2)); ct.Value = strings.TrimSpace(string(t2))
continue continue
} }
t3, ok := tok.(xml.Comment); t3, ok := tok.(xml.Comment)
if ok && ct != nil { if ok && ct != nil {
t := NewNode(NT_COMMENT); t := NewNode(NT_COMMENT)
t.Value = strings.TrimSpace(string(t3)); t.Value = strings.TrimSpace(string(t3))
ct.AddChild(t); ct.AddChild(t)
continue continue
} }
t4, ok := tok.(xml.Directive); t4, ok := tok.(xml.Directive)
if ok && ct != nil { if ok && ct != nil {
t := NewNode(NT_DIRECTIVE); t := NewNode(NT_DIRECTIVE)
t.Value = strings.TrimSpace(string(t4)); t.Value = strings.TrimSpace(string(t4))
ct.AddChild(t); ct.AddChild(t)
continue continue
} }
t5, ok := tok.(xml.StartElement); t5, ok := tok.(xml.StartElement)
if ok && ct != nil { if ok && ct != nil {
t := NewNode(NT_ELEMENT); t := NewNode(NT_ELEMENT)
t.Name = t5.Name; t.Name = t5.Name
t.Attributes = make([]Attr, len(t5.Attr)); t.Attributes = make([]Attr, len(t5.Attr))
for i, v := range t5.Attr { for i, v := range t5.Attr {
t.Attributes[i].Name = v.Name; t.Attributes[i].Name = v.Name
t.Attributes[i].Value = v.Value; t.Attributes[i].Value = v.Value
} }
ct.AddChild(t); ct.AddChild(t)
ct = t; ct = t
continue continue
} }
t6, ok := tok.(xml.ProcInst); t6, ok := tok.(xml.ProcInst)
if ok { if ok {
if t6.Target == "xml" { // xml doctype if t6.Target == "xml" { // xml doctype
doctype := strings.TrimSpace(string(t6.Inst)); doctype := strings.TrimSpace(string(t6.Inst))
/* // Not needed. There is only xml version 1.0 /* // Not needed. There is only xml version 1.0
pos := strings.Index(doctype, `version="`); pos := strings.Index(doctype, `version="`);
if pos > -1 { if pos > -1 {
@ -153,7 +151,7 @@ func (this *Document) LoadString(s string) (err os.Error) {
*/ */
/* // Not needed. Any string we handle in Go is UTF8 /* // Not needed. Any string we handle in Go is UTF8
// encoded. This means we will save UTF8 data as well. // encoded. This means we will save UTF8 data as well.
pos = strings.Index(doctype, `encoding="`); pos = strings.Index(doctype, `encoding="`);
if pos > -1 { if pos > -1 {
this.Encoding = doctype[pos+len(`encoding="`) : len(doctype)]; this.Encoding = doctype[pos+len(`encoding="`) : len(doctype)];
@ -162,100 +160,106 @@ func (this *Document) LoadString(s string) (err os.Error) {
} }
*/ */
pos := strings.Index(doctype, `standalone="`); pos := strings.Index(doctype, `standalone="`)
if pos > -1 { if pos > -1 {
this.StandAlone = doctype[pos+len(`standalone="`) : len(doctype)]; this.StandAlone = doctype[pos+len(`standalone="`) : len(doctype)]
pos = strings.Index(this.StandAlone, `"`); pos = strings.Index(this.StandAlone, `"`)
this.StandAlone = this.StandAlone[0:pos]; this.StandAlone = this.StandAlone[0:pos]
} }
} else if ct != nil { } else if ct != nil {
t := NewNode(NT_PROCINST); t := NewNode(NT_PROCINST)
t.Target = strings.TrimSpace(t6.Target); t.Target = strings.TrimSpace(t6.Target)
t.Value = strings.TrimSpace(string(t6.Inst)); t.Value = strings.TrimSpace(string(t6.Inst))
ct.AddChild(t); ct.AddChild(t)
} }
continue continue
} }
_, ok = tok.(xml.EndElement); _, ok = tok.(xml.EndElement)
if ok { if ok {
ct = ct.Parent; ct = ct.Parent
continue continue
} }
} }
return; return
} }
func (this *Document) LoadFile(path string) (err os.Error) { func (this *Document) LoadFile(path string) (err os.Error) {
file, err := os.Open(path, os.O_RDONLY, 0600); file, err := os.Open(path, os.O_RDONLY, 0600)
if err != nil { if err != nil {
return return
} }
defer file.Close(); defer file.Close()
content := ""; content := ""
buff := make([]byte, 256); buff := make([]byte, 256)
for { for {
_, err := file.Read(buff); _, err := file.Read(buff)
if err != nil { if err != nil {
break break
} }
content += string(buff); content += string(buff)
} }
err = this.LoadString(content); err = this.LoadString(content)
return; return
} }
func (this *Document) LoadUri(uri string) (err os.Error) { func (this *Document) LoadUri(uri string) (err os.Error) {
r, _, err := http.Get(uri); r, _, err := http.Get(uri)
if err != nil { if err != nil {
return return
} }
defer r.Body.Close(); defer r.Body.Close()
b, err := io.ReadAll(r.Body); data := ""
if err != nil { b := make([]byte, 256)
return
for {
n, err := io.ReadFull(r.Body, b)
if n == 0 || err == os.EOF {
break
}
data += string(b)
} }
err = this.LoadString(string(b)); err = this.LoadString(data)
return; return
} }
func (this *Document) LoadStream(r *io.Reader) (err os.Error) { func (this *Document) LoadStream(r *io.Reader) (err os.Error) {
content := ""; content := ""
buff := make([]byte, 256); buff := make([]byte, 256)
for { for {
_, err := r.Read(buff); _, err := r.Read(buff)
if err != nil { if err != nil {
break break
} }
content += string(buff); content += string(buff)
} }
err = this.LoadString(content); err = this.LoadString(content)
return; return
} }
// ***************************************************************************** // *****************************************************************************
// *** Satisfy ISaver interface // *** Satisfy ISaver interface
// ***************************************************************************** // *****************************************************************************
func (this *Document) SaveFile(path string) (err os.Error) { func (this *Document) SaveFile(path string) (err os.Error) {
file, err := os.Open(path, os.O_WRONLY | os.O_CREAT, 0600); file, err := os.Open(path, os.O_WRONLY|os.O_CREAT, 0600)
if err != nil { if err != nil {
return return
} }
defer file.Close(); defer file.Close()
content, err := this.SaveString(); content, err := this.SaveString()
if err != nil { if err != nil {
return return
} }
file.Write(strings.Bytes(content)); file.Write([]byte(content))
return return
} }
@ -265,16 +269,15 @@ func (this *Document) SaveString() (s string, err os.Error) {
this.Version, this.Encoding, this.StandAlone) this.Version, this.Encoding, this.StandAlone)
} }
s += this.Root.String(); s += this.Root.String()
return; return
} }
func (this *Document) SaveStream(w *io.Writer) (err os.Error) { func (this *Document) SaveStream(w *io.Writer) (err os.Error) {
s, err := this.SaveString(); s, err := this.SaveString()
if err != nil { if err != nil {
return return
} }
w.Write(strings.Bytes(s)); w.Write([]byte(s))
return; return
} }

View File

@ -5,32 +5,40 @@ import "utf8"
import "regexp" import "regexp"
import "strconv" import "strconv"
var reg_entity = regexp.MustCompile("^&#[0-9]+;$"); var reg_entity = regexp.MustCompile("^&#[0-9]+;$")
// Converts a single numerical html entity to a regular Go utf-token. // Converts a single numerical html entity to a regular Go utf-token.
// ex: "♣" -> "♣" // ex: "♣" -> "♣"
func HtmlToUTF8(entity string) string { func HtmlToUTF8(entity string) string {
// Make sure we have a valid entity: { // Make sure we have a valid entity: {
ok := reg_entity.MatchString(entity); ok := reg_entity.MatchString(entity)
if !ok { return "" } if !ok {
return ""
}
// Convert entity to number // Convert entity to number
num, err := strconv.Atoi(entity[2:len(entity)-1]); num, err := strconv.Atoi(entity[2 : len(entity)-1])
if err != nil { return "" } if err != nil {
return ""
}
var arr [3]byte; var arr [3]byte
size := utf8.EncodeRune(num, &arr); size := utf8.EncodeRune(num, &arr)
if size == 0 { return "" } if size == 0 {
return ""
}
return string(&arr); return string(&arr)
} }
// Converts a single Go utf-token to it's an Html entity. // Converts a single Go utf-token to it's an Html entity.
// ex: "♣" -> "♣" // ex: "♣" -> "♣"
func UTF8ToHtml(token string) string { func UTF8ToHtml(token string) string {
rune, size := utf8.DecodeRuneInString(token); rune, size := utf8.DecodeRuneInString(token)
if size == 0 { return "" } if size == 0 {
return fmt.Sprintf("&#%d;", rune); return ""
}
return fmt.Sprintf("&#%d;", rune)
} }
/* /*
@ -46,261 +54,258 @@ func UTF8ToHtml(token string) string {
It will be used to map non-standard xml entities to a proper value. It will be used to map non-standard xml entities to a proper value.
If the parser encounters any unknown entities, it will throw a syntax If the parser encounters any unknown entities, it will throw a syntax
error and abort the parsing. Hence the ability to supply this map. error and abort the parsing. Hence the ability to supply this map.
*/ */
func loadNonStandardEntities(em *map[string]string) { func loadNonStandardEntities(em *map[string]string) {
(*em)["pi"] = "\u03c0"; (*em)["pi"] = "\u03c0"
(*em)["nabla"] = "\u2207"; (*em)["nabla"] = "\u2207"
(*em)["isin"] = "\u2208"; (*em)["isin"] = "\u2208"
(*em)["loz"] = "\u25ca"; (*em)["loz"] = "\u25ca"
(*em)["prop"] = "\u221d"; (*em)["prop"] = "\u221d"
(*em)["para"] = "\u00b6"; (*em)["para"] = "\u00b6"
(*em)["Aring"] = "\u00c5"; (*em)["Aring"] = "\u00c5"
(*em)["euro"] = "\u20ac"; (*em)["euro"] = "\u20ac"
(*em)["sup3"] = "\u00b3"; (*em)["sup3"] = "\u00b3"
(*em)["sup2"] = "\u00b2"; (*em)["sup2"] = "\u00b2"
(*em)["sup1"] = "\u00b9"; (*em)["sup1"] = "\u00b9"
(*em)["prod"] = "\u220f"; (*em)["prod"] = "\u220f"
(*em)["gamma"] = "\u03b3"; (*em)["gamma"] = "\u03b3"
(*em)["perp"] = "\u22a5"; (*em)["perp"] = "\u22a5"
(*em)["lfloor"] = "\u230a"; (*em)["lfloor"] = "\u230a"
(*em)["fnof"] = "\u0192"; (*em)["fnof"] = "\u0192"
(*em)["frasl"] = "\u2044"; (*em)["frasl"] = "\u2044"
(*em)["rlm"] = "\u200f"; (*em)["rlm"] = "\u200f"
(*em)["omega"] = "\u03c9"; (*em)["omega"] = "\u03c9"
(*em)["part"] = "\u2202"; (*em)["part"] = "\u2202"
(*em)["euml"] = "\u00eb"; (*em)["euml"] = "\u00eb"
(*em)["Kappa"] = "\u039a"; (*em)["Kappa"] = "\u039a"
(*em)["nbsp"] = "\u00a0"; (*em)["nbsp"] = "\u00a0"
(*em)["Eacute"] = "\u00c9"; (*em)["Eacute"] = "\u00c9"
(*em)["brvbar"] = "\u00a6"; (*em)["brvbar"] = "\u00a6"
(*em)["otimes"] = "\u2297"; (*em)["otimes"] = "\u2297"
(*em)["ndash"] = "\u2013"; (*em)["ndash"] = "\u2013"
(*em)["thinsp"] = "\u2009"; (*em)["thinsp"] = "\u2009"
(*em)["nu"] = "\u03bd"; (*em)["nu"] = "\u03bd"
(*em)["Upsilon"] = "\u03a5"; (*em)["Upsilon"] = "\u03a5"
(*em)["upsih"] = "\u03d2"; (*em)["upsih"] = "\u03d2"
(*em)["raquo"] = "\u00bb"; (*em)["raquo"] = "\u00bb"
(*em)["yacute"] = "\u00fd"; (*em)["yacute"] = "\u00fd"
(*em)["delta"] = "\u03b4"; (*em)["delta"] = "\u03b4"
(*em)["eth"] = "\u00f0"; (*em)["eth"] = "\u00f0"
(*em)["supe"] = "\u2287"; (*em)["supe"] = "\u2287"
(*em)["ne"] = "\u2260"; (*em)["ne"] = "\u2260"
(*em)["ni"] = "\u220b"; (*em)["ni"] = "\u220b"
(*em)["eta"] = "\u03b7"; (*em)["eta"] = "\u03b7"
(*em)["uArr"] = "\u21d1"; (*em)["uArr"] = "\u21d1"
(*em)["image"] = "\u2111"; (*em)["image"] = "\u2111"
(*em)["asymp"] = "\u2248"; (*em)["asymp"] = "\u2248"
(*em)["oacute"] = "\u00f3"; (*em)["oacute"] = "\u00f3"
(*em)["rarr"] = "\u2192"; (*em)["rarr"] = "\u2192"
(*em)["emsp"] = "\u2003"; (*em)["emsp"] = "\u2003"
(*em)["acirc"] = "\u00e2"; (*em)["acirc"] = "\u00e2"
(*em)["shy"] = "\u00ad"; (*em)["shy"] = "\u00ad"
(*em)["yuml"] = "\u00ff"; (*em)["yuml"] = "\u00ff"
(*em)["acute"] = "\u00b4"; (*em)["acute"] = "\u00b4"
(*em)["int"] = "\u222b"; (*em)["int"] = "\u222b"
(*em)["ccedil"] = "\u00e7"; (*em)["ccedil"] = "\u00e7"
(*em)["Acirc"] = "\u00c2"; (*em)["Acirc"] = "\u00c2"
(*em)["Ograve"] = "\u00d2"; (*em)["Ograve"] = "\u00d2"
(*em)["times"] = "\u00d7"; (*em)["times"] = "\u00d7"
(*em)["weierp"] = "\u2118"; (*em)["weierp"] = "\u2118"
(*em)["Tau"] = "\u03a4"; (*em)["Tau"] = "\u03a4"
(*em)["omicron"] = "\u03bf"; (*em)["omicron"] = "\u03bf"
(*em)["lt"] = "\u003c"; (*em)["lt"] = "\u003c"
(*em)["Mu"] = "\u039c"; (*em)["Mu"] = "\u039c"
(*em)["Ucirc"] = "\u00db"; (*em)["Ucirc"] = "\u00db"
(*em)["sub"] = "\u2282"; (*em)["sub"] = "\u2282"
(*em)["le"] = "\u2264"; (*em)["le"] = "\u2264"
(*em)["sum"] = "\u2211"; (*em)["sum"] = "\u2211"
(*em)["sup"] = "\u2283"; (*em)["sup"] = "\u2283"
(*em)["lrm"] = "\u200e"; (*em)["lrm"] = "\u200e"
(*em)["frac34"] = "\u00be"; (*em)["frac34"] = "\u00be"
(*em)["Iota"] = "\u0399"; (*em)["Iota"] = "\u0399"
(*em)["Ugrave"] = "\u00d9"; (*em)["Ugrave"] = "\u00d9"
(*em)["THORN"] = "\u00de"; (*em)["THORN"] = "\u00de"
(*em)["rsaquo"] = "\u203a"; (*em)["rsaquo"] = "\u203a"
(*em)["not"] = "\u00ac"; (*em)["not"] = "\u00ac"
(*em)["sigma"] = "\u03c3"; (*em)["sigma"] = "\u03c3"
(*em)["iuml"] = "\u00ef"; (*em)["iuml"] = "\u00ef"
(*em)["epsilon"] = "\u03b5"; (*em)["epsilon"] = "\u03b5"
(*em)["spades"] = "\u2660"; (*em)["spades"] = "\u2660"
(*em)["theta"] = "\u03b8"; (*em)["theta"] = "\u03b8"
(*em)["divide"] = "\u00f7"; (*em)["divide"] = "\u00f7"
(*em)["Atilde"] = "\u00c3"; (*em)["Atilde"] = "\u00c3"
(*em)["uacute"] = "\u00fa"; (*em)["uacute"] = "\u00fa"
(*em)["Rho"] = "\u03a1"; (*em)["Rho"] = "\u03a1"
(*em)["trade"] = "\u2122"; (*em)["trade"] = "\u2122"
(*em)["chi"] = "\u03c7"; (*em)["chi"] = "\u03c7"
(*em)["agrave"] = "\u00e0"; (*em)["agrave"] = "\u00e0"
(*em)["or"] = "\u2228"; (*em)["or"] = "\u2228"
(*em)["circ"] = "\u02c6"; (*em)["circ"] = "\u02c6"
(*em)["middot"] = "\u00b7"; (*em)["middot"] = "\u00b7"
(*em)["plusmn"] = "\u00b1"; (*em)["plusmn"] = "\u00b1"
(*em)["aring"] = "\u00e5"; (*em)["aring"] = "\u00e5"
(*em)["lsquo"] = "\u2018"; (*em)["lsquo"] = "\u2018"
(*em)["Yacute"] = "\u00dd"; (*em)["Yacute"] = "\u00dd"
(*em)["oline"] = "\u203e"; (*em)["oline"] = "\u203e"
(*em)["copy"] = "\u00a9"; (*em)["copy"] = "\u00a9"
(*em)["icirc"] = "\u00ee"; (*em)["icirc"] = "\u00ee"
(*em)["lowast"] = "\u2217"; (*em)["lowast"] = "\u2217"
(*em)["Oacute"] = "\u00d3"; (*em)["Oacute"] = "\u00d3"
(*em)["aacute"] = "\u00e1"; (*em)["aacute"] = "\u00e1"
(*em)["oplus"] = "\u2295"; (*em)["oplus"] = "\u2295"
(*em)["crarr"] = "\u21b5"; (*em)["crarr"] = "\u21b5"
(*em)["thetasym"] = "\u03d1"; (*em)["thetasym"] = "\u03d1"
(*em)["Beta"] = "\u0392"; (*em)["Beta"] = "\u0392"
(*em)["laquo"] = "\u00ab"; (*em)["laquo"] = "\u00ab"
(*em)["rang"] = "\u232a"; (*em)["rang"] = "\u232a"
(*em)["tilde"] = "\u02dc"; (*em)["tilde"] = "\u02dc"
(*em)["Uuml"] = "\u00dc"; (*em)["Uuml"] = "\u00dc"
(*em)["zwj"] = "\u200d"; (*em)["zwj"] = "\u200d"
(*em)["mu"] = "\u03bc"; (*em)["mu"] = "\u03bc"
(*em)["Ccedil"] = "\u00c7"; (*em)["Ccedil"] = "\u00c7"
(*em)["infin"] = "\u221e"; (*em)["infin"] = "\u221e"
(*em)["ouml"] = "\u00f6"; (*em)["ouml"] = "\u00f6"
(*em)["rfloor"] = "\u230b"; (*em)["rfloor"] = "\u230b"
(*em)["pound"] = "\u00a3"; (*em)["pound"] = "\u00a3"
(*em)["szlig"] = "\u00df"; (*em)["szlig"] = "\u00df"
(*em)["thorn"] = "\u00fe"; (*em)["thorn"] = "\u00fe"
(*em)["forall"] = "\u2200"; (*em)["forall"] = "\u2200"
(*em)["piv"] = "\u03d6"; (*em)["piv"] = "\u03d6"
(*em)["rdquo"] = "\u201d"; (*em)["rdquo"] = "\u201d"
(*em)["frac12"] = "\u00bd"; (*em)["frac12"] = "\u00bd"
(*em)["frac14"] = "\u00bc"; (*em)["frac14"] = "\u00bc"
(*em)["Ocirc"] = "\u00d4"; (*em)["Ocirc"] = "\u00d4"
(*em)["Ecirc"] = "\u00ca"; (*em)["Ecirc"] = "\u00ca"
(*em)["kappa"] = "\u03ba"; (*em)["kappa"] = "\u03ba"
(*em)["Euml"] = "\u00cb"; (*em)["Euml"] = "\u00cb"
(*em)["minus"] = "\u2212"; (*em)["minus"] = "\u2212"
(*em)["cong"] = "\u2245"; (*em)["cong"] = "\u2245"
(*em)["hellip"] = "\u2026"; (*em)["hellip"] = "\u2026"
(*em)["equiv"] = "\u2261"; (*em)["equiv"] = "\u2261"
(*em)["cent"] = "\u00a2"; (*em)["cent"] = "\u00a2"
(*em)["Uacute"] = "\u00da"; (*em)["Uacute"] = "\u00da"
(*em)["darr"] = "\u2193"; (*em)["darr"] = "\u2193"
(*em)["Eta"] = "\u0397"; (*em)["Eta"] = "\u0397"
(*em)["sbquo"] = "\u201a"; (*em)["sbquo"] = "\u201a"
(*em)["rArr"] = "\u21d2"; (*em)["rArr"] = "\u21d2"
(*em)["igrave"] = "\u00ec"; (*em)["igrave"] = "\u00ec"
(*em)["uml"] = "\u00a8"; (*em)["uml"] = "\u00a8"
(*em)["lambda"] = "\u03bb"; (*em)["lambda"] = "\u03bb"
(*em)["oelig"] = "\u0153"; (*em)["oelig"] = "\u0153"
(*em)["harr"] = "\u2194"; (*em)["harr"] = "\u2194"
(*em)["ang"] = "\u2220"; (*em)["ang"] = "\u2220"
(*em)["clubs"] = "\u2663"; (*em)["clubs"] = "\u2663"
(*em)["and"] = "\u2227"; (*em)["and"] = "\u2227"
(*em)["permil"] = "\u2030"; (*em)["permil"] = "\u2030"
(*em)["larr"] = "\u2190"; (*em)["larr"] = "\u2190"
(*em)["Yuml"] = "\u0178"; (*em)["Yuml"] = "\u0178"
(*em)["cup"] = "\u222a"; (*em)["cup"] = "\u222a"
(*em)["Xi"] = "\u039e"; (*em)["Xi"] = "\u039e"
(*em)["Alpha"] = "\u0391"; (*em)["Alpha"] = "\u0391"
(*em)["phi"] = "\u03c6"; (*em)["phi"] = "\u03c6"
(*em)["ucirc"] = "\u00fb"; (*em)["ucirc"] = "\u00fb"
(*em)["oslash"] = "\u00f8"; (*em)["oslash"] = "\u00f8"
(*em)["rsquo"] = "\u2019"; (*em)["rsquo"] = "\u2019"
(*em)["AElig"] = "\u00c6"; (*em)["AElig"] = "\u00c6"
(*em)["mdash"] = "\u2014"; (*em)["mdash"] = "\u2014"
(*em)["psi"] = "\u03c8"; (*em)["psi"] = "\u03c8"
(*em)["eacute"] = "\u00e9"; (*em)["eacute"] = "\u00e9"
(*em)["otilde"] = "\u00f5"; (*em)["otilde"] = "\u00f5"
(*em)["yen"] = "\u00a5"; (*em)["yen"] = "\u00a5"
(*em)["gt"] = "\u003e"; (*em)["gt"] = "\u003e"
(*em)["Iuml"] = "\u00cf"; (*em)["Iuml"] = "\u00cf"
(*em)["Prime"] = "\u2033"; (*em)["Prime"] = "\u2033"
(*em)["Chi"] = "\u03a7"; (*em)["Chi"] = "\u03a7"
(*em)["ge"] = "\u2265"; (*em)["ge"] = "\u2265"
(*em)["reg"] = "\u00ae"; (*em)["reg"] = "\u00ae"
(*em)["hearts"] = "\u2665"; (*em)["hearts"] = "\u2665"
(*em)["auml"] = "\u00e4"; (*em)["auml"] = "\u00e4"
(*em)["Agrave"] = "\u00c0"; (*em)["Agrave"] = "\u00c0"
(*em)["sect"] = "\u00a7"; (*em)["sect"] = "\u00a7"
(*em)["sube"] = "\u2286"; (*em)["sube"] = "\u2286"
(*em)["sigmaf"] = "\u03c2"; (*em)["sigmaf"] = "\u03c2"
(*em)["Gamma"] = "\u0393"; (*em)["Gamma"] = "\u0393"
(*em)["amp"] = "\u0026"; (*em)["amp"] = "\u0026"
(*em)["ensp"] = "\u2002"; (*em)["ensp"] = "\u2002"
(*em)["ETH"] = "\u00d0"; (*em)["ETH"] = "\u00d0"
(*em)["Igrave"] = "\u00cc"; (*em)["Igrave"] = "\u00cc"
(*em)["Omega"] = "\u03a9"; (*em)["Omega"] = "\u03a9"
(*em)["Lambda"] = "\u039b"; (*em)["Lambda"] = "\u039b"
(*em)["Omicron"] = "\u039f"; (*em)["Omicron"] = "\u039f"
(*em)["there4"] = "\u2234"; (*em)["there4"] = "\u2234"
(*em)["ntilde"] = "\u00f1"; (*em)["ntilde"] = "\u00f1"
(*em)["xi"] = "\u03be"; (*em)["xi"] = "\u03be"
(*em)["dagger"] = "\u2020"; (*em)["dagger"] = "\u2020"
(*em)["egrave"] = "\u00e8"; (*em)["egrave"] = "\u00e8"
(*em)["Delta"] = "\u0394"; (*em)["Delta"] = "\u0394"
(*em)["OElig"] = "\u0152"; (*em)["OElig"] = "\u0152"
(*em)["diams"] = "\u2666"; (*em)["diams"] = "\u2666"
(*em)["ldquo"] = "\u201c"; (*em)["ldquo"] = "\u201c"
(*em)["radic"] = "\u221a"; (*em)["radic"] = "\u221a"
(*em)["Oslash"] = "\u00d8"; (*em)["Oslash"] = "\u00d8"
(*em)["Ouml"] = "\u00d6"; (*em)["Ouml"] = "\u00d6"
(*em)["lceil"] = "\u2308"; (*em)["lceil"] = "\u2308"
(*em)["uarr"] = "\u2191"; (*em)["uarr"] = "\u2191"
(*em)["atilde"] = "\u00e3"; (*em)["atilde"] = "\u00e3"
(*em)["iquest"] = "\u00bf"; (*em)["iquest"] = "\u00bf"
(*em)["lsaquo"] = "\u2039"; (*em)["lsaquo"] = "\u2039"
(*em)["Epsilon"] = "\u0395"; (*em)["Epsilon"] = "\u0395"
(*em)["iacute"] = "\u00ed"; (*em)["iacute"] = "\u00ed"
(*em)["cap"] = "\u2229"; (*em)["cap"] = "\u2229"
(*em)["deg"] = "\u00b0"; (*em)["deg"] = "\u00b0"
(*em)["Otilde"] = "\u00d5"; (*em)["Otilde"] = "\u00d5"
(*em)["zeta"] = "\u03b6"; (*em)["zeta"] = "\u03b6"
(*em)["ocirc"] = "\u00f4"; (*em)["ocirc"] = "\u00f4"
(*em)["scaron"] = "\u0161"; (*em)["scaron"] = "\u0161"
(*em)["ecirc"] = "\u00ea"; (*em)["ecirc"] = "\u00ea"
(*em)["ordm"] = "\u00ba"; (*em)["ordm"] = "\u00ba"
(*em)["tau"] = "\u03c4"; (*em)["tau"] = "\u03c4"
(*em)["Auml"] = "\u00c4"; (*em)["Auml"] = "\u00c4"
(*em)["dArr"] = "\u21d3"; (*em)["dArr"] = "\u21d3"
(*em)["ordf"] = "\u00aa"; (*em)["ordf"] = "\u00aa"
(*em)["alefsym"] = "\u2135"; (*em)["alefsym"] = "\u2135"
(*em)["notin"] = "\u2209"; (*em)["notin"] = "\u2209"
(*em)["Pi"] = "\u03a0"; (*em)["Pi"] = "\u03a0"
(*em)["sdot"] = "\u22c5"; (*em)["sdot"] = "\u22c5"
(*em)["upsilon"] = "\u03c5"; (*em)["upsilon"] = "\u03c5"
(*em)["iota"] = "\u03b9"; (*em)["iota"] = "\u03b9"
(*em)["hArr"] = "\u21d4"; (*em)["hArr"] = "\u21d4"
(*em)["Sigma"] = "\u03a3"; (*em)["Sigma"] = "\u03a3"
(*em)["lang"] = "\u2329"; (*em)["lang"] = "\u2329"
(*em)["curren"] = "\u00a4"; (*em)["curren"] = "\u00a4"
(*em)["Theta"] = "\u0398"; (*em)["Theta"] = "\u0398"
(*em)["lArr"] = "\u21d0"; (*em)["lArr"] = "\u21d0"
(*em)["Phi"] = "\u03a6"; (*em)["Phi"] = "\u03a6"
(*em)["Nu"] = "\u039d"; (*em)["Nu"] = "\u039d"
(*em)["rho"] = "\u03c1"; (*em)["rho"] = "\u03c1"
(*em)["alpha"] = "\u03b1"; (*em)["alpha"] = "\u03b1"
(*em)["iexcl"] = "\u00a1"; (*em)["iexcl"] = "\u00a1"
(*em)["micro"] = "\u00b5"; (*em)["micro"] = "\u00b5"
(*em)["cedil"] = "\u00b8"; (*em)["cedil"] = "\u00b8"
(*em)["Ntilde"] = "\u00d1"; (*em)["Ntilde"] = "\u00d1"
(*em)["Psi"] = "\u03a8"; (*em)["Psi"] = "\u03a8"
(*em)["Dagger"] = "\u2021"; (*em)["Dagger"] = "\u2021"
(*em)["Egrave"] = "\u00c8"; (*em)["Egrave"] = "\u00c8"
(*em)["Icirc"] = "\u00ce"; (*em)["Icirc"] = "\u00ce"
(*em)["nsub"] = "\u2284"; (*em)["nsub"] = "\u2284"
(*em)["bdquo"] = "\u201e"; (*em)["bdquo"] = "\u201e"
(*em)["empty"] = "\u2205"; (*em)["empty"] = "\u2205"
(*em)["aelig"] = "\u00e6"; (*em)["aelig"] = "\u00e6"
(*em)["ograve"] = "\u00f2"; (*em)["ograve"] = "\u00f2"
(*em)["macr"] = "\u00af"; (*em)["macr"] = "\u00af"
(*em)["Zeta"] = "\u0396"; (*em)["Zeta"] = "\u0396"
(*em)["beta"] = "\u03b2"; (*em)["beta"] = "\u03b2"
(*em)["sim"] = "\u223c"; (*em)["sim"] = "\u223c"
(*em)["uuml"] = "\u00fc"; (*em)["uuml"] = "\u00fc"
(*em)["Aacute"] = "\u00c1"; (*em)["Aacute"] = "\u00c1"
(*em)["Iacute"] = "\u00cd"; (*em)["Iacute"] = "\u00cd"
(*em)["exist"] = "\u2203"; (*em)["exist"] = "\u2203"
(*em)["prime"] = "\u2032"; (*em)["prime"] = "\u2032"
(*em)["rceil"] = "\u2309"; (*em)["rceil"] = "\u2309"
(*em)["real"] = "\u211c"; (*em)["real"] = "\u211c"
(*em)["zwnj"] = "\u200c"; (*em)["zwnj"] = "\u200c"
(*em)["bull"] = "\u2022"; (*em)["bull"] = "\u2022"
(*em)["quot"] = "\u0022"; (*em)["quot"] = "\u0022"
(*em)["Scaron"] = "\u0160"; (*em)["Scaron"] = "\u0160"
(*em)["ugrave"] = "\u00f9"; (*em)["ugrave"] = "\u00f9"
} }

View File

@ -4,19 +4,19 @@ import "os"
import "io" import "io"
type ILoader interface { type ILoader interface {
LoadUrl(string) os.Error; LoadUrl(string) os.Error
LoadFile(string) os.Error; LoadFile(string) os.Error
LoadString(string) os.Error; LoadString(string) os.Error
LoadStream(*io.Reader) os.Error; LoadStream(*io.Reader) os.Error
} }
type ISaver interface { type ISaver interface {
SaveFile(string) os.Error; SaveFile(string) os.Error
SaveString(string) (string, os.Error); SaveString(string) (string, os.Error)
SaveStream(*io.Writer) os.Error; SaveStream(*io.Writer) os.Error
} }
type ILoaderSaver interface { type ILoaderSaver interface {
ILoader; ILoader
ISaver; ISaver
} }

View File

@ -7,175 +7,219 @@ import "fmt"
import "strconv" import "strconv"
const ( const (
NT_ROOT = 0x00; NT_ROOT = 0x00
NT_DIRECTIVE = 0x01; NT_DIRECTIVE = 0x01
NT_PROCINST = 0x02; NT_PROCINST = 0x02
NT_COMMENT = 0x03; NT_COMMENT = 0x03
NT_ELEMENT = 0x04; NT_ELEMENT = 0x04
) )
type Attr struct { type Attr struct {
Name xml.Name; Name xml.Name
Value string; Value string
} }
type Node struct { type Node struct {
Type byte; Type byte
Name xml.Name; Name xml.Name
Children []*Node; Children []*Node
Attributes []Attr; Attributes []Attr
Parent *Node; Parent *Node
Value string; Value string
Target string; // procinst field Target string // procinst field
} }
func NewNode(tid byte) *Node { return &Node{Type: tid} } func NewNode(tid byte) *Node { return &Node{Type: tid} }
// This wraps the standard xml.Unmarshal function and supplies this particular // This wraps the standard xml.Unmarshal function and supplies this particular
// node as the content to be unmarshalled. // node as the content to be unmarshalled.
func (this *Node) Unmarshal(obj interface{}) os.Error { func (this *Node) Unmarshal(obj interface{}) os.Error {
return xml.Unmarshal(strings.NewReader(this.String()), obj); return xml.Unmarshal(strings.NewReader(this.String()), obj)
} }
// Get node value as string // Get node value as string
func (this *Node) GetValue(namespace, name string) string { func (this *Node) GetValue(namespace, name string) string {
node := rec_SelectNode(this, namespace, name); node := rec_SelectNode(this, namespace, name)
if node == nil { return "" } if node == nil {
return node.Value; return ""
}
return node.Value
} }
// Get node value as int // Get node value as int
func (this *Node) GetValuei(namespace, name string) int { func (this *Node) GetValuei(namespace, name string) int {
node := rec_SelectNode(this, namespace, name); node := rec_SelectNode(this, namespace, name)
if node == nil { return 0 } if node == nil {
if node.Value == "" { return 0 } return 0
n, _ := strconv.Atoi(node.Value); }
return n; if node.Value == "" {
return 0
}
n, _ := strconv.Atoi(node.Value)
return n
} }
// Get node value as int64 // Get node value as int64
func (this *Node) GetValuei64(namespace, name string) int64 { func (this *Node) GetValuei64(namespace, name string) int64 {
node := rec_SelectNode(this, namespace, name); node := rec_SelectNode(this, namespace, name)
if node == nil { return 0 } if node == nil {
if node.Value == "" { return 0 } return 0
n, _ := strconv.Atoi64(node.Value); }
return n; if node.Value == "" {
return 0
}
n, _ := strconv.Atoi64(node.Value)
return n
} }
// Get node value as uint // Get node value as uint
func (this *Node) GetValueui(namespace, name string) uint { func (this *Node) GetValueui(namespace, name string) uint {
node := rec_SelectNode(this, namespace, name); node := rec_SelectNode(this, namespace, name)
if node == nil { return 0 } if node == nil {
if node.Value == "" { return 0 } return 0
n, _ := strconv.Atoui(node.Value); }
return n; if node.Value == "" {
return 0
}
n, _ := strconv.Atoui(node.Value)
return n
} }
// Get node value as uint64 // Get node value as uint64
func (this *Node) GetValueui64(namespace, name string) uint64 { func (this *Node) GetValueui64(namespace, name string) uint64 {
node := rec_SelectNode(this, namespace, name); node := rec_SelectNode(this, namespace, name)
if node == nil { return 0 } if node == nil {
if node.Value == "" { return 0 } return 0
n, _ := strconv.Atoui64(node.Value); }
return n; if node.Value == "" {
return 0
}
n, _ := strconv.Atoui64(node.Value)
return n
} }
// Get node value as float // Get node value as float
func (this *Node) GetValuef(namespace, name string) float { func (this *Node) GetValuef(namespace, name string) float {
node := rec_SelectNode(this, namespace, name); node := rec_SelectNode(this, namespace, name)
if node == nil { return 0 } if node == nil {
if node.Value == "" { return 0 } return 0
n, _ := strconv.Atof(node.Value); }
return n; if node.Value == "" {
return 0
}
n, _ := strconv.Atof(node.Value)
return n
} }
// Get node value as float32 // Get node value as float32
func (this *Node) GetValuef32(namespace, name string) float32 { func (this *Node) GetValuef32(namespace, name string) float32 {
node := rec_SelectNode(this, namespace, name); node := rec_SelectNode(this, namespace, name)
if node == nil { return 0 } if node == nil {
if node.Value == "" { return 0 } return 0
n, _ := strconv.Atof32(node.Value); }
return n; if node.Value == "" {
return 0
}
n, _ := strconv.Atof32(node.Value)
return n
} }
// Get node value as float64 // Get node value as float64
func (this *Node) GetValuef64(namespace, name string) float64 { func (this *Node) GetValuef64(namespace, name string) float64 {
node := rec_SelectNode(this, namespace, name); node := rec_SelectNode(this, namespace, name)
if node == nil { return 0 } if node == nil {
if node.Value == "" { return 0 } return 0
n, _ := strconv.Atof64(node.Value); }
return n; if node.Value == "" {
return 0
}
n, _ := strconv.Atof64(node.Value)
return n
} }
// Get attribute value as string // Get attribute value as string
func (this *Node) GetAttr(namespace, name string) string { func (this *Node) GetAttr(namespace, name string) string {
for _,v := range this.Attributes { for _, v := range this.Attributes {
if namespace == v.Name.Space && name == v.Name.Local { if namespace == v.Name.Space && name == v.Name.Local {
return v.Value; return v.Value
} }
} }
return ""; return ""
} }
// Get attribute value as int // Get attribute value as int
func (this *Node) GetAttri(namespace, name string) int { func (this *Node) GetAttri(namespace, name string) int {
s := this.GetAttr(namespace, name); s := this.GetAttr(namespace, name)
if s == "" { return 0 } if s == "" {
n, _ := strconv.Atoi(s); return 0
return n; }
n, _ := strconv.Atoi(s)
return n
} }
// Get attribute value as uint // Get attribute value as uint
func (this *Node) GetAttrui(namespace, name string) uint { func (this *Node) GetAttrui(namespace, name string) uint {
s := this.GetAttr(namespace, name); s := this.GetAttr(namespace, name)
if s == "" { return 0 } if s == "" {
n, _ := strconv.Atoui(s); return 0
return n; }
n, _ := strconv.Atoui(s)
return n
} }
// Get attribute value as uint64 // Get attribute value as uint64
func (this *Node) GetAttrui64(namespace, name string) uint64 { func (this *Node) GetAttrui64(namespace, name string) uint64 {
s := this.GetAttr(namespace, name); s := this.GetAttr(namespace, name)
if s == "" { return 0 } if s == "" {
n, _ := strconv.Atoui64(s); return 0
return n; }
n, _ := strconv.Atoui64(s)
return n
} }
// Get attribute value as int64 // Get attribute value as int64
func (this *Node) GetAttri64(namespace, name string) int64 { func (this *Node) GetAttri64(namespace, name string) int64 {
s := this.GetAttr(namespace, name); s := this.GetAttr(namespace, name)
if s == "" { return 0 } if s == "" {
n, _ := strconv.Atoi64(s); return 0
return n; }
n, _ := strconv.Atoi64(s)
return n
} }
// Get attribute value as float // Get attribute value as float
func (this *Node) GetAttrf(namespace, name string) float { func (this *Node) GetAttrf(namespace, name string) float {
s := this.GetAttr(namespace, name); s := this.GetAttr(namespace, name)
if s == "" { return 0 } if s == "" {
n, _ := strconv.Atof(s); return 0
return n; }
n, _ := strconv.Atof(s)
return n
} }
// Get attribute value as float32 // Get attribute value as float32
func (this *Node) GetAttrf32(namespace, name string) float32 { func (this *Node) GetAttrf32(namespace, name string) float32 {
s := this.GetAttr(namespace, name); s := this.GetAttr(namespace, name)
if s == "" { return 0 } if s == "" {
n, _ := strconv.Atof32(s); return 0
return n; }
n, _ := strconv.Atof32(s)
return n
} }
// Get attribute value as float64 // Get attribute value as float64
func (this *Node) GetAttrf64(namespace, name string) float64 { func (this *Node) GetAttrf64(namespace, name string) float64 {
s := this.GetAttr(namespace, name); s := this.GetAttr(namespace, name)
if s == "" { return 0 } if s == "" {
n, _ := strconv.Atof64(s); return 0
return n; }
n, _ := strconv.Atof64(s)
return n
} }
// Returns true if this node has the specified attribute. False otherwise. // Returns true if this node has the specified attribute. False otherwise.
func (this *Node) HasAttr(namespace, name string) bool { func (this *Node) HasAttr(namespace, name string) bool {
for _,v := range this.Attributes { for _, v := range this.Attributes {
if namespace == v.Name.Space && name == v.Name.Local { if namespace == v.Name.Space && name == v.Name.Local {
return true return true
} }
@ -185,46 +229,46 @@ func (this *Node) HasAttr(namespace, name string) bool {
// Select single node by name // Select single node by name
func (this *Node) SelectNode(namespace, name string) *Node { func (this *Node) SelectNode(namespace, name string) *Node {
return rec_SelectNode(this, namespace, name); return rec_SelectNode(this, namespace, name)
} }
func rec_SelectNode(cn *Node, namespace, name string) *Node { func rec_SelectNode(cn *Node, namespace, name string) *Node {
if cn.Name.Space == namespace && cn.Name.Local == name { if cn.Name.Space == namespace && cn.Name.Local == name {
return cn; return cn
} }
for _, v := range cn.Children { for _, v := range cn.Children {
tn := rec_SelectNode(v, namespace, name); tn := rec_SelectNode(v, namespace, name)
if tn != nil { return tn } if tn != nil {
return tn
}
} }
return nil; return nil
} }
// Select multiple nodes by name // Select multiple nodes by name
func (this *Node) SelectNodes(namespace, name string) []*Node { func (this *Node) SelectNodes(namespace, name string) []*Node {
list := make([]*Node, 0); list := make([]*Node, 0)
rec_SelectNodes(this, namespace, name, &list); rec_SelectNodes(this, namespace, name, &list)
return list; return list
} }
func rec_SelectNodes(cn *Node, namespace, name string, list *[]*Node) { func rec_SelectNodes(cn *Node, namespace, name string, list *[]*Node) {
if cn.Name.Space == namespace && cn.Name.Local == name { if cn.Name.Space == namespace && cn.Name.Local == name {
slice := make([]*Node, len(*list) + 1); c := make([]*Node, len(*list)+1)
for i,v := range *list { copy(c, *list)
slice[i] = v; c[len(c)-1] = cn
} *list = c
slice[len(slice) - 1] = cn;
*list = slice;
return return
} }
for _, v := range cn.Children { for _, v := range cn.Children {
rec_SelectNodes(v, namespace, name, list); rec_SelectNodes(v, namespace, name, list)
} }
} }
// Convert node to appropriate string representation based on it's @Type. // 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 // 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 // Document. This one has no representation by itself. It merely forwards the
// String() call to it's child nodes. // String() call to it's child nodes.
func (this *Node) String() (s string) { func (this *Node) String() (s string) {
@ -240,29 +284,29 @@ func (this *Node) String() (s string) {
case NT_ROOT: case NT_ROOT:
s = this.printRoot() s = this.printRoot()
} }
return; return
} }
func (this *Node) printRoot() (s string) { func (this *Node) printRoot() (s string) {
for _, v := range this.Children { for _, v := range this.Children {
s += v.String() s += v.String()
} }
return; return
} }
func (this *Node) printProcInst() (s string) { func (this *Node) printProcInst() (s string) {
s = "<?" + this.Target + " " + this.Value + "?>"; s = "<?" + this.Target + " " + this.Value + "?>"
return; return
} }
func (this *Node) printComment() (s string) { func (this *Node) printComment() (s string) {
s = "<!-- " + this.Value + " -->"; s = "<!-- " + this.Value + " -->"
return; return
} }
func (this *Node) printDirective() (s string) { func (this *Node) printDirective() (s string) {
s = "<!" + this.Value + "!>"; s = "<!" + this.Value + "!>"
return; return
} }
func (this *Node) printElement() (s string) { func (this *Node) printElement() (s string) {
@ -281,23 +325,23 @@ func (this *Node) printElement() (s string) {
} }
if len(this.Children) == 0 && len(this.Value) == 0 { if len(this.Children) == 0 && len(this.Value) == 0 {
s += " />"; s += " />"
return; return
} }
s += ">"; s += ">"
for _, v := range this.Children { for _, v := range this.Children {
s += v.String() s += v.String()
} }
s += this.Value; s += this.Value
if len(this.Name.Space) > 0 { if len(this.Name.Space) > 0 {
s += "</" + this.Name.Space + ":" + this.Name.Local + ">" s += "</" + this.Name.Space + ":" + this.Name.Local + ">"
} else { } else {
s += "</" + this.Name.Local + ">" s += "</" + this.Name.Local + ">"
} }
return; return
} }
// Add a child node // Add a child node
@ -305,38 +349,32 @@ func (this *Node) AddChild(t *Node) {
if t.Parent != nil { if t.Parent != nil {
t.Parent.RemoveChild(t) t.Parent.RemoveChild(t)
} }
t.Parent = this; t.Parent = this
slice := make([]*Node, len(this.Children)+1); c := make([]*Node, len(this.Children)+1)
for i, v := range this.Children { copy(c, this.Children)
slice[i] = v c[len(c)-1] = t
} this.Children = c
slice[len(slice)-1] = t;
this.Children = slice;
} }
// Remove a child node // Remove a child node
func (this *Node) RemoveChild(t *Node) { func (this *Node) RemoveChild(t *Node) {
pos := -1; p := -1
for i, v := range this.Children { for i, v := range this.Children {
if v == t { if v == t {
pos = i; p = i
break; break
} }
} }
if pos == -1 { if p == -1 {
return return
} }
slice := make([]*Node, len(this.Children)-1);
idx := 0; c := make([]*Node, len(this.Children)-1)
for i, v := range this.Children { copy(c, this.Children[0:p])
if i != pos { copy(c[p:], this.Children[p+1:])
slice[idx] = v; this.Children = c
idx++;
}
}
t.Parent = nil; t.Parent = nil
} }

View File

@ -3,108 +3,106 @@ package xmlx
import "testing" import "testing"
func TestLoadLocal(t *testing.T) { func TestLoadLocal(t *testing.T) {
doc := New(); doc := New()
err := doc.LoadFile("test.xml"); err := doc.LoadFile("test.xml")
if err != nil { if err != nil {
t.Errorf("%s", err); t.Errorf("%s", err)
return; return
} }
if len(doc.Root.Children) == 0 { if len(doc.Root.Children) == 0 {
t.Errorf("Root node has no children."); t.Errorf("Root node has no children.")
return; return
} }
} }
func TestLoadRemote(t *testing.T) { func TestLoadRemote(t *testing.T) {
doc := New(); doc := New()
err := doc.LoadUri("http://tldp.org/authors/template/Sample-HOWTO.xml"); err := doc.LoadUri("http://tldp.org/authors/template/Sample-HOWTO.xml")
if err != nil { if err != nil {
t.Errorf("%s", err); t.Errorf("%s", err)
return; return
} }
if len(doc.Root.Children) == 0 { if len(doc.Root.Children) == 0 {
t.Errorf("Root node has no children."); t.Errorf("Root node has no children.")
return; return
} }
} }
func TestSave(t *testing.T) { func TestSave(t *testing.T) {
doc := New(); doc := New()
err := doc.LoadFile("test.xml"); err := doc.LoadFile("test.xml")
if err != nil { if err != nil {
t.Errorf("LoadFile(): %s", err); t.Errorf("LoadFile(): %s", err)
return; return
} }
err = doc.SaveFile("test1.xml"); err = doc.SaveFile("test1.xml")
if err != nil { if err != nil {
t.Errorf("SaveFile(): %s", err); t.Errorf("SaveFile(): %s", err)
return; return
} }
} }
func TestNodeSearch(t *testing.T) { func TestNodeSearch(t *testing.T) {
doc := New(); doc := New()
err := doc.LoadFile("test.xml"); err := doc.LoadFile("test.xml")
if err != nil { if err != nil {
t.Errorf("LoadFile(): %s", err); t.Errorf("LoadFile(): %s", err)
return; return
} }
node := doc.SelectNode("", "item"); node := doc.SelectNode("", "item")
if node == nil { if node == nil {
t.Errorf("SelectNode(): No node found."); t.Errorf("SelectNode(): No node found.")
return; return
} }
nodes := doc.SelectNodes("", "item"); nodes := doc.SelectNodes("", "item")
if len(nodes) == 0 { if len(nodes) == 0 {
t.Errorf("SelectNodes(): no nodes found."); t.Errorf("SelectNodes(): no nodes found.")
return; return
} }
} }
type Image struct { type Image struct {
Title string; Title string
Url string; Url string
Link string; Link string
Width string; Width string
Height string; Height string
Description string; Description string
} }
func TestUnmarshal(t *testing.T) { func TestUnmarshal(t *testing.T) {
doc := New(); doc := New()
err := doc.LoadFile("test.xml"); err := doc.LoadFile("test.xml")
if err != nil { if err != nil {
t.Errorf("LoadFile(): %s", err); t.Errorf("LoadFile(): %s", err)
return; return
} }
node := doc.SelectNode("", "image"); node := doc.SelectNode("", "image")
if node == nil { if node == nil {
t.Errorf("SelectNode(): No node found."); t.Errorf("SelectNode(): No node found.")
return; return
} }
img := Image{}; img := Image{}
err = node.Unmarshal(&img); err = node.Unmarshal(&img)
if err != nil { if err != nil {
t.Errorf("Unmarshal(): %s", err); t.Errorf("Unmarshal(): %s", err)
return; return
} }
if img.Title != "WriteTheWeb" { if img.Title != "WriteTheWeb" {
t.Errorf("Image.Title has incorrect value. Got '%s', expected 'WriteTheWeb'.", img.Title); t.Errorf("Image.Title has incorrect value. Got '%s', expected 'WriteTheWeb'.", img.Title)
return; return
} }
} }