For a learning exercise, I'm rewriting my Nowplaying Clojure web application into Go. In the case of Clojure, the clojure.xml package handled this non-UTF8 XML file:
<?xml version="1.0" encoding="ISO-8859-1"?>
<nexgen_audio_export>
<audio ID="id_1667331726_30393658">
<type>Song</type>
<status>Playing</status>
<played_time>09:41:18</played_time>
<composer>Frederic Delius</composer>
<title>Violin Sonata No.1</title>
<artist>Tasmin Little, violin; Piers Lane, piano</artist>
</audio>
</nexgen_audio_export> |
<?xml version="1.0" encoding="ISO-8859-1"?>
<nexgen_audio_export>
<audio ID="id_1667331726_30393658">
<type>Song</type>
<status>Playing</status>
<played_time>09:41:18</played_time>
<composer>Frederic Delius</composer>
<title>Violin Sonata No.1</title>
<artist>Tasmin Little, violin; Piers Lane, piano</artist>
</audio>
</nexgen_audio_export>
without complaint, but in the case of Go, I got this error:
xml: encoding "ISO-8859-1" declared but Decoder.CharsetReader is nil
when I tried my first version:
type Piece struct {
Title string
Composer string
}
type SecondInversionFeed struct {
XMLName xml.Name `xml:nexgen_audio_export`
Audio SecondInversionAudio `xml:"audio"`
}
type SecondInversionAudio struct {
Title string `xml:"title"`
Composer string `xml:"composer"`
}
func translateSecondInversion(data []byte) Piece {
var feed SecondInversionFeed
err := xml.Unmarshal(data, &feed)
if err != nil {
log.Fatal("Unmarshal error:", err)
}
return Piece{feed.Audio.Title, feed.Audio.Composer}
} |
type Piece struct {
Title string
Composer string
}
type SecondInversionFeed struct {
XMLName xml.Name `xml:nexgen_audio_export`
Audio SecondInversionAudio `xml:"audio"`
}
type SecondInversionAudio struct {
Title string `xml:"title"`
Composer string `xml:"composer"`
}
func translateSecondInversion(data []byte) Piece {
var feed SecondInversionFeed
err := xml.Unmarshal(data, &feed)
if err != nil {
log.Fatal("Unmarshal error:", err)
}
return Piece{feed.Audio.Title, feed.Audio.Composer}
}
I read this Stack Overflow thread a few times, but I still wasn't sure how to use go-charset or some other library to accomplish my task.
I first tried using go-charset to translate the file and pass it to Unmarshal, but that declaration at the top:
<?xml version="1.0" encoding="ISO-8859-1"?> |
<?xml version="1.0" encoding="ISO-8859-1"?>
still caused the same error. I then realized that the Unmarshal function simply creates a new Decoder, so I just had to pass a reference to the charset.NewReader function, and the xml package would use that to translate my XML data.
Here is a small program that demonstrates my approach:
package main
import (
"bytes"
"code.google.com/p/go-charset/charset"
_ "code.google.com/p/go-charset/data"
"encoding/xml"
"fmt"
)
type Feed struct {
XMLName xml.Name `xml:nexgen_audio_export`
Audio FeedAudio `xml:"audio"`
}
type FeedAudio struct {
Title string `xml:"title"`
Composer string `xml:"composer"`
}
func main() {
xml_data := []byte(`
<?xml version="1.0" encoding="ISO-8859-1"?>
<nexgen_audio_export>
<audio ID="id_1667331726_30393658">
<type>Song</type>
<status>Playing</status>
<played_time>09:41:18</played_time>
<composer>Frederic Delius</composer>
<title>Violin Sonata No.1</title>
<artist>Tasmin Little, violin; Piers Lane, piano</artist>
</audio>
</nexgen_audio_export>
`)
var feed Feed
reader := bytes.NewReader(xml_data)
decoder := xml.NewDecoder(reader)
decoder.CharsetReader = charset.NewReader
err := decoder.Decode(&feed)
if err != nil {
fmt.Println("decoder error:", err)
}
fmt.Println(feed.Audio.Title)
} |
package main
import (
"bytes"
"code.google.com/p/go-charset/charset"
_ "code.google.com/p/go-charset/data"
"encoding/xml"
"fmt"
)
type Feed struct {
XMLName xml.Name `xml:nexgen_audio_export`
Audio FeedAudio `xml:"audio"`
}
type FeedAudio struct {
Title string `xml:"title"`
Composer string `xml:"composer"`
}
func main() {
xml_data := []byte(`
<?xml version="1.0" encoding="ISO-8859-1"?>
<nexgen_audio_export>
<audio ID="id_1667331726_30393658">
<type>Song</type>
<status>Playing</status>
<played_time>09:41:18</played_time>
<composer>Frederic Delius</composer>
<title>Violin Sonata No.1</title>
<artist>Tasmin Little, violin; Piers Lane, piano</artist>
</audio>
</nexgen_audio_export>
`)
var feed Feed
reader := bytes.NewReader(xml_data)
decoder := xml.NewDecoder(reader)
decoder.CharsetReader = charset.NewReader
err := decoder.Decode(&feed)
if err != nil {
fmt.Println("decoder error:", err)
}
fmt.Println(feed.Audio.Title)
}