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