Skip to content

Instantly share code, notes, and snippets.

@advincze
Last active January 13, 2016 07:28
Show Gist options
  • Save advincze/d1974d07350aa04e4325 to your computer and use it in GitHub Desktop.
Save advincze/d1974d07350aa04e4325 to your computer and use it in GitHub Desktop.
unmarshal full subtree as element
package main
import (
"bytes"
"encoding/xml"
"io"
"log"
"testing"
)
const s = `
<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"
xml:lang="en"
xml:base="http://www.example.org">
<id>http://www.example.org/myfeed</id>
<title>My Simple Feed</title>
<updated>2005-07-15T12:00:00Z</updated>
<link href="/blog" />
<link rel="self" href="/myfeed" />
<entry>
<id>http://www.example.org/entries/1</id>
<title>A simple blog entry</title>
<link href="/blog/2005/07/1" />
<updated>2005-07-15T12:00:00Z</updated>
<summary>This is a simple blog entry</summary>
</entry>
<entry>
<id>http://www.example.org/entries/2</id>
<title />
<link href="/blog/2005/07/2" />
<updated>2005-07-15T12:00:00Z</updated>
<summary>This is simple blog entry without a title</summary>
</entry>
<entry>
<id>tag:update:20050718</id>
<title>Update: 20050718</title>
<updated>2005-07-18T12:00:00Z</updated>
<link rel="alternate"
type="text/html"
href="/updates/2005/07/18/readme.html_20050718" />
<content type="application/zip"
src="/updates/2005/07/18/update_20050718.zip" />
</entry>
<entry>
<id>tag:update:20050717</id>
<title>Update: 20050717</title>
<updated>2005-17-17T12:00:00Z</updated>
<link rel="alternate"
type="text/html"
href="/updates/2005/07/17/readme_20050717.html" />
<content type="application/zip"
src="/updates/2005/07/17/update_20050717.zip" />
</entry>
</feed>
`
func TestUnmarshal(t *testing.T) {
var feed Feed
r := bytes.NewBufferString(s)
dec := xml.NewDecoder(r)
err := dec.Decode(&feed)
if err != nil {
panic(err)
}
for _, e := range feed.Entries {
log.Println(string(e.Content))
}
}
func BenchmarkUnmarshal(b *testing.B) {
b.StopTimer()
var (
feed Feed
err error
r io.Reader
)
b.StartTimer()
for i := 0; i < b.N; i++ {
r = bytes.NewBufferString(s)
err = xml.NewDecoder(r).Decode(&feed)
if err != nil {
b.Error(err)
}
}
}
type Feed struct {
ID string `xml:"id"`
Entries []Entry `xml:"entry"`
}
type Entry struct {
Content []byte
}
func (e *Entry) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
var buf bytes.Buffer
enc := xml.NewEncoder(&buf)
err := enc.EncodeToken(start)
if err != nil {
return err
}
for {
tok, err := d.Token()
if err != nil {
return err
}
err = enc.EncodeToken(tok)
if err != nil {
return err
}
switch x := tok.(type) {
case xml.EndElement:
if x.Name == start.Name {
err = enc.Flush()
if err != nil {
return err
}
e.Content = buf.Bytes()
return nil
}
}
}
}
@advincze
Copy link
Author

the namespace output is not so nice as long as golang/go#13400 is not fixed. there is a workaround though

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment