146 lines
3.4 KiB
Go
146 lines
3.4 KiB
Go
package eprel
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// ExtractFromAttrs builds the nested EPREL object used by V1 process items and
|
|
// the dashboard product API (id / label / pdf / energy_class / energy_scale).
|
|
// Returns nil when no usable EPREL fields are present.
|
|
//
|
|
// Nested attrs["eprel"] may use flat export aliases (eprel_id, eprel_label, …);
|
|
// those are normalized onto the public keys. Flat eprel_* keys fill any gaps.
|
|
func ExtractFromAttrs(attrs map[string]any) any {
|
|
if attrs == nil {
|
|
return nil
|
|
}
|
|
out := map[string]any{}
|
|
if e, ok := attrs["eprel"]; ok && e != nil {
|
|
switch t := e.(type) {
|
|
case map[string]any:
|
|
for k, v := range t {
|
|
if s := attrString(v); s == "" {
|
|
continue
|
|
} else {
|
|
out[strings.TrimSpace(k)] = s
|
|
}
|
|
}
|
|
default:
|
|
if s := attrString(e); s != "" {
|
|
return map[string]any{"id": s}
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
put := func(dstKey string, keys ...string) {
|
|
if attrString(out[dstKey]) != "" {
|
|
return
|
|
}
|
|
for _, k := range keys {
|
|
if s := attrString(attrs[k]); s != "" {
|
|
out[dstKey] = s
|
|
return
|
|
}
|
|
// Also accept aliases already copied from a nested object.
|
|
if s := attrString(out[k]); s != "" {
|
|
out[dstKey] = s
|
|
return
|
|
}
|
|
}
|
|
}
|
|
put("id", "eprel_id", "EPRELID", "eprelId")
|
|
put("label", "eprel_label", "eprel_label_url")
|
|
put("pdf", "eprel_pdf", "eprel_pdf_url")
|
|
put("energy_class", "eprel_energy_class", "energyClass")
|
|
put("energy_scale", "eprel_energy_scale", "energyClassRange", "energyScale")
|
|
return NormalizeShape(out)
|
|
}
|
|
|
|
// NormalizeShape keeps only the public EPREL keys with non-empty string values.
|
|
// Alias keys (eprel_id, …) are folded onto id/label/pdf/energy_class/energy_scale.
|
|
func NormalizeShape(v any) any {
|
|
if v == nil {
|
|
return nil
|
|
}
|
|
m, ok := v.(map[string]any)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
if len(m) == 0 {
|
|
return nil
|
|
}
|
|
out := map[string]any{}
|
|
for k, val := range m {
|
|
if s := attrString(val); s != "" {
|
|
out[strings.TrimSpace(k)] = s
|
|
}
|
|
}
|
|
fold := func(dst string, aliases ...string) {
|
|
if attrString(out[dst]) != "" {
|
|
for _, a := range aliases {
|
|
delete(out, a)
|
|
}
|
|
return
|
|
}
|
|
for _, a := range aliases {
|
|
if s := attrString(out[a]); s != "" {
|
|
out[dst] = s
|
|
break
|
|
}
|
|
}
|
|
for _, a := range aliases {
|
|
delete(out, a)
|
|
}
|
|
}
|
|
fold("id", "eprel_id", "EPRELID", "eprelId")
|
|
fold("label", "eprel_label", "eprel_label_url")
|
|
fold("pdf", "eprel_pdf", "eprel_pdf_url")
|
|
fold("energy_class", "eprel_energy_class", "energyClass")
|
|
fold("energy_scale", "eprel_energy_scale", "energyClassRange", "energyScale")
|
|
|
|
canonical := map[string]any{}
|
|
for _, k := range []string{"id", "label", "pdf", "energy_class", "energy_scale"} {
|
|
if s := attrString(out[k]); s != "" {
|
|
canonical[k] = s
|
|
}
|
|
}
|
|
if len(canonical) == 0 {
|
|
return nil
|
|
}
|
|
return canonical
|
|
}
|
|
|
|
func attrString(v any) string {
|
|
if v == nil {
|
|
return ""
|
|
}
|
|
switch t := v.(type) {
|
|
case string:
|
|
return strings.TrimSpace(t)
|
|
case float64:
|
|
// JSON numbers for numeric eprel ids.
|
|
if t == float64(int64(t)) {
|
|
return strings.TrimSpace(fmt.Sprintf("%.0f", t))
|
|
}
|
|
return strings.TrimSpace(fmt.Sprint(t))
|
|
case int:
|
|
return fmt.Sprintf("%d", t)
|
|
case int64:
|
|
return fmt.Sprintf("%d", t)
|
|
case map[string]any:
|
|
for _, k := range []string{"value", "#text", "text", "id"} {
|
|
if s := attrString(t[k]); s != "" {
|
|
return s
|
|
}
|
|
}
|
|
return ""
|
|
default:
|
|
s := strings.TrimSpace(fmt.Sprint(v))
|
|
if s == "" || s == "<nil>" {
|
|
return ""
|
|
}
|
|
return s
|
|
}
|
|
}
|