例1
json/XMLに"192.168.0.1"を値として持つフィールドがあり、それをgo言語のnet.IP型としてパースしたい。
例2
json/XMLに"PT1440M"を値として持つフィールドがあり、をISO8601継続時間型としてgo言語のtime.Duration型としてパースしたい。
■ ISO8601とは
ISO 8601は、日付と時刻の表記に関するISOの国際規格である。
(略)
ISO 8601形式の時刻表記例
基本形式 20220622T124204+0900
拡張形式 2022-06-22T12:42:04+09:00
wikipediaより
■ ISO8601継続時間とは
継続時間は、ある期間中に含まれる時間の合計を定義し、P[n]Y[n]M[n]DT[n]H[n]M[n]S、または、右に示すように、P[n]Wの形式で表される。
(略)
P は期間を表す指定子(period を表す)であり、継続時間表現の先頭に置かれる。
Y は年の指定子であり、年を表す数値の後に置かれる。
M は月の指定子であり、月を表す数値の後に置かれる。
W は週の指定子であり、週を表す数値の後に置かれる。
D は日の指定子であり、日を表す数値の後に置かれる。
T 時間の指定子であり、継続時間表現の時間の部分の前に置く。
H は時間の指定子であり、時間を表す数値の後に置かれる。
M は分の指定子であり、分を表す数値の後に置かれる。
S は秒の指定子であり、秒を表す数値の後に置かれる。
たとえば、P3Y6M4DT12H30M5Sは、「3年、6か月、4日、12時間、30分、5秒」という継続時間を表現している。
wikipediaより
まず json/XMLに含まれる文字列フィールドを文字列としてパースする方法をおさらいしておく。
一般的に以下のように書く。
(エラーハンドリングは省略。以降同じ。)
実行結果
以下の部分を、stringではなくnet.IP型、time.Duration型として読むように修正したい。
IPアドレス文字列は以下の方法でnet.IP型にパースできる。
ISO8601継続時間文字列はそのままではtime.Duration型にパースできない。
ISO8601継続時間型を扱うライブラリ(ここでは"github.com/rickb777/date/period")を使えば以下の方法でtime.Duration型にパースできる。
上記をjson/XMLを構造体に読み込む際に呼び出されるメソッドUnmarshalJSON()/UnmarshalXML()に組み込む。
UnmarshalJSON()/UnmarshalXML()内部で、一旦、各フィールドの値を文字列として吸い出してしまうのがミソ。
UnmarshalJSON()/UnmarshalXML()は
で呼び出される。
実行結果
この方法の場合はjsonとXMLでそれぞれ
json/XMLを読み込む構造体のフィールドの型がUnmarshalText()を持っている場合はそれを使うことができる。UnmarshalText()には文字列をパースする処理が実装済みである。
フィールドの型がUnmarshalText()を持っていない場合は、自分で用意した型ならUnmarshalText()を実装できる。(goDoc)
今回のjson/XML構造体内のフィールドのnet.IP型はUnmarshalText()を持つ。(goDoc)
time.Durationはそれ自体ではISO8601継続時間文字列をパースできないので、time.Duration型に変わって、"github.com/rickb777/date/period"のperiod型をフィールドとして持たせる。
このperiod型はUnmarshalText()を持つ。(goDoc)
よって、方法1の場合とは違って
net.IP型/period型のUnmarshalText()も
で呼び出される。
実行結果