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
					
				
					 2 changed files with 48 additions and 108 deletions
				
			
		
							
								
								
									
										138
									
								
								src/document.go
									
										
									
									
									
								
							
							
						
						
									
										138
									
								
								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…
	
	Add table
		Add a link
		
	
		Reference in a new issue