diff --git a/errors.go b/errors.go index dedd6a1..01d00b2 100644 --- a/errors.go +++ b/errors.go @@ -42,6 +42,7 @@ type StructError struct { Level int Line int NodeName string + Path string } // ValidationError is returned when xsd validation caused an error, to access the fields of the Errors slice use type assertion (see example). diff --git a/examples_test.go b/examples_test.go index 8cef49d..d25abdf 100644 --- a/examples_test.go +++ b/examples_test.go @@ -43,6 +43,7 @@ func Example() { fmt.Println(err) fmt.Printf("Error in line: %d\n", err.(xsdvalidate.ValidationError).Errors[0].Line) fmt.Println(err.(xsdvalidate.ValidationError).Errors[0].Message) + fmt.Println(err.(xsdvalidate.ValidationError).Errors[0].Path) default: fmt.Println(err) } @@ -56,6 +57,7 @@ func Example() { fmt.Println(err) fmt.Printf("Error in line: %d\n", err.(xsdvalidate.ValidationError).Errors[0].Line) fmt.Println(err.(xsdvalidate.ValidationError).Errors[0].Message) + fmt.Println(err.(xsdvalidate.ValidationError).Errors[0].Path) default: fmt.Println(err) } @@ -64,7 +66,9 @@ func Example() { // 3: Element 'shipto': This element is not expected. Expected is ( orderperson ). // Error in line: 3 // Element 'shipto': This element is not expected. Expected is ( orderperson ). + // shiptolen; i++) { free(errArr->data[i].message); free(errArr->data[i].node); + free(errArr->data[i].path); } free(errArr->data); } @@ -147,6 +149,7 @@ static void simpleStructErrorCallback(void* ctx, xmlErrorPtr p) { struct simpleXmlError sErr; sErr.message = calloc(GO_ERR_INIT, sizeof(char)); sErr.node = calloc(GO_ERR_INIT, sizeof(char)); + sErr.path = calloc(GO_ERR_INIT, sizeof(char)); sErr.type = VALIDATION_ERROR; sErr.code = p->code; @@ -168,6 +171,35 @@ static void simpleStructErrorCallback(void* ctx, xmlErrorPtr p) { sErr.node = malloc(cpyLen); snprintf(sErr.node, cpyLen, "%s", (((xmlNodePtr)p->node)->name)); } + + int pathLen = GO_ERR_INIT; + if (cpyLen > pathLen) { + free(sErr.path); + pathLen = cpyLen *2; + sErr.path = malloc(pathLen); + } + + cpyLen = snprintf(sErr.path, pathLen, "%s", sErr.node); + xmlNodePtr node = (xmlNodePtr)p->node; + node = node->parent; + while (node != NULL && node->name != NULL) { + int offset = cpyLen; + int limit = pathLen - offset; + + cpyLen = cpyLen + snprintf(sErr.path+offset, limit, "<%s", node->name); + if (cpyLen > pathLen) { + pathLen += cpyLen; + limit = pathLen - offset; + + char* newPath = malloc(pathLen); + cpyLen = snprintf(newPath, offset + 1, "%s", sErr.path); + cpyLen = cpyLen + snprintf(newPath + offset, limit, "<%s", node->name); + + free(sErr.path); + sErr.path = newPath; + } + node = node->parent; + } } if (sErrArr->len >= sErrArr->cap) { sErrArr->cap = sErrArr->cap * 2; @@ -304,6 +336,7 @@ static errArray cValidate(const xmlDocPtr doc, const xmlSchemaPtr schema) { struct simpleXmlError simpleError; simpleError.message = calloc(GO_ERR_INIT, sizeof(char)); simpleError.node = calloc(GO_ERR_INIT, sizeof(char)); + simpleError.path = calloc(GO_ERR_INIT, sizeof(char)); if (schema == NULL) { simpleError.type = LIBXML2_ERROR; @@ -338,6 +371,7 @@ static errArray cValidate(const xmlDocPtr doc, const xmlSchemaPtr schema) { } else { free(simpleError.node); free(simpleError.message); + free(simpleError.path); } } } @@ -357,6 +391,7 @@ static errArray cValidateBuf(const void* goXmlSource, struct simpleXmlError simpleError; simpleError.message = calloc(GO_ERR_INIT, sizeof(char)); simpleError.node = calloc(GO_ERR_INIT, sizeof(char)); + simpleError.path = calloc(GO_ERR_INIT, sizeof(char)); struct xmlParserResult parserResult = cParseDoc(goXmlSource, goXmlSourceLen, xmlParserOptions); @@ -387,6 +422,7 @@ static errArray cValidateBuf(const void* goXmlSource, } free(simpleError.node); free(simpleError.message); + free(simpleError.path); freeErrArray(&errArr); free(parserResult.errorStr); @@ -476,7 +512,8 @@ func handleErrArray(errSlice []C.struct_simpleXmlError) ValidationError { Message: strings.Trim(C.GoString(errSlice[i].message), "\n"), Level: int(errSlice[i].level), Line: int(errSlice[i].line), - NodeName: C.GoString(errSlice[i].node)} + NodeName: C.GoString(errSlice[i].node), + Path: C.GoString(errSlice[i].path)} } return ve