概要
知らなかったので、忘れないうちにメモメモ。。。
通常、XMLのエンコーディングはUTF-8となっているものがほとんどですが、業務とかだと稀に Shift_JIS とかなっている場合があります。
例えば、以下のような感じ。
<?xml version="1.0" encoding="Shift_JIS"?> <data> <hello>へろー</hello> <world>ワールド</world> </data>
当然、ファイルのエンコーディングはShift-JISで保存されてるので、VSCodeとかで見るとデフォでは化けます。
上記のようなXMLデータを xml.Unmarshal しようとすると、データを読み出す io.Reader がShift-JISに対応していても、以下のようにエラーが返ってきます。
xml: encoding "Shift_JIS" declared but Decoder.CharsetReader is nil
「エンコーディングのところが Shift_JIS ってなってるけど、 Decoder.CharsetReader が nil やで」
って言ってますね。最初、CharsetReader って何?ってなりました。
以下に記載がありました。
https://pkg.go.dev/encoding/xml@go1.19.2#Decoder
なるほど。なので、これを設定すれば良いということですね。
てことで、試してみました。
サンプル
データとして利用するのは上に挙げた XML です。
// XML宣言にてencodingの指定がUTF-8ではない場合のXMLデコードのサンプルです. // // # REFERENCES // // - https://stackoverflow.com/questions/54915307/error-unmarshaling-a-simple-xml-in-golang // - https://qiita.com/bamchoh/items/a4c64ace78200bf0fa6e // - https://pkg.go.dev/encoding/xml@go1.19.2#Decoder package main import ( "encoding/xml" "fmt" "io" "log" "github.com/devlights/gomy/fileio" "github.com/devlights/gomy/fileio/jp" ) type ( xmlData struct { XMLName xml.Name `xml:"data"` Hello string `xml:"hello"` World string `xml:"world"` } ) func (me xmlData) String() string { return fmt.Sprintf("hello=%s\tworld=%s", me.Hello, me.World) } func fail() error { var ( r io.Reader closer func() error err error ) r, closer, err = fileio.OpenRead("sample.xml", jp.ShiftJis) if err != nil { return err } defer closer() var ( data xmlData decoder = xml.NewDecoder(r) ) // encoding="shift-jis" なデータをそのままUnmarshalするとエラーになる // // 以下のランタイムエラーが出る // xml: encoding "shift-jis" declared but Decoder.CharsetReader is nil err = decoder.Decode(&data) if err != nil { fmt.Printf("[fail] %v\n", err) return nil } fmt.Printf("[fail] %v\n", data) return nil } func succ() error { var ( r io.Reader closer func() error err error ) r, closer, err = fileio.OpenRead("sample.xml", jp.ShiftJis) if err != nil { return err } defer closer() var ( data xmlData decoder = xml.NewDecoder(r) ) // encoding="shift-jis" なデータをそのままUnmarshalするとエラーになる // // XML宣言にてUTF-8以外のエンコーディングが指定されている場合 // CharsetReaderが呼び出されるため、設定する必要がある. decoder.CharsetReader = func(charset string, input io.Reader) (io.Reader, error) { // 既に shift-jis で読み出せる io.Reader なので、そのまま返す. // そうではない場合は、ここでラップして返す. return input, nil } err = decoder.Decode(&data) if err != nil { return err } fmt.Printf("[succ] %v\n", data) return nil } func run() error { var ( err error ) err = fail() if err != nil { return err } err = succ() if err != nil { return err } return nil } func main() { err := run() if err != nil { log.Fatalln(err) } }
version: "3" tasks: default: cmds: - go run main.go
実行すると以下のようになります。
$ task -d examples/singleapp/xml_shiftjis/ task: [default] go run main.go [fail] xml: encoding "Shift_JIS" declared but Decoder.CharsetReader is nil [succ] hello=へろー world=ワールド
参考情報
try-golang/examples/singleapp/xml_shiftjis at master · devlights/try-golang · GitHub
過去の記事については、以下のページからご参照下さい。
サンプルコードは、以下の場所で公開しています。