github.com/kaptinlin/jsonschema@v0.4.6/oneOf.go (about) 1 package jsonschema 2 3 import ( 4 "fmt" 5 "strconv" 6 "strings" 7 ) 8 9 // EvaluateOneOf checks if the data conforms to exactly one of the schemas specified in the oneOf attribute. 10 // According to the JSON Schema Draft 2020-12: 11 // - The "oneOf" keyword's value must be a non-empty array, where each item is either a valid JSON Schema or a boolean. 12 // - An instance validates successfully against this keyword if it validates successfully against exactly one schema or is true for exactly one boolean in this array. 13 // 14 // This function ensures that the data instance meets exactly one of the specified constraints defined by the schemas or booleans in the oneOf array. 15 // If the instance conforms to more than one or none of the schemas, it returns a EvaluationError detailing the specific failures or the lack of a valid schema. 16 // 17 // Reference: https://json-schema.org/draft/2020-12/json-schema-core#name-oneof 18 func evaluateOneOf(schema *Schema, instance interface{}, evaluatedProps map[string]bool, evaluatedItems map[int]bool, dynamicScope *DynamicScope) ([]*EvaluationResult, *EvaluationError) { 19 if len(schema.OneOf) == 0 { 20 return nil, nil // No oneOf constraints to validate against. 21 } 22 23 valid_indexs := []string{} 24 results := []*EvaluationResult{} 25 var tempEvaluatedProps map[string]bool 26 var tempEvaluatedItems map[int]bool 27 28 for i, subSchema := range schema.OneOf { 29 if subSchema != nil { 30 result, schemaEvaluatedProps, schemaEvaluatedItems := subSchema.evaluate(instance, dynamicScope) 31 if result != nil { 32 results = append(results, result.SetEvaluationPath(fmt.Sprintf("/oneOf/%d", i)). 33 SetSchemaLocation(schema.GetSchemaLocation(fmt.Sprintf("/oneOf/%d", i))). 34 SetInstanceLocation(""), 35 ) 36 37 if result.IsValid() { 38 valid_indexs = append(valid_indexs, strconv.Itoa(i)) 39 tempEvaluatedProps = schemaEvaluatedProps 40 tempEvaluatedItems = schemaEvaluatedItems 41 } 42 } 43 } 44 } 45 46 if len(valid_indexs) == 1 { 47 // Merge maps only if exactly one schema or boolean condition is successfully validated 48 mergeStringMaps(evaluatedProps, tempEvaluatedProps) 49 mergeIntMaps(evaluatedItems, tempEvaluatedItems) 50 return results, nil 51 } 52 53 if len(valid_indexs) > 1 { 54 return results, NewEvaluationError("oneOf", "one_of_multiple_matches", "Value should match exactly one schema but matches multiple at indexes {matches}", map[string]interface{}{ 55 "matches": strings.Join(valid_indexs, ", "), 56 }) 57 } else { // If no conditions are met, return error 58 return results, NewEvaluationError("oneOf", "one_of_item_mismatch", "Value does not match the oneOf schema") 59 } 60 }