Updated code to use more recent go idioms. Yielding more compact xml processing. Hopefully better performant.

This commit is contained in:
jim teeuwen 2010-05-26 02:24:44 +02:00
parent 6a776b0cda
commit 79794996d0
2 changed files with 48 additions and 108 deletions

View File

@ -29,6 +29,8 @@ package xmlx
import "os" import "os"
import "io" import "io"
import "io/ioutil"
import "path"
import "strings" import "strings"
import "xml" import "xml"
import "fmt" import "fmt"
@ -85,125 +87,75 @@ func (this *Document) LoadString(s string) (err os.Error) {
this.Root = NewNode(NT_ROOT) this.Root = NewNode(NT_ROOT)
ct := this.Root ct := this.Root
var tok xml.Token
for { for {
tok, err := xp.Token() if tok, err = xp.Token(); err != nil {
if err != nil { if err == os.EOF {
if err != os.EOF && this.Verbose { return nil
}
if this.Verbose {
fmt.Fprintf(os.Stderr, "Xml Error: %s\n", err) fmt.Fprintf(os.Stderr, "Xml Error: %s\n", err)
} }
return return err
} }
t1, ok := tok.(xml.SyntaxError) switch tt := tok.(type) {
if ok { case xml.SyntaxError:
err = os.NewError(t1.String()) return os.NewError(tt.String())
return case xml.CharData:
} ct.Value = strings.TrimSpace(string(tt))
case xml.Comment:
t2, ok := tok.(xml.CharData)
if ok && ct != nil {
ct.Value = strings.TrimSpace(string(t2))
continue
}
t3, ok := tok.(xml.Comment)
if ok && ct != nil {
t := NewNode(NT_COMMENT) t := NewNode(NT_COMMENT)
t.Value = strings.TrimSpace(string(t3)) t.Value = strings.TrimSpace(string(tt))
ct.AddChild(t) ct.AddChild(t)
continue case xml.Directive:
}
t4, ok := tok.(xml.Directive)
if ok && ct != nil {
t := NewNode(NT_DIRECTIVE) t := NewNode(NT_DIRECTIVE)
t.Value = strings.TrimSpace(string(t4)) t.Value = strings.TrimSpace(string(tt))
ct.AddChild(t) ct.AddChild(t)
continue case xml.StartElement:
}
t5, ok := tok.(xml.StartElement)
if ok && ct != nil {
t := NewNode(NT_ELEMENT) t := NewNode(NT_ELEMENT)
t.Name = t5.Name t.Name = tt.Name
t.Attributes = make([]Attr, len(t5.Attr)) t.Attributes = make([]Attr, len(tt.Attr))
for i, v := range t5.Attr { for i, v := range tt.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 case xml.ProcInst:
} if tt.Target == "xml" { // xml doctype
doctype := strings.TrimSpace(string(tt.Inst))
t6, ok := tok.(xml.ProcInst)
if ok {
if t6.Target == "xml" { // xml doctype
doctype := strings.TrimSpace(string(t6.Inst))
/* // Not needed. There is only xml version 1.0
pos := strings.Index(doctype, `version="`);
if pos > -1 {
this.Version = doctype[pos+len(`version="`) : len(doctype)];
pos = strings.Index(this.Version, `"`);
this.Version = this.Version[0:pos];
}
*/
/* // Not needed. Any string we handle in Go is UTF8
// encoded. This means we will save UTF8 data as well.
pos = strings.Index(doctype, `encoding="`);
if pos > -1 {
this.Encoding = doctype[pos+len(`encoding="`) : len(doctype)];
pos = strings.Index(this.Encoding, `"`);
this.Encoding = this.Encoding[0:pos];
}
*/
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 {
t := NewNode(NT_PROCINST) t := NewNode(NT_PROCINST)
t.Target = strings.TrimSpace(t6.Target) t.Target = strings.TrimSpace(tt.Target)
t.Value = strings.TrimSpace(string(t6.Inst)) t.Value = strings.TrimSpace(string(tt.Inst))
ct.AddChild(t) ct.AddChild(t)
} }
continue case xml.EndElement:
} if ct = ct.Parent; ct == nil {
return
_, ok = tok.(xml.EndElement) }
if ok {
ct = ct.Parent
continue
} }
} }
return return
} }
func (this *Document) LoadFile(path string) (err os.Error) { func (this *Document) LoadFile(filename string) (err os.Error) {
file, err := os.Open(path, os.O_RDONLY, 0600) var data []byte
if err != nil {
if data, err = ioutil.ReadFile(path.Clean(filename)); err != nil {
return return
} }
defer file.Close()
content := "" return this.LoadString(string(data))
buff := make([]byte, 256)
for {
_, err := file.Read(buff)
if err != nil {
break
}
content += string(buff)
}
err = this.LoadString(content)
return
} }
func (this *Document) LoadUri(uri string) (err os.Error) { func (this *Document) LoadUri(uri string) (err os.Error) {
@ -214,18 +166,12 @@ func (this *Document) LoadUri(uri string) (err os.Error) {
defer r.Body.Close() defer r.Body.Close()
data := "" var b []byte
b := make([]byte, 256) if b, err = ioutil.ReadAll(r.Body); err != nil {
return
for {
n, err := io.ReadFull(r.Body, b)
if n == 0 || err == os.EOF {
break
}
data += string(b)
} }
err = this.LoadString(data) err = this.LoadString(string(b))
return return
} }

View File

@ -4,9 +4,8 @@ import "testing"
func TestLoadLocal(t *testing.T) { func TestLoadLocal(t *testing.T) {
doc := New() doc := New()
err := doc.LoadFile("test.xml")
if err != nil { if err := doc.LoadFile("test.xml"); err != nil {
t.Errorf("%s", err) t.Errorf("%s", err)
return return
} }
@ -19,9 +18,8 @@ func TestLoadLocal(t *testing.T) {
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")
if err != nil { if err := doc.LoadUri("http://www.w3schools.com/xml/plant_catalog.xml"); err != nil {
t.Errorf("%s", err) t.Errorf("%s", err)
return return
} }
@ -34,15 +32,13 @@ func TestLoadRemote(t *testing.T) {
func TestSave(t *testing.T) { func TestSave(t *testing.T) {
doc := New() doc := New()
err := doc.LoadFile("test.xml")
if err != nil { if err := doc.LoadFile("test.xml"); err != nil {
t.Errorf("LoadFile(): %s", err) t.Errorf("LoadFile(): %s", err)
return return
} }
err = doc.SaveFile("test1.xml") if err := doc.SaveFile("test1.xml"); err != nil {
if err != nil {
t.Errorf("SaveFile(): %s", err) t.Errorf("SaveFile(): %s", err)
return return
} }
@ -50,15 +46,13 @@ func TestSave(t *testing.T) {
func TestNodeSearch(t *testing.T) { func TestNodeSearch(t *testing.T) {
doc := New() doc := New()
err := doc.LoadFile("test.xml")
if err != nil { if err := doc.LoadFile("test.xml"); err != nil {
t.Errorf("LoadFile(): %s", err) t.Errorf("LoadFile(): %s", err)
return return
} }
node := doc.SelectNode("", "item") if node := doc.SelectNode("", "item"); node == nil {
if node == nil {
t.Errorf("SelectNode(): No node found.") t.Errorf("SelectNode(): No node found.")
return return
} }