128 lines
2.5 KiB
Go
128 lines
2.5 KiB
Go
package eprel
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
var eprelIDKeys = []string{
|
|
"eprel_id",
|
|
"EPRELID",
|
|
"eprelId",
|
|
"EprelId",
|
|
"eprelID",
|
|
}
|
|
|
|
// NormalizeID coerces XML/API values (string, number, {"#text": ...}) to a trimmed ID.
|
|
// Placeholder feed values like "0" / "0000" become empty so the EPREL step is not
|
|
// falsely "skipped" after a doomed fetch attempt.
|
|
func NormalizeID(v any) string {
|
|
if v == nil {
|
|
return ""
|
|
}
|
|
var s string
|
|
switch t := v.(type) {
|
|
case string:
|
|
s = strings.TrimSpace(t)
|
|
case json.Number:
|
|
s = strings.TrimSpace(t.String())
|
|
if i := strings.IndexByte(s, '.'); i >= 0 {
|
|
s = s[:i]
|
|
}
|
|
case float64:
|
|
if t != t { // NaN
|
|
return ""
|
|
}
|
|
s = strconv.FormatInt(int64(t), 10)
|
|
case float32:
|
|
s = strconv.FormatInt(int64(t), 10)
|
|
case int:
|
|
s = strconv.Itoa(t)
|
|
case int64:
|
|
s = strconv.FormatInt(t, 10)
|
|
case int32:
|
|
s = strconv.FormatInt(int64(t), 10)
|
|
case json.RawMessage:
|
|
var decoded any
|
|
if err := json.Unmarshal(t, &decoded); err != nil {
|
|
return ""
|
|
}
|
|
return NormalizeID(decoded)
|
|
case map[string]any:
|
|
if text, ok := t["#text"]; ok {
|
|
return NormalizeID(text)
|
|
}
|
|
if text, ok := t["text"]; ok {
|
|
return NormalizeID(text)
|
|
}
|
|
return ""
|
|
case []any:
|
|
for _, item := range t {
|
|
if id := NormalizeID(item); id != "" {
|
|
return id
|
|
}
|
|
}
|
|
return ""
|
|
case []string:
|
|
for _, item := range t {
|
|
if id := NormalizeID(item); id != "" {
|
|
return id
|
|
}
|
|
}
|
|
return ""
|
|
default:
|
|
s = strings.TrimSpace(fmt.Sprint(t))
|
|
if s == "" || s == "<nil>" {
|
|
return ""
|
|
}
|
|
}
|
|
if isPlaceholderEPRELID(s) {
|
|
return ""
|
|
}
|
|
return s
|
|
}
|
|
|
|
func isPlaceholderEPRELID(id string) bool {
|
|
id = strings.TrimSpace(id)
|
|
if id == "" {
|
|
return true
|
|
}
|
|
for _, r := range id {
|
|
if r != '0' {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
// IsValidID reports whether v normalizes to a non-empty EPREL registration id.
|
|
func IsValidID(v any) bool {
|
|
return NormalizeID(v) != ""
|
|
}
|
|
|
|
// ExtractID finds an EPREL ID in mapped, raw, and/or attribute field maps
|
|
// (vendor feeds often use <EPRELID/> / eprel_id; specs parse may put it only in attrs).
|
|
func ExtractID(sources ...map[string]any) string {
|
|
for _, src := range sources {
|
|
if src == nil {
|
|
continue
|
|
}
|
|
for _, key := range eprelIDKeys {
|
|
if id := NormalizeID(src[key]); id != "" {
|
|
return id
|
|
}
|
|
}
|
|
for key, value := range src {
|
|
compact := strings.ToLower(strings.ReplaceAll(key, "_", ""))
|
|
if compact == "eprelid" {
|
|
if id := NormalizeID(value); id != "" {
|
|
return id
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ""
|
|
}
|