Golangではencoding/xml
パッケージでXMLを簡単に扱えそうなので、Hello World的に試してみました。
今回のエントリでは、XMLファイルを読んで特定のエレメントを削ったXMLを再出力するということをやってみました。
(といっても、Unmarshal(XML⇒構造体への変換)する構造体に対象要素に紐づくメンバを用意しないだけで実現できます)
前提
今回は以下のようなXMLが書かれたファイルがあるとして、その中からdescription
というエレメントを除外したいとします
<?xml version="1.0" encoding="UTF-8"?> <servers> <server> <id>s0001</id> <name>サーバA-001</name> <port>443</port> <description>試験用のサーバです</description> <subscriber_id>sub000002</subscriber_id> <contract_period> <start_date>2017-10-01</start_date> <end_date>2021-09-30</end_date> </contract_period> </server> <server> <id>s0002</id> <name>サーバA-002</name> <port>8080</port> <description>ECサイトで利用するための</description> <subscriber_id>sub000001</subscriber_id> <contract_period> <start_date>2012-04-01</start_date> <end_date>2024-03-31</end_date> </contract_period> </server> <server> <id>s0003</id> <name>サーバA-002</name> <port>8080</port> <description>利用用途未定</description> <subscriber_id>sub000003</subscriber_id> <contract_period> <start_date>2015-04-01</start_date> <end_date>2019-03-31</end_date> </contract_period> </server> </servers>
Golang側のコードでは、上記XMLをUnmarshalして紐づける構造体を以下のように用意しました。
(server構造体に、description
のエレメントを紐づける変数がありません)
除外する要素以外は構造体のタグで紐づけを行っています
type ServerList struct { XMLName xml.Name `xml:"servers"` Svs []server `xml:"server"` } type server struct { XMLName xml.Name `xml:"server"` ID string `xml:"id"` ServerName string `xml:"name"` Port string `xml:"port"` SubscriberID string `xml:"subscriber_id"` ContractStartDate string `xml:"contract_period>start_date"` ContractEndDate string `xml:"contract_period>end_date"` }
実行サンプル
以下XMLファイルを読んで、エレメント削って出力するGoのプログラムです。
読み込むXMLファイルをコマンドラインで -f パラメータに与えて、エレメントを除外した結果を標準出力に出力するようにしています。
(そのため、結果をリダイレクトれば結果をファイルに出力できます)
package main import ( "encoding/xml" "flag" "fmt" "io/ioutil" "os" ) type ServerList struct { XMLName xml.Name `xml:"servers"` Svs []server `xml:"server"` } type server struct { XMLName xml.Name `xml:"server"` ID string `xml:"id"` ServerName string `xml:"name"` Port string `xml:"port"` SubscriberID string `xml:"subscriber_id"` ContractStartDate string `xml:"contract_period>start_date"` ContractEndDate string `xml:"contract_period>end_date"` } func main() { var ( srcXML string ) flag.StringVar(&srcXML, "f", "servers.xml.", "src xml path.") flag.Parse() file, err := os.Open(srcXML) if err != nil { fmt.Printf("error: %v", err) return } defer file.Close() data, err := ioutil.ReadAll(file) if err != nil { fmt.Printf("error: %v", err) return } serverList := ServerList{} err = xml.Unmarshal(data, &serverList) if err != nil { fmt.Printf("error: %v", err) return } output, err := xml.MarshalIndent(serverList, " ", " ") if err != nil { fmt.Printf("error: %v\n", err) } os.Stdout.Write([]byte(xml.Header)) os.Stdout.Write(output) }
ビルド(go build)後に以下のようにコマンドを実行(original.xmlが元のXMLファイル)
xmlconv.exe -f original.xml > dest.xml
結果、dest.xmlには以下のような内容が出力されています(description
というエレメントが除外されています)
<?xml version="1.0" encoding="UTF-8"?> <servers> <server> <id>s0001</id> <name>サーバA-001</name> <port>443</port> <subscriber_id>sub000002</subscriber_id> <contract_period> <start_date>2017-10-01</start_date> <end_date>2021-09-30</end_date> </contract_period> </server> <server> <id>s0002</id> <name>サーバA-002</name> <port>8080</port> <subscriber_id>sub000001</subscriber_id> <contract_period> <start_date>2012-04-01</start_date> <end_date>2024-03-31</end_date> </contract_period> </server> <server> <id>s0003</id> <name>サーバA-002</name> <port>8080</port> <subscriber_id>sub000003</subscriber_id> <contract_period> <start_date>2015-04-01</start_date> <end_date>2019-03-31</end_date> </contract_period> </server> </servers>
というわけで簡単にXMLファイルを扱うことができました