Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does this XML validation via XSD fail in libxml2 (but succeed in xmllint) and how do I fix it?

If I run this XML validation via xmllint:

xmllint --noout --schema schema.xsd test.xml

I get this success message:

.../test.xml validates

However if I run the same validation via libxml2's C API:

int result = xmlSchemaValidateDoc(...)

I get a return value of 1845 and this failure message:

Element '{http://example.com/XMLSchema/1.0}foo': No matching global declaration available for the validation root.

Which I can make absolutely no sense of. :(


schema.xsd:

<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE xs:schema PUBLIC "-//W3C//DTD XMLSCHEMA 200102//EN" "XMLSchema.dtd" >
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://example.com/XMLSchema/1.0" targetNamespace="http://example.com/XMLSchema/1.0" elementFormDefault="qualified" attributeFormDefault="unqualified">

    <xs:element name="foo">
    </xs:element>
</xs:schema>

test.xml:

<?xml version="1.0" encoding="UTF-8"?>

<foo xmlns="http://example.com/XMLSchema/1.0">
</foo>

main.c:

#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <string.h>

#include <libxml/parser.h>
#include <libxml/valid.h>
#include <libxml/xmlschemas.h>

u_int32_t get_file_size(const char *file_name) {
    struct stat buf;
    if ( stat(file_name, &buf) != 0 ) return(0);
    return (unsigned int)buf.st_size;
}

void handleValidationError(void *ctx, const char *format, ...) {
    char *errMsg;
    va_list args;
    va_start(args, format);
    vasprintf(&errMsg, format, args);
    va_end(args);
    fprintf(stderr, "Validation Error: %s", errMsg);
    free(errMsg);
}

int main (int argc, const char * argv[]) {
    const char *xsdPath = argv[1];
    const char *xmlPath = argv[2];

    printf("\n");

    printf("XSD File: %s\n", xsdPath);
    printf("XML File: %s\n", xmlPath);

    int xmlLength = get_file_size(xmlPath);
    char *xmlSource = (char *)malloc(sizeof(char) * xmlLength);

    FILE *p = fopen(xmlPath, "r");
    char c;
    unsigned int i = 0;
    while ((c = fgetc(p)) != EOF) {
        xmlSource[i++] = c;
    }
    printf("\n");

    printf("XML Source:\n\n%s\n", xmlSource);
    fclose(p);

    printf("\n");

    int result = 42;
    xmlSchemaParserCtxtPtr parserCtxt = NULL;
    xmlSchemaPtr schema = NULL;
    xmlSchemaValidCtxtPtr validCtxt = NULL;

    xmlDocPtr xmlDocumentPointer = xmlParseMemory(xmlSource, xmlLength);
    parserCtxt = xmlSchemaNewParserCtxt(xsdPath);

    if (parserCtxt == NULL) {
        fprintf(stderr, "Could not create XSD schema parsing context.\n");
        goto leave;
    }

    schema = xmlSchemaParse(parserCtxt);

    if (schema == NULL) {
        fprintf(stderr, "Could not parse XSD schema.\n");
        goto leave;
    }

    validCtxt = xmlSchemaNewValidCtxt(schema);

    if (!validCtxt) {
        fprintf(stderr, "Could not create XSD schema validation context.\n");
        goto leave;
    }

    xmlSetStructuredErrorFunc(NULL, NULL);
    xmlSetGenericErrorFunc(NULL, handleValidationError);
    xmlThrDefSetStructuredErrorFunc(NULL, NULL);
    xmlThrDefSetGenericErrorFunc(NULL, handleValidationError);

    result = xmlSchemaValidateDoc(validCtxt, xmlDocumentPointer);

leave:

    if (parserCtxt) {
        xmlSchemaFreeParserCtxt(parserCtxt);
    }

    if (schema) {
        xmlSchemaFree(schema);
    }

    if (validCtxt) {
        xmlSchemaFreeValidCtxt(validCtxt);
    }
    printf("\n");
    printf("Validation successful: %s (result: %d)\n", (result == 0) ? "YES" : "NO", result);

    return 0;
}

console output:

XSD File: /Users/dephiniteloop/Desktop/xml_validate/schema.xsd
XML File: /Users/dephiniteloop/Desktop/xml_validate/test.gkml

XML Source:

<?xml version="1.0" encoding="UTF-8"?>

<foo xmlns="http://example.com/XMLSchema/1.0">
</foo>

Validation Error: Element '{http://example.com/XMLSchema/1.0}foo': No matching global declaration available for the validation root.

Validation successful: NO (result: 1845)

In case it matters: I'm on OSX 10.6.7 with its default libxml2.dylib
(/Developer/SDKs/MacOSX10.6.sdk/usr/lib/libxml2.2.7.3.dylib)

like image 770
mtree Avatar asked Jun 08 '11 20:06

mtree


People also ask

How connect XML to XSD?

Reference the XSD schema in the XML document using XML schema instance attributes such as either xsi:schemaLocation or xsi:noNamespaceSchemaLocation. Add the XSD schema file to a schema cache and then connect that cache to the DOM document or SAX reader, prior to loading or parsing the XML document.


2 Answers

After getting some help on the gnome project's xml mailing-list it appears as if my error is not caused by a bug of mine, but rather by a bug of OSX 10.6.x's distribution (v2.7.3) of libxml2.
(as in: same code works for others, yet fails for me OSX' legacy distribution)

I checked the libxml2 release notes and found two candidates:

Release notes of Update 2.7.4 list the following bug fix:

  • "579746 XSD validation not correct / nilable groups (Daniel Veillard)"

Release notes of Update 2.7.8 list the following bug fix:

  • "Fix errors in XSD double validation check (Csaba Raduly)"

Haven't yet had success getting the latest build (v2.7.8) of libxml2 to work with my project (or rather Xcode in general) though.

like image 156
mtree Avatar answered Oct 11 '22 12:10

mtree


I tried your content and code on Ubuntu Linux. Worked without any objection.

Build command:

gcc -Wall -I/usr/include/libxml2 main.c -lxml2 -o xmlvalid 

Run command:

./xmlvalid ./schema.xsd ./test.xml

Output:

XSD File: ./schema.xsd
XML File: ./test.xml

XML Source:

<?xml version="1.0" encoding="UTF-8"?>

<foo xmlns="http://example.com/XMLSchema/1.0">
</foo>

Validation successful: YES (result: 0)

like image 22
jsa Avatar answered Oct 11 '22 13:10

jsa