Updated code to use more recent go idioms. Yielding more compact xml processing. Hopefully better performant.
This commit is contained in:
parent
6a776b0cda
commit
79794996d0
136
src/document.go
136
src/document.go
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue