This commit is contained in:
2026-08-16 16:57:36 +02:00
parent 96f8c1115c
commit 532d439c41
106 changed files with 10147 additions and 494 deletions
+57
View File
@@ -85,6 +85,13 @@ func normalizeValue(key string, v any) any {
if v == nil {
return nil
}
// Descriptions must be plain scalars (never leftover ["…"] / HTML arrays).
if isDescriptionFieldKey(key) {
if s := PlainDescriptionFromAny(v); s != "" {
return SanitizeText(s)
}
return nil
}
switch t := v.(type) {
case string:
s := strings.TrimSpace(t)
@@ -124,6 +131,13 @@ func normalizeValue(key string, v any) any {
if text, ok := t["text"]; ok {
return normalizeValue(key, text)
}
// Feed/XML category objects often carry unique_id — flatten to a scalar
// so StepResult.Category / processed_products.category get the code.
if key == "category" {
if id := categoryUniqueIDFromAny(t); id != "" {
return id
}
}
nested := make(map[string]any, len(t))
for nk, nv := range t {
if nn := normalizeValue(canonicalizeKey(nk), nv); nn != nil {
@@ -138,6 +152,14 @@ func normalizeValue(key string, v any) any {
if len(t) == 0 {
return nil
}
// Scalar-ish fields (name, brand, eprel_id, …): collapse one-element /
// joinable arrays so process steps never see []any where a string is expected.
if flat := coerceScalarText(t); flat != "" && looksLikeScalarFieldArray(t) {
if isDimensionKey(key) && isZeroishString(flat) {
return nil
}
return SanitizeText(flat)
}
out := make([]any, 0, len(t))
for _, item := range t {
if nn := normalizeValue(key, item); nn != nil {
@@ -160,6 +182,41 @@ func normalizeValue(key string, v any) any {
}
}
// looksLikeScalarFieldArray is true when every element coerces to a short scalar
// (string/number/#text) — not nested attribute/spec objects.
func looksLikeScalarFieldArray(items []any) bool {
if len(items) == 0 {
return false
}
for _, item := range items {
switch t := item.(type) {
case nil:
continue
case string, float64, float32, int, int64, int32, bool:
continue
case map[string]any:
if _, ok := t["#text"]; ok {
continue
}
if _, ok := t["text"]; ok {
continue
}
if _, ok := t["value"]; ok {
continue
}
return false
case []any, []string:
return false
default:
if _, ok := item.(jsonNumberStringer); ok {
continue
}
return false
}
}
return true
}
func isDimensionKey(key string) bool {
switch key {
case "width", "height", "depth", "weight", "length", "net_width", "net_height", "net_depth", "net_mass":