Finalized resolver

This commit is contained in:
Simon Martens
2025-01-03 18:57:22 +01:00
parent e6a77ab557
commit 9ca2ebb75f
10 changed files with 225 additions and 64 deletions

View File

@@ -0,0 +1,29 @@
package xmlprovider
import "fmt"
type XMLItem interface {
fmt.Stringer
Keys() []string
Name() string
}
type ILibrary interface {
Parse(meta ParseMeta) error
}
type ResolvingMap[T XMLItem] map[string][]Resolved[T]
type ReferenceResolver[T XMLItem] interface {
References() ResolvingMap[T]
}
type Resolved[T XMLItem] struct {
Item *T
Reference string
Category string
Cert bool
Conjecture bool
Comment string
MetaData map[string]string
}

View File

@@ -7,30 +7,26 @@ import (
"sync" "sync"
) )
type ReferenceResolver interface {
GetReferences() map[string][]string
}
type Resolver[T XMLItem] struct { type Resolver[T XMLItem] struct {
index map[string]map[string][]*T // Map[typeName][refID] -> []*T index map[string]map[string][]Resolved[T] // Map[typeName][refID] -> []*T
mu sync.Mutex // Synchronization for thread safety mu sync.Mutex // Synchronization for thread safety
} }
func NewResolver[T XMLItem]() *Resolver[T] { func NewResolver[T XMLItem]() *Resolver[T] {
return &Resolver[T]{index: make(map[string]map[string][]*T)} return &Resolver[T]{index: make(map[string]map[string][]Resolved[T])}
} }
func (r *Resolver[T]) Add(typeName, refID string, item *T) { func (r *Resolver[T]) Add(typeName, refID string, item Resolved[T]) {
r.mu.Lock() r.mu.Lock()
defer r.mu.Unlock() defer r.mu.Unlock()
if _, exists := r.index[typeName]; !exists { if _, exists := r.index[typeName]; !exists {
r.index[typeName] = make(map[string][]*T) r.index[typeName] = make(map[string][]Resolved[T])
} }
r.index[typeName][refID] = append(r.index[typeName][refID], item) r.index[typeName][refID] = append(r.index[typeName][refID], item)
} }
func (r *Resolver[T]) Get(typeName, refID string) ([]*T, error) { func (r *Resolver[T]) Get(typeName, refID string) ([]Resolved[T], error) {
r.mu.Lock() r.mu.Lock()
defer r.mu.Unlock() defer r.mu.Unlock()

View File

@@ -34,17 +34,6 @@ func (p ParseMeta) Failed(path string) bool {
return slices.Contains(p.FailedPaths, path) return slices.Contains(p.FailedPaths, path)
} }
type XMLItem interface {
fmt.Stringer
Keys() []string
Name() string
}
type ILibrary interface {
Parse(meta ParseMeta) error
Latest() *ParseMeta
}
// An XMLProvider is a struct that holds holds serialized XML data of a specific type. It combines multiple parses IF a succeeded parse can not serialize the data from a path. // An XMLProvider is a struct that holds holds serialized XML data of a specific type. It combines multiple parses IF a succeeded parse can not serialize the data from a path.
type XMLProvider[T XMLItem] struct { type XMLProvider[T XMLItem] struct {
// INFO: map is type map[string]*T // INFO: map is type map[string]*T
@@ -72,7 +61,8 @@ func NewXMLProvider[T XMLItem]() *XMLProvider[T] {
func (p *XMLProvider[T]) Prepare() { func (p *XMLProvider[T]) Prepare() {
p.mu.Lock() p.mu.Lock()
defer p.mu.Unlock() defer p.mu.Unlock()
p.Array = make([]T, 0) // INFO: We take 1000 here as to not reallocate the memory as mutch.
p.Array = make([]T, 0, 1000)
} }
func (p *XMLProvider[T]) Serialize(dataholder XMLRootElement[T], path string, latest ParseMeta) error { func (p *XMLProvider[T]) Serialize(dataholder XMLRootElement[T], path string, latest ParseMeta) error {
@@ -94,13 +84,14 @@ func (p *XMLProvider[T]) Serialize(dataholder XMLRootElement[T], path string, la
} }
// INFO: If the item has a GetReferences method, we add the references to the resolver. // INFO: If the item has a GetReferences method, we add the references to the resolver.
// if refResolver, ok := any(item).(ReferenceResolver); ok { if rr, ok := any(item).(ReferenceResolver[T]); ok {
// for name, ids := range refResolver.GetReferences() { for name, ids := range rr.References() {
// for _, id := range ids { for _, res := range ids {
// p.Resolver.Add(name, id, &item) res.Item = &item
// } p.Resolver.Add(name, res.Reference, res)
// } }
// } }
}
} }
p.Array = append(p.Array, newItems...) p.Array = append(p.Array, newItems...)
@@ -144,7 +135,7 @@ func (p *XMLProvider[T]) Cleanup(latest ParseMeta) {
} }
} }
func (p *XMLProvider[T]) ReverseLookup(item XMLItem) ([]*T, error) { func (p *XMLProvider[T]) ReverseLookup(item XMLItem) ([]Resolved[T], error) {
keys := item.Keys() keys := item.Keys()
if len(keys) == 0 { if len(keys) == 0 {
@@ -158,7 +149,7 @@ func (p *XMLProvider[T]) ReverseLookup(item XMLItem) ([]*T, error) {
} }
} }
return []*T{}, nil return []Resolved[T]{}, nil
} }
func (a *XMLProvider[T]) String() string { func (a *XMLProvider[T]) String() string {

View File

@@ -64,14 +64,17 @@ func AgentsView(letterorid string, lib *xmlmodels.Library) *AgentsListView {
// TODO: We won't need to lock the library if we take down the server during parsing // TODO: We won't need to lock the library if we take down the server during parsing
lib.Works.Lock() lib.Works.Lock()
for _, w := range lib.Works.Array { // for _, a := range res.Agents {
if ref, ok := w.ReferencesAgent(letterorid); ok { //
if entry, ok := res.Agents[ref.Ref]; ok { // }
entry.Works = append(entry.Works, WorkByAgent{Work: w, Reference: *ref}) // for _, w := range lib.Works.Array {
res.Agents[ref.Ref] = entry // if ref, ok := w.ReferencesAgent(letterorid); ok {
} // if entry, ok := res.Agents[ref.Ref]; ok {
} // entry.Works = append(entry.Works, WorkByAgent{Work: w, Reference: *ref})
} // res.Agents[ref.Ref] = entry
// }
// }
// }
lib.Works.Unlock() lib.Works.Unlock()
lib.Pieces.Lock() lib.Pieces.Lock()

View File

@@ -2,7 +2,6 @@ package viewmodels
import ( import (
"fmt" "fmt"
"log"
"maps" "maps"
"slices" "slices"
"sort" "sort"
@@ -33,7 +32,6 @@ func YearView(year int, lib *xmlmodels.Library) (*YearVM, error) {
lib.Issues.Lock() lib.Issues.Lock()
for _, issue := range lib.Issues.Array { for _, issue := range lib.Issues.Array {
log.Printf("Issue: %v", issue)
y := issue.Datum.When.Year y := issue.Datum.When.Year
years[y] = true years[y] = true
if y == year { if y == year {

View File

@@ -61,6 +61,13 @@ func (i Identifier) Keys() []string {
return i.keys return i.keys
} }
type Reference struct {
Ref string `xml:"ref,attr"`
Category string `xml:"kat,attr"`
Unsicher bool `xml:"unsicher,attr"`
Inner Inner
}
type Value struct { type Value struct {
Chardata string `xml:",chardata"` Chardata string `xml:",chardata"`
} }

View File

@@ -40,12 +40,12 @@ func (l *Library) String() string {
// INFO: this is the only place where the providers are created. There is no need for locking on access. // INFO: this is the only place where the providers are created. There is no need for locking on access.
func NewLibrary() *Library { func NewLibrary() *Library {
return &Library{ return &Library{
Agents: &xmlprovider.XMLProvider[Agent]{}, Agents: xmlprovider.NewXMLProvider[Agent](),
Places: &xmlprovider.XMLProvider[Place]{}, Places: xmlprovider.NewXMLProvider[Place](),
Works: &xmlprovider.XMLProvider[Work]{}, Works: xmlprovider.NewXMLProvider[Work](),
Categories: &xmlprovider.XMLProvider[Category]{}, Categories: xmlprovider.NewXMLProvider[Category](),
Issues: &xmlprovider.XMLProvider[Issue]{}, Issues: xmlprovider.NewXMLProvider[Issue](),
Pieces: &xmlprovider.XMLProvider[Piece]{}, Pieces: xmlprovider.NewXMLProvider[Piece](),
} }
} }

View File

@@ -6,6 +6,7 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/Theodor-Springmann-Stiftung/kgpz_web/providers/xmlprovider"
"github.com/google/uuid" "github.com/google/uuid"
) )
@@ -66,6 +67,111 @@ func (p Piece) ReferencesIssue(y, no int) (*IssueRef, bool) {
return nil, false return nil, false
} }
func (p Piece) References() xmlprovider.ResolvingMap[Piece] {
refs := make(xmlprovider.ResolvingMap[Piece])
x := CategoryRef{}
for _, ref := range p.IssueRefs {
if ref.When.Year == 0 || ref.Nr == 0 {
continue
}
if ref.Category != "" {
refs[x.Name()] = append(refs[x.Name()], xmlprovider.Resolved[Piece]{
Reference: ref.Category,
Cert: !ref.Unsicher,
Conjecture: false,
Comment: ref.Inner.InnerXML,
})
}
refs[ref.Name()] = append(refs[ref.Name()], xmlprovider.Resolved[Piece]{
Reference: strconv.Itoa(ref.When.Year) + "-" + strconv.Itoa(ref.Nr),
Category: ref.Category,
Cert: !ref.Unsicher,
Conjecture: false,
Comment: ref.Inner.InnerXML,
MetaData: map[string]string{"Von": strconv.Itoa(ref.Von), "Bis": strconv.Itoa(ref.Bis)},
})
}
for _, ref := range p.PlaceRefs {
if ref.Category != "" {
refs[x.Name()] = append(refs[x.Name()], xmlprovider.Resolved[Piece]{
Reference: ref.Category,
Cert: !ref.Unsicher,
Conjecture: false,
Comment: ref.Inner.InnerXML,
})
}
refs[ref.Name()] = append(refs[ref.Name()], xmlprovider.Resolved[Piece]{
Reference: ref.Ref,
Category: ref.Category,
Cert: !ref.Unsicher,
Conjecture: false,
Comment: ref.Inner.InnerXML,
MetaData: map[string]string{},
})
}
for _, ref := range p.AgentRefs {
if ref.Category != "" {
refs[x.Name()] = append(refs[x.Name()], xmlprovider.Resolved[Piece]{
Reference: ref.Category,
Cert: !ref.Unsicher,
Conjecture: false,
Comment: ref.Inner.InnerXML,
})
}
refs[ref.Name()] = append(refs[ref.Name()], xmlprovider.Resolved[Piece]{
Reference: ref.Ref,
Category: ref.Category,
Cert: !ref.Unsicher,
Conjecture: false,
Comment: ref.Inner.InnerXML,
MetaData: map[string]string{},
})
}
for _, ref := range p.WorkRefs {
if ref.Category != "" {
refs[x.Name()] = append(refs[x.Name()], xmlprovider.Resolved[Piece]{
Reference: ref.Category,
Cert: !ref.Unsicher,
Conjecture: false,
Comment: ref.Inner.InnerXML,
})
}
refs[ref.Name()] = append(refs[ref.Name()], xmlprovider.Resolved[Piece]{
Reference: ref.Ref,
Category: ref.Category,
Cert: !ref.Unsicher,
Conjecture: false,
MetaData: map[string]string{},
})
}
for _, ref := range p.PieceRefs {
if ref.Category != "" {
refs[x.Name()] = append(refs[x.Name()], xmlprovider.Resolved[Piece]{
Reference: ref.Category,
Cert: !ref.Unsicher,
Conjecture: false,
Comment: ref.Inner.InnerXML,
MetaData: map[string]string{},
})
}
refs[ref.Name()] = append(refs[ref.Name()], xmlprovider.Resolved[Piece]{
Reference: ref.Ref,
Category: ref.Category,
Cert: !ref.Unsicher,
Conjecture: false,
Comment: ref.Inner.InnerXML,
MetaData: map[string]string{},
})
}
return refs
}
func (p Piece) ReferencesAgent(a string) (*AgentRef, bool) { func (p Piece) ReferencesAgent(a string) (*AgentRef, bool) {
for _, i := range p.AgentRefs { for _, i := range p.AgentRefs {
if strings.HasPrefix(i.Ref, a) { if strings.HasPrefix(i.Ref, a) {

View File

@@ -2,18 +2,16 @@ package xmlmodels
import "encoding/xml" import "encoding/xml"
type Reference struct {
Ref string `xml:"ref,attr"`
Category string `xml:"kat,attr"`
Unsicher bool `xml:"unsicher,attr"`
Value
}
type AgentRef struct { type AgentRef struct {
XMLName xml.Name `xml:"akteur"` XMLName xml.Name `xml:"akteur"`
Reference Reference
} }
func (ar AgentRef) Name() string {
var x Agent
return x.Name()
}
type IssueRef struct { type IssueRef struct {
XMLName xml.Name `xml:"stueck"` XMLName xml.Name `xml:"stueck"`
Nr int `xml:"nr,attr"` Nr int `xml:"nr,attr"`
@@ -24,24 +22,49 @@ type IssueRef struct {
Reference // Nicht im Schema Reference // Nicht im Schema
} }
func (ir IssueRef) Name() string {
var x Issue
return x.Name()
}
type PlaceRef struct { type PlaceRef struct {
XMLName xml.Name `xml:"ort"` XMLName xml.Name `xml:"ort"`
Reference Reference
} }
func (pr PlaceRef) Name() string {
var x Place
return x.Name()
}
type CategoryRef struct { type CategoryRef struct {
XMLName xml.Name `xml:"kategorie"` XMLName xml.Name `xml:"kategorie"`
Reference Reference
} }
func (cr CategoryRef) Name() string {
var x Category
return x.Name()
}
type WorkRef struct { type WorkRef struct {
XMLName xml.Name `xml:"werk"` XMLName xml.Name `xml:"werk"`
Page string `xml:"s,attr"` Page string `xml:"s,attr"`
Reference Reference
} }
func (wr WorkRef) Name() string {
var x Work
return x.Name()
}
type PieceRef struct { type PieceRef struct {
XMLName xml.Name `xml:"beitrag"` XMLName xml.Name `xml:"beitrag"`
Page string `xml:"s,attr"` Page string `xml:"s,attr"`
Reference Reference
} }
func (pr PieceRef) Name() string {
var x Piece
return x.Name()
}

View File

@@ -3,7 +3,8 @@ package xmlmodels
import ( import (
"encoding/json" "encoding/json"
"encoding/xml" "encoding/xml"
"strings"
"github.com/Theodor-Springmann-Stiftung/kgpz_web/providers/xmlprovider"
) )
type Work struct { type Work struct {
@@ -20,15 +21,6 @@ func (w Work) Name() string {
return "work" return "work"
} }
func (p Work) ReferencesAgent(a string) (*AgentRef, bool) {
for _, i := range p.AgentRefs {
if strings.HasPrefix(i.Ref, a) {
return &i, true
}
}
return nil, false
}
type Citation struct { type Citation struct {
XMLName xml.Name `xml:"zitation"` XMLName xml.Name `xml:"zitation"`
Title string `xml:"title"` Title string `xml:"title"`
@@ -37,6 +29,22 @@ type Citation struct {
Inner Inner
} }
func (w Work) References() xmlprovider.ResolvingMap[Work] {
refs := make(xmlprovider.ResolvingMap[Work])
for _, ref := range w.AgentRefs {
refs[ref.Name()] = append(refs[ref.Name()], xmlprovider.Resolved[Work]{
Item: &w, // Reference to the current Work item
Reference: ref.Ref, // Reference ID
Category: ref.Category, // Category of the reference
Cert: !ref.Unsicher, // Certainty flag (true if not unsure)
Conjecture: false,
Comment: ref.Inner.InnerXML,
})
}
return refs
}
func (w Work) String() string { func (w Work) String() string {
data, _ := json.MarshalIndent(w, "", " ") data, _ := json.MarshalIndent(w, "", " ")
return string(data) return string(data)