注意
この方法が正しいのかどうかは不明です。
やり方
<?xml version="1.0" encoding="utf-16"?>
<root>
<elem id="1">
Hello World
</elem>
<elem id="2">
こんにちは世界
</elem>
</root>
こんな感じのUTF-16(BOM付きBig Endian)のXMLファイルがあったとして
package main
import (
"encoding/xml"
"io"
"os"
"io/ioutil"
"bytes"
"unicode/utf16"
"unicode/utf8"
"strings"
"fmt"
)
type Elem struct {
Id string `xml:"id,attr"`
Text string `xml:",chardata"`
}
type Root struct {
Elems []Elem `xml:"elem"`
}
// UTF-16(BOM付き,BE)想定
func decode_utf16(b []byte) string {
u16s := make([]uint16, 1)
ret := &bytes.Buffer{}
b8buf := make([]byte, 4)
lb := len(b)
for i := 2; i < lb; i += 2 {
u16s[0] = uint16(b[i+1]) + (uint16(b[i]) << 8)
r := utf16.Decode(u16s)
n := utf8.EncodeRune(b8buf, r[0])
ret.Write(b8buf[:n])
}
return ret.String()
}
func fake_charset_reader(enc string, r io.Reader) (io.Reader, error) {
return r, nil
}
func main() {
fp, err := os.Open("utf-16.xml")
if err != nil {
panic(err)
}
xml_doc, _ := ioutil.ReadAll(fp)
var root Root
nr := strings.NewReader(decode_utf16(xml_doc))
decoder := xml.NewDecoder(nr)
decoder.CharsetReader = fake_charset_reader
err = decoder.Decode(&root)
if err != nil {
panic(err)
}
fmt.Println(root)
}
こんな感じのコードでパースできる。
ポイントは2箇所
-
decode_utf16(xml_doc)
でUTF-16をUTF-8に変換してるとこ -
decoder.CharsetReader
にfake_charset_reader
を代入してるとこ
decode_utf16()
で UTF-8 に変換しないと、XMLの一行目をちゃんと読み取ってくれないので、UTF-8のファイルじゃないよ。と怒られる。だからと言って、変換したデータだけ渡しても、CharsetReaderがセットされてないよと怒られる。んで、CharsetReader を charsetパッケージのCharsetReaderにしても、ちゃんと動かない(これがなぜかは不明だけど、おそらく渡ってきたio.ReaderがUTF-8に変換されているから、UTF-16じゃねぇよ!って怒られているんじゃないか)、なので、CharsetReaderにフェイクのCharsetReaderをかまして、エンコード無視でUTF-8のReaderを使うという作戦。一応、うまくいく。ただ、UTF-16にしかない文字コードとかあったらコケそう。
参考
-
[How to convert xml encoding UTF-16 to UTF-8 in golang]
http://stackoverflow.com/questions/34890522/how-to-convert-xml-encoding-utf-16-to-utf-8-in-golang -
[Unmarshal an ISO-8859-1 XML input in Go]
http://stackoverflow.com/questions/6002619/unmarshal-an-iso-8859-1-xml-input-in-go -
[XMLのパース/生成]
http://cuto.unirita.co.jp/gostudy/post/standard-library-xml/ -
[UTF-16は、実は5種類ある!]
http://d.hatena.ne.jp/chaichanPaPa/20081124/1227514306