parse plus
This commit is contained in:
parent
a40e947e60
commit
f7b8217d32
6 changed files with 7823 additions and 1582 deletions
|
@ -2,6 +2,7 @@ package main
|
|||
|
||||
import (
|
||||
"flag"
|
||||
"log"
|
||||
|
||||
"github.com/robertjanetzko/LegendsBrowser2/analyze/df"
|
||||
)
|
||||
|
@ -16,6 +17,9 @@ func main() {
|
|||
}
|
||||
|
||||
if *g {
|
||||
df.Generate()
|
||||
err := df.Generate()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -115,6 +115,8 @@ func createMetadata(a *AnalyzeData) (*Metadata, error) {
|
|||
Type: "int",
|
||||
Multiple: a.Fields[f].Multiple,
|
||||
Legend: legend,
|
||||
Base: a.Fields[f].Base,
|
||||
Plus: a.Fields[f].Plus,
|
||||
}
|
||||
if ok, elements := isArray(f, fs); ok {
|
||||
el := typeNames[elements]
|
||||
|
@ -141,7 +143,7 @@ func createMetadata(a *AnalyzeData) (*Metadata, error) {
|
|||
Id: a.Fields[k+PATH_SEPARATOR+"id"] != nil,
|
||||
Named: a.Fields[k+PATH_SEPARATOR+"name"] != nil,
|
||||
Typed: a.Fields[k+PATH_SEPARATOR+"type"] != nil,
|
||||
SubTypes: getSubtypes(objectTypes, k),
|
||||
SubTypes: getSubtypes(a, k),
|
||||
SubTypeOf: getSubtypeOf(k),
|
||||
Fields: objFields,
|
||||
}
|
||||
|
@ -172,22 +174,17 @@ func filterSubtypes(data *map[string]*FieldData) []string {
|
|||
return list
|
||||
}
|
||||
|
||||
func getSubtypes(objectTypes []string, k string) *[]string {
|
||||
subtypes := make(map[string]bool)
|
||||
|
||||
for _, t := range objectTypes {
|
||||
if strings.HasPrefix(t, k+"+") && !strings.Contains(t[len(k):], PATH_SEPARATOR) {
|
||||
subtypes[t[strings.LastIndex(t, "+")+1:]] = true
|
||||
func getSubtypes(a *AnalyzeData, k string) *[]Subtype {
|
||||
if allowedTyped[k] {
|
||||
if st, ok := a.SubTypes[k]; ok {
|
||||
var list []Subtype
|
||||
for _, v := range *st {
|
||||
list = append(list, *v)
|
||||
}
|
||||
return &list
|
||||
}
|
||||
}
|
||||
|
||||
keys := util.Keys(subtypes)
|
||||
sort.Strings(keys)
|
||||
|
||||
if len(keys) > 0 {
|
||||
return &keys
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -7,9 +7,11 @@ import (
|
|||
"go/format"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"sort"
|
||||
"text/template"
|
||||
|
||||
"github.com/iancoleman/strcase"
|
||||
"github.com/robertjanetzko/LegendsBrowser2/backend/util"
|
||||
)
|
||||
|
||||
type Object struct {
|
||||
|
@ -17,17 +19,25 @@ type Object struct {
|
|||
Id bool `json:"id,omitempty"`
|
||||
Named bool `json:"named,omitempty"`
|
||||
Typed bool `json:"typed,omitempty"`
|
||||
SubTypes *[]string `json:"subtypes,omitempty"`
|
||||
SubTypes *[]Subtype `json:"subtypes,omitempty"`
|
||||
SubTypeOf *string `json:"subtypeof,omitempty"`
|
||||
Fields map[string]Field `json:"fields"`
|
||||
}
|
||||
|
||||
type Subtype struct {
|
||||
Name string `json:"name"`
|
||||
BaseType string `json:"base"`
|
||||
PlusType string `json:"plus"`
|
||||
}
|
||||
|
||||
type Field struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
Multiple bool `json:"multiple,omitempty"`
|
||||
ElementType *string `json:"elements,omitempty"`
|
||||
Legend string `json:"legend"`
|
||||
Base bool
|
||||
Plus bool
|
||||
}
|
||||
|
||||
func (f Field) TypeLine() string {
|
||||
|
@ -55,7 +65,15 @@ func (f Field) TypeLine() string {
|
|||
return fmt.Sprintf("%s %s%s %s", n, m, t, j)
|
||||
}
|
||||
|
||||
func (f Field) StartAction() string {
|
||||
func (f Field) Init(plus bool) string {
|
||||
if !plus && f.Type == "map" {
|
||||
return fmt.Sprintf("obj.%s = make(map[int]*%s)", f.Name, *f.ElementType)
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func (f Field) StartAction(plus bool) string {
|
||||
n := f.Name
|
||||
|
||||
if n == "Id" || n == "Name" {
|
||||
|
@ -63,7 +81,7 @@ func (f Field) StartAction() string {
|
|||
}
|
||||
|
||||
if f.Type == "object" {
|
||||
p := fmt.Sprintf("v, _ := parse%s(d, &t)", f.Name)
|
||||
p := fmt.Sprintf("v, _ := parse%s(d, &t)", *f.ElementType)
|
||||
if !f.Multiple {
|
||||
return fmt.Sprintf("%s\nobj.%s = v", p, n)
|
||||
} else {
|
||||
|
@ -79,7 +97,12 @@ func (f Field) StartAction() string {
|
|||
}
|
||||
|
||||
if f.Type == "map" {
|
||||
return fmt.Sprintf("obj.%s = make(map[int]*%s)\nparseMap(d, &obj.%s, %s)", f.Name, *f.ElementType, f.Name, gen)
|
||||
if !plus {
|
||||
return fmt.Sprintf("parseMap(d, &obj.%s, %s)", f.Name, gen)
|
||||
} else {
|
||||
gen = fmt.Sprintf("parse%sPlus", *f.ElementType)
|
||||
return fmt.Sprintf("parseMapPlus(d, &obj.%s, %s)", f.Name, gen)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -114,16 +137,67 @@ func (f Field) EndAction() string {
|
|||
return ""
|
||||
}
|
||||
|
||||
func (f Field) Active(plus bool) bool {
|
||||
if plus && f.Plus {
|
||||
return true
|
||||
}
|
||||
if !plus && f.Base {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type ActiveSubType struct {
|
||||
Case string
|
||||
Name string
|
||||
Options []string
|
||||
}
|
||||
|
||||
func (f Object) ActiveSubTypes(plus bool) []*ActiveSubType {
|
||||
subs := make(map[string]*ActiveSubType)
|
||||
|
||||
for _, s := range *f.SubTypes {
|
||||
if !plus && s.BaseType == "" {
|
||||
continue
|
||||
}
|
||||
if plus && s.PlusType == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
a := ActiveSubType{}
|
||||
if plus {
|
||||
a.Case = s.PlusType
|
||||
} else {
|
||||
a.Case = s.BaseType
|
||||
}
|
||||
a.Name = f.Name + s.Name
|
||||
a.Options = append(a.Options, a.Name)
|
||||
|
||||
if sub, ok := subs[a.Case]; ok {
|
||||
sub.Options = append(sub.Options, a.Name)
|
||||
} else {
|
||||
subs[a.Case] = &a
|
||||
}
|
||||
}
|
||||
|
||||
list := util.Values(subs)
|
||||
sort.SliceStable(list, func(i, j int) bool {
|
||||
return list[i].Case < list[j].Case
|
||||
})
|
||||
|
||||
return list
|
||||
}
|
||||
|
||||
var packageTemplate = template.Must(template.New("").Parse(`// Code generated by legendsbrowser; DO NOT EDIT.
|
||||
package model
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"strconv"
|
||||
"github.com/iancoleman/strcase"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
{{- range $name, $obj := .Objects }}
|
||||
{{- range $name, $obj := $.Objects }}
|
||||
type {{ $obj.Name }} struct {
|
||||
{{- range $fname, $field := $obj.Fields }}
|
||||
{{- if not (and (eq $fname "type") (not (not $obj.SubTypes))) }}
|
||||
|
@ -150,12 +224,25 @@ func n(d []byte) int {
|
|||
return v
|
||||
}
|
||||
|
||||
{{- range $name, $obj := .Objects }}
|
||||
func parse{{ $obj.Name }}(d *xml.Decoder, start *xml.StartElement) (*{{ $obj.Name }}, error) {
|
||||
{{- range $name, $obj := $.Objects }}
|
||||
{{- range $plus := $.Modes }}
|
||||
func parse{{ $obj.Name }}{{ if $plus }}Plus{{ end }}(d *xml.Decoder, start *xml.StartElement{{ if $plus }}, obj *{{ $obj.Name }}{{ end }}) (*{{ $obj.Name }}, error) {
|
||||
var (
|
||||
obj = {{ $obj.Name }}{}
|
||||
{{- if not $plus }}
|
||||
obj = &{{ $obj.Name }}{}
|
||||
{{- end }}
|
||||
data []byte
|
||||
)
|
||||
{{- if $plus }}
|
||||
if obj == nil {
|
||||
obj = &{{ $obj.Name }}{}
|
||||
}
|
||||
{{- end }}
|
||||
|
||||
{{- range $fname, $field := $obj.Fields }}
|
||||
{{ $field.Init $plus }}
|
||||
{{- end }}
|
||||
|
||||
for {
|
||||
tok, err := d.Token()
|
||||
if err != nil {
|
||||
|
@ -165,8 +252,10 @@ func parse{{ $obj.Name }}(d *xml.Decoder, start *xml.StartElement) (*{{ $obj.Nam
|
|||
case xml.StartElement:
|
||||
switch t.Name.Local {
|
||||
{{- range $fname, $field := $obj.Fields }}
|
||||
{{- if $field.Active $plus }}
|
||||
case "{{ $fname }}":
|
||||
{{ $field.StartAction }}
|
||||
{{ $field.StartAction $plus }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
default:
|
||||
// fmt.Println("unknown field", t.Name.Local)
|
||||
|
@ -178,18 +267,35 @@ func parse{{ $obj.Name }}(d *xml.Decoder, start *xml.StartElement) (*{{ $obj.Nam
|
|||
|
||||
case xml.EndElement:
|
||||
if t.Name.Local == start.Name.Local {
|
||||
return &obj, nil
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
switch t.Name.Local {
|
||||
{{- range $fname, $field := $obj.Fields }}
|
||||
{{- range $fname, $field := $obj.Fields }}{{- if $field.Active $plus }}
|
||||
case "{{ $fname }}":
|
||||
{{- if and (eq $fname "type") (not (not $obj.SubTypes)) }}
|
||||
|
||||
var err error
|
||||
switch strcase.ToCamel(string(data)) {
|
||||
{{- range $sub := $obj.SubTypes }}
|
||||
case "{{ $sub }}":
|
||||
obj.Details, err = parse{{ $obj.Name }}{{ $sub }}(d, start)
|
||||
switch string(data) {
|
||||
{{- range $sub := ($obj.ActiveSubTypes $plus) }}
|
||||
case "{{ $sub.Case }}":
|
||||
{{- if eq 1 (len $sub.Options) }}
|
||||
{{- if not $plus }}
|
||||
obj.Details, err = parse{{ $sub.Name }}(d, start)
|
||||
{{- else }}
|
||||
obj.Details, err = parse{{ $sub.Name }}Plus(d, start, obj.Details.(*{{ $sub.Name }}))
|
||||
{{- end }}
|
||||
{{- else }}
|
||||
switch details := obj.Details.(type) {
|
||||
{{- range $opt := $sub.Options }}
|
||||
case *{{ $opt}}:
|
||||
obj.Details, err = parse{{ $opt }}Plus(d, start, details)
|
||||
{{- end }}
|
||||
default:
|
||||
fmt.Println("unknown subtype option", obj.Details)
|
||||
d.Skip()
|
||||
}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
default:
|
||||
d.Skip()
|
||||
|
@ -197,11 +303,12 @@ func parse{{ $obj.Name }}(d *xml.Decoder, start *xml.StartElement) (*{{ $obj.Nam
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &obj, nil
|
||||
return obj, nil
|
||||
|
||||
{{- else }}
|
||||
{{ $field.EndAction }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}{{- end }}
|
||||
default:
|
||||
// fmt.Println("unknown field", t.Name.Local)
|
||||
}
|
||||
|
@ -209,6 +316,7 @@ func parse{{ $obj.Name }}(d *xml.Decoder, start *xml.StartElement) (*{{ $obj.Nam
|
|||
}
|
||||
}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
`))
|
||||
|
||||
func generateCode(objects *Metadata) error {
|
||||
|
@ -224,15 +332,18 @@ func generateCode(objects *Metadata) error {
|
|||
var buf bytes.Buffer
|
||||
err = packageTemplate.Execute(&buf, struct {
|
||||
Objects *Metadata
|
||||
Modes []bool
|
||||
}{
|
||||
Objects: objects,
|
||||
Modes: []bool{false, true},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
p, err := format.Source(buf.Bytes())
|
||||
if err != nil {
|
||||
return err
|
||||
fmt.Println("WARN: could not format source", err)
|
||||
p = buf.Bytes()
|
||||
}
|
||||
_, err = f.Write(p)
|
||||
return err
|
||||
|
|
|
@ -17,7 +17,7 @@ import (
|
|||
|
||||
func AnalyzeStructure(filex string) error {
|
||||
fmt.Println("Search...", filex)
|
||||
files, err := filepath.Glob(filex + "/*.xml")
|
||||
files, err := filepath.Glob(filex + "/*-legends.xml")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -44,12 +44,14 @@ func NewFieldData() *FieldData {
|
|||
}
|
||||
|
||||
type AnalyzeData struct {
|
||||
Fields map[string]*FieldData
|
||||
Fields map[string]*FieldData
|
||||
SubTypes map[string]*map[string]*Subtype
|
||||
}
|
||||
|
||||
func NewAnalyzeData() *AnalyzeData {
|
||||
return &AnalyzeData{
|
||||
Fields: make(map[string]*FieldData, 0),
|
||||
Fields: make(map[string]*FieldData, 0),
|
||||
SubTypes: make(map[string]*map[string]*Subtype),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,29 +84,86 @@ func (a *AnalyzeData) GetField(s string) *FieldData {
|
|||
}
|
||||
}
|
||||
|
||||
func analyze(file string, a *AnalyzeData) error {
|
||||
xmlFile, err := os.Open(file)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
func (a *AnalyzeData) GetSubType(s string, t string) *Subtype {
|
||||
var (
|
||||
st *map[string]*Subtype
|
||||
su *Subtype
|
||||
ok bool
|
||||
)
|
||||
|
||||
if st, ok = a.SubTypes[s]; !ok {
|
||||
x := make(map[string]*Subtype)
|
||||
a.SubTypes[s] = &x
|
||||
st = &x
|
||||
}
|
||||
|
||||
plus := strings.HasSuffix(file, "_plus.xml")
|
||||
if su, ok = (*st)[t]; !ok {
|
||||
x := Subtype{Name: t}
|
||||
(*st)[t] = &x
|
||||
su = &x
|
||||
}
|
||||
|
||||
return su
|
||||
}
|
||||
|
||||
type AnalyzeContext struct {
|
||||
file string
|
||||
plus bool
|
||||
subtypes map[string]map[int]string
|
||||
}
|
||||
|
||||
func analyze(file string, a *AnalyzeData) error {
|
||||
|
||||
ctx := AnalyzeContext{
|
||||
file: file,
|
||||
plus: false,
|
||||
subtypes: make(map[string]map[int]string),
|
||||
}
|
||||
|
||||
// base file
|
||||
|
||||
xmlFile, err := os.Open(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("Successfully Opened", file)
|
||||
defer xmlFile.Close()
|
||||
|
||||
converter := util.NewConvertReader(xmlFile)
|
||||
_, err = analyzeElement(xml.NewDecoder(util.NewConvertReader(xmlFile)), a, make([]string, 0), &ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return analyzeElement(xml.NewDecoder(converter), a, make([]string, 0), plus)
|
||||
// plus file
|
||||
|
||||
ctx.plus = true
|
||||
file = strings.Replace(file, "-legends.xml", "-legends_plus.xml", 1)
|
||||
xmlFile, err = os.Open(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Println("Successfully Opened", file)
|
||||
defer xmlFile.Close()
|
||||
|
||||
_, err = analyzeElement(xml.NewDecoder(util.NewConvertReader(xmlFile)), a, make([]string, 0), &ctx)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
const PATH_SEPARATOR = "|"
|
||||
|
||||
func analyzeElement(d *xml.Decoder, a *AnalyzeData, path []string, plus bool) error {
|
||||
type Value struct {
|
||||
Name string
|
||||
Value string
|
||||
}
|
||||
|
||||
func analyzeElement(d *xml.Decoder, a *AnalyzeData, path []string, ctx *AnalyzeContext) (*Value, error) {
|
||||
if len(path) > 1 {
|
||||
s := strings.Join(path, PATH_SEPARATOR)
|
||||
fd := a.GetField(s)
|
||||
if plus {
|
||||
if ctx.plus {
|
||||
fd.Plus = true
|
||||
} else {
|
||||
fd.Base = true
|
||||
|
@ -112,7 +171,11 @@ func analyzeElement(d *xml.Decoder, a *AnalyzeData, path []string, plus bool) er
|
|||
}
|
||||
|
||||
var (
|
||||
data []byte
|
||||
data []byte
|
||||
id int
|
||||
idFound bool
|
||||
subtype string
|
||||
subtypeFound bool
|
||||
)
|
||||
value := true
|
||||
|
||||
|
@ -124,7 +187,7 @@ Loop:
|
|||
if err == io.EOF {
|
||||
break Loop
|
||||
} else if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
switch t := tok.(type) {
|
||||
case xml.StartElement:
|
||||
|
@ -137,24 +200,64 @@ Loop:
|
|||
}
|
||||
fields[t.Name.Local] = true
|
||||
|
||||
analyzeElement(d, a, newPath, plus)
|
||||
v, err := analyzeElement(d, a, newPath, ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if v != nil {
|
||||
if v.Name == "id" {
|
||||
idFound = true
|
||||
id, _ = strconv.Atoi(v.Value)
|
||||
}
|
||||
if v.Name == "type" {
|
||||
subtypeFound = true
|
||||
subtype = v.Value
|
||||
|
||||
if idFound && subtypeFound {
|
||||
p := strings.Join(path, PATH_SEPARATOR)
|
||||
if strings.Contains(p, "+") {
|
||||
p = p[:strings.LastIndex(p, "+")]
|
||||
}
|
||||
typeMap, ok := ctx.subtypes[p]
|
||||
if !ok {
|
||||
typeMap = make(map[int]string)
|
||||
ctx.subtypes[p] = typeMap
|
||||
}
|
||||
if !ctx.plus {
|
||||
typeMap[id] = subtype
|
||||
a.GetSubType(p, strcase.ToCamel(subtype)).BaseType = subtype
|
||||
} else {
|
||||
if typeMap[id] != subtype {
|
||||
if typeMap[id] != "" {
|
||||
a.GetSubType(p, strcase.ToCamel(typeMap[id])).PlusType = subtype
|
||||
} else {
|
||||
a.GetSubType(p, strcase.ToCamel(subtype)).PlusType = subtype
|
||||
}
|
||||
subtype = typeMap[id]
|
||||
} else {
|
||||
a.GetSubType(p, strcase.ToCamel(subtype)).PlusType = subtype
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
path[len(path)-1] = path[len(path)-1] + "+" + strcase.ToCamel(subtype)
|
||||
}
|
||||
}
|
||||
|
||||
case xml.CharData:
|
||||
data = append(data, t...)
|
||||
|
||||
case xml.EndElement:
|
||||
if value {
|
||||
if _, err := strconv.Atoi(string(data)); err != nil {
|
||||
s := string(data)
|
||||
if _, err := strconv.Atoi(s); err != nil {
|
||||
a.GetField(strings.Join(path, PATH_SEPARATOR)).IsString = true
|
||||
}
|
||||
return &Value{Name: t.Name.Local, Value: s}, nil
|
||||
}
|
||||
|
||||
if t.Name.Local == "type" {
|
||||
path[len(path)-2] = path[len(path)-2] + "+" + strcase.ToCamel(string(data))
|
||||
}
|
||||
|
||||
return nil
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
return nil, nil
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -3,7 +3,10 @@ package model
|
|||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/robertjanetzko/LegendsBrowser2/backend/util"
|
||||
)
|
||||
|
@ -23,6 +26,8 @@ func Parse(file string) (*DfWorld, error) {
|
|||
converter := util.NewConvertReader(xmlFile)
|
||||
d := xml.NewDecoder(converter)
|
||||
|
||||
var world *DfWorld
|
||||
BaseLoop:
|
||||
for {
|
||||
tok, err := d.Token()
|
||||
if err != nil {
|
||||
|
@ -31,10 +36,51 @@ func Parse(file string) (*DfWorld, error) {
|
|||
switch t := tok.(type) {
|
||||
case xml.StartElement:
|
||||
if t.Name.Local == "df_world" {
|
||||
return parseDfWorld(d, &t)
|
||||
world, err = parseDfWorld(d, &t)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
break BaseLoop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plus := true
|
||||
|
||||
if plus {
|
||||
file = strings.Replace(file, "-legends.xml", "-legends_plus.xml", 1)
|
||||
xmlFile, err := os.Open(file)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return world, nil
|
||||
}
|
||||
|
||||
fmt.Println("Successfully Opened", file)
|
||||
defer xmlFile.Close()
|
||||
|
||||
converter := util.NewConvertReader(xmlFile)
|
||||
d := xml.NewDecoder(converter)
|
||||
|
||||
PlusLoop:
|
||||
for {
|
||||
tok, err := d.Token()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch t := tok.(type) {
|
||||
case xml.StartElement:
|
||||
if t.Name.Local == "df_world" {
|
||||
world, err = parseDfWorldPlus(d, &t, world)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
break PlusLoop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return world, nil
|
||||
}
|
||||
|
||||
func parseArray[T any](d *xml.Decoder, dest *[]T, creator func(*xml.Decoder, *xml.StartElement) (T, error)) {
|
||||
|
@ -70,3 +116,52 @@ func parseMap[T Identifiable](d *xml.Decoder, dest *map[int]T, creator func(*xml
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func parseMapPlus[T Identifiable](d *xml.Decoder, dest *map[int]T, creator func(*xml.Decoder, *xml.StartElement, T) (T, error)) {
|
||||
for {
|
||||
tok, err := d.Token()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
switch t := tok.(type) {
|
||||
case xml.StartElement:
|
||||
id, err := parseId(d)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
x, err := creator(d, &t, (*dest)[id])
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
(*dest)[id] = x
|
||||
|
||||
case xml.EndElement:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
func parseId(d *xml.Decoder) (int, error) {
|
||||
var data []byte
|
||||
for {
|
||||
tok, err := d.Token()
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
switch t := tok.(type) {
|
||||
case xml.StartElement:
|
||||
data = nil
|
||||
if t.Name.Local != "id" {
|
||||
d.Skip()
|
||||
// return -1, fmt.Errorf("expected id at: %d", d.InputOffset())
|
||||
}
|
||||
|
||||
case xml.CharData:
|
||||
data = append(data, t...)
|
||||
|
||||
case xml.EndElement:
|
||||
if t.Name.Local == "id" {
|
||||
return strconv.Atoi(string(data))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue