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 == "" { 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 / 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 "" }