1
1

More than 5 years have passed since last update.

UTF-16エンコードのXMLファイルをgolangでパースする

Last updated at Posted at 2016-09-12

注意

この方法が正しいのかどうかは不明です。

やり方

<?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.CharsetReaderfake_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にしかない文字コードとかあったらコケそう。

参考

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1