Skip to content

Instantly share code, notes, and snippets.

@goura
Last active February 5, 2023 07:37
Show Gist options
  • Save goura/ea24ee3775cd08d1beb6700753195323 to your computer and use it in GitHub Desktop.
Save goura/ea24ee3775cd08d1beb6700753195323 to your computer and use it in GitHub Desktop.
Read Kifukinkoujo-ni-kansuru-shoumeisho (寄付金控除に関する証明書) from standard input and print items inside it
// Parse kifukinkoujoshoumeisho xml and print the donation entries inside it
// Disclaimer: This doesn't do XMLDsig verification
// Disclaimer: no warranty, use it at your own risk
//
// For example you can save this as furusato-sum.go and run it like
// $ cat aaaa.xml | go run furusato-sum.go | awk -F "\t" '{sum += $3} END {print sum}'
// To get the sum of the amount of donations inside the xml
package main
import (
"encoding/xml"
"fmt"
"io"
"os"
"time"
)
// <TEG830> is the root tag
// Contains two similar but different containers
type Teg830 struct {
XMLName xml.Name `xml:"TEG830"`
Container1 _Teg830_1 `xml:"TEG830-1"`
Container2 _Teg830_2 `xml:"TEG830-2"`
}
// <TEG830-1> tag contains metadata and the first 10 items
// We're not interested in metadata, so I'll just pick up the items
// Items are under the <WML00000> tag
type _Teg830_1 struct {
WML00000 _WML00000 `xml:"WML00000"`
}
// <TEG830-2> tag contains 11th and beyond items
// It contains <WMN00000> which is the same shape as <WML00000>
// But under <TEG830-2> there are multiple <WMN00000>s
type _Teg830_2 struct {
WMN00000s []_WMN00000 `xml:"WMN00000"`
}
// <WML00000> contains multiple <WML00010>s
// <WMN00000> contains multiple <WMN00010>s
// <WML00010> and <WMN00010> are the same shape
type _WML00000 struct {
WML00010s []_WML00010 `xml:"WML00010"`
}
type _WMN00000 struct {
WMN00010s []_WMN00010 `xml:"WMN00010"`
}
// <WML00010> contains what we want
// The unique ID (?), date, city info and the amount of money you donated
// <WMN00010> is the same shape as <WML00010>
type _WML00010 struct {
UniqueID string `xml:"WML00020"`
DateInfo _WMx00030 `xml:"WML00030"`
LGInfo _WML00040 `xml:"WML00040"`
Amount int `xml:"WML00070"`
}
type _WMN00010 struct {
UniqueID string `xml:"WMN00020"`
DateInfo _WMx00030 `xml:"WMN00030"`
LGInfo _WMN00040 `xml:"WMN00040"`
Amount int `xml:"WMN00070"`
}
// _WMx00030 is for both <WMN00030> and <WML00030>
type _WMx00030 struct {
Year int `xml:"yyyy"`
Month int `xml:"mm"`
Day int `xml:"dd"`
}
// <WML00040> and <WML00040> contain the city info
type _WML00040 struct {
LGName string `xml:"WML00050"`
LGNumber string `xml:"WML00060>hojinbango"`
}
type _WMN00040 struct {
LGName string `xml:"WMN00050"`
LGNumber string `xml:"WMN00060>hojinbango"`
}
// Struct for info we are interested in
type FurusatoItem struct {
UniqueID string
Date time.Time
Amount int
LGName string
LGNumber string
}
// Utility function to create time.Time from YYYYMMDD
func WMx00030toDate(DateInfo _WMx00030) time.Time {
loc, _ := time.LoadLocation("Asia/Tokyo")
t := time.Date(
DateInfo.Year,
time.Month(DateInfo.Month),
DateInfo.Day,
0, 0, 0, 0, loc)
return t
}
func main() {
// Read from stdio and parse XML
byteValue, _ := io.ReadAll(os.Stdin)
var teg830 Teg830
xml.Unmarshal(byteValue, &teg830)
furusatoItems := make([]FurusatoItem, 0)
// First pick up items under <TEG830-1>
for _, data := range teg830.Container1.WML00000.WML00010s {
item := FurusatoItem{
UniqueID: data.UniqueID,
Date: WMx00030toDate(data.DateInfo),
Amount: data.Amount,
LGName: data.LGInfo.LGName,
LGNumber: data.LGInfo.LGNumber,
}
furusatoItems = append(furusatoItems, item)
}
// Next pick up items under <TEG830-2>
for _, container := range teg830.Container2.WMN00000s {
for _, data := range container.WMN00010s {
item := FurusatoItem{
UniqueID: data.UniqueID,
Date: WMx00030toDate(data.DateInfo),
Amount: data.Amount,
LGName: data.LGInfo.LGName,
LGNumber: data.LGInfo.LGNumber,
}
furusatoItems = append(furusatoItems, item)
}
}
// Output as lines of tab separated values
for _, item := range furusatoItems {
datestr := item.Date.Format("2006/01/02")
fmt.Printf("%v\t%v\t%v\t%v\t%v\n", item.UniqueID, datestr, item.Amount, item.LGNumber, item.LGName)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment