libxml2 получает ошибки проверки xsd - PullRequest
0 голосов
/ 10 января 2019

Я использую xmlTextReader для обработки больших XML-файлов. Теперь мне нужно проверить экземпляр по схеме XSD. API из libxml2 немного сбивает с толку, как это сделать.

При моем подходе я получаю ошибки проверки в функции schemaParseErrorHandler, но без номеров строк или столбцов. Как я могу получить эту информацию?

#include <stdio.h>
#include <libxml/xmlreader.h>
#include <libxml/encoding.h>
#include <libxml/xmlwriter.h>

static void schemaParseErrorHandler(void *arg, xmlErrorPtr error)
{
    fprintf( stderr, "Error at line %d, column %d\n%s",
        error->line, error->int2, error->message);

    *((bool*)arg) = true;
}

int main( int argc, char **argv )
{
    xmlInitParser();

    xmlSchemaPtr schema = NULL;
    xmlSchemaParserCtxtPtr schema_parser_ctxt = NULL;

    int has_schema_errors = 0;
    int ret = -1;

    xmlSchemaValidCtxtPtr valid_ctxt = NULL;
    if ((schema_parser_ctxt = xmlSchemaNewParserCtxt("example.xsd")))
    {
        schema = xmlSchemaParse(schema_parser_ctxt);
        xmlSchemaFreeParserCtxt(schema_parser_ctxt);

        if (schema)
        {
            valid_ctxt = xmlSchemaNewValidCtxt(schema);
        }
    }

    xmlTextReaderPtr reader = NULL;
    reader = xmlReaderForFile(filename, RPCXmlStream::STD_ENCODING, 0);

    if (reader != NULL)
    {
        if (valid_ctxt)
        {
            xmlTextReaderSchemaValidateCtxt(reader, valid_ctxt, 0);
            xmlSchemaSetValidStructuredErrors(valid_ctxt, schemaParseErrorHandler, &has_schema_errors);
        }

        ret = xmlTextReaderRead(reader);

        while (ret == 1 && !has_schema_errors)
        {
            //... procesing informations
            ret = xmlTextReaderRead(reader);
        }
    }

    if (ret != 0)
    {
        xmlErrorPtr err = xmlGetLastError();

        TRACE("%s: failed to parse in line %d, col %d. Error %d: %s\n",
            err->file,
            err->line,
            err->int2,
            err->code,
            err->message);
    }

    xmlFreeTextReader(reader);
    xmlCleanupParser();     

    return 0;
}

Еще одна попытка была использовать функцию xmlTextReaderSchemaValidate(reader, "example.xsd"); вместо создания xmlSchemaNewValidCtxt, но затем происходит сбой программы при первом вызове xmlTextReaderRead.

Итак, как правильно выполняется проверка, чтобы информация об ошибках включала номера строк и столбцов?

1 Ответ

0 голосов
/ 10 января 2019

Итак, ваши вопросы заставили меня задуматься, и когда я заглянул в документацию libxml2 ,

Structure xmlError
struct _xmlError {
    int domain  : What part of the library raised this er
    int code    : The error code, e.g. an xmlParserError
    char *  message : human-readable informative error messag
    xmlErrorLevel   level   : how consequent is the error
    char *  file    : the filename
    int line    : the line number if available
    char *  str1    : extra string information
    char *  str2    : extra string information
    char *  str3    : extra string information
    int int1    : extra number information
    int int2    : error column # or 0 if N/A (todo: renam
    void *  ctxt    : the parser context if available
    void *  node    : the node in the tree
}

, где мы можем ясно видеть, что xmlErrorPtr, который возвращается функцией xmlGetLastError(), четко содержит информацию о имени файла, номере строки и номере столбца.

    char *  file    : the filename
    int line    : the line number if available
    ...
    int int2    : error column

Итак, чтобы проверить, было ли это возможно или нет, вот код, который я использовал (в основном ваш код с небольшими изменениями, чтобы он работал в моей системе):

#include <stdio.h>
#include <stdbool.h>
#include <libxml/xmlreader.h>
#include <libxml/encoding.h>
#include <libxml/xmlwriter.h>

static void schemaParseErrorHandler(void *arg, xmlErrorPtr error)
{
    fprintf(stderr, "Error at line %d, column %d\n%s", error->line, error->int2, error->message);
    *((bool*)arg) = true;
}

int main( int argc, char **argv )
{
    xmlInitParser();
    xmlSchemaPtr schema = NULL;
    xmlSchemaParserCtxtPtr schema_parser_ctxt = NULL;
    int has_schema_errors = 0;
    int ret = -1;
    xmlSchemaValidCtxtPtr valid_ctxt = NULL;
    if ((schema_parser_ctxt = xmlSchemaNewParserCtxt("/home/junglefox/shiporder.xsd")))
    {
        schema = xmlSchemaParse(schema_parser_ctxt);
        xmlSchemaFreeParserCtxt(schema_parser_ctxt);
        if (schema)
        {
            valid_ctxt = xmlSchemaNewValidCtxt(schema);
        }
    }
    xmlTextReaderPtr reader = NULL;
    const char* filename = "/home/junglefox/shiporder.xml";
    reader = xmlReaderForFile(filename, /*RPCXmlStream::STD_ENCODING,*/ NULL, 0);

    if (reader != NULL)
    {
        if (valid_ctxt)
        {
            xmlTextReaderSchemaValidateCtxt(reader, valid_ctxt, 0);
            xmlSchemaSetValidStructuredErrors(valid_ctxt, schemaParseErrorHandler, &has_schema_errors);
        }
        ret = xmlTextReaderRead(reader);
        while (ret == 1 && !has_schema_errors)
        {
            //... procesing informations
            ret = xmlTextReaderRead(reader);
        }
    }

    if (ret != 0)
    {
        xmlErrorPtr err = xmlGetLastError();
        fprintf(stdout, "%s: failed to parse in line %d, col %d. Error %d: %s\n",
                err->file,
                err->line,
                err->int2,
                err->code,
                err->message);
    }
    xmlFreeTextReader(reader);
    xmlCleanupParser();
    return 0;
}

где shiporder.xml и shiporder.xsd , использованные в этой программе, были скопированы из url и сохранены локально.

Я скомпилировал и запустил код следующим образом:

junglefox@ubuntu:~$ gcc -o test_xsd main.c -I/usr/include/libxml2/ -lxml2 -L/usr/lib/x86_64-linux-gnu/
junglefox@ubuntu:~$ ./test_xsd
junglefox@ubuntu:~$

На этот раз на выходе ничего не было. Как и должно быть, так как ошибок не было.

Если, однако, теперь я делаю преднамеренную ошибку в файле shiporder.xml , как показано ниже:

  • Вот частичный -сниппет из багги shiporder.xml :

    <?xml version="1.0" encoding="UTF-8"?> ... <item> <title>Hide your heart</title> <quantity>1</quantity> price>9.90</price> </item> </shiporder>

  • Обратите внимание на пропавших без вести < до price!

Теперь я снова запускаю программу,

junglefox@ubuntu:~$ ./test_xsd 
Error at line 22, column 0
Element 'item': Character content other than whitespace is not allowed because the content type is 'element-only'.

который отвечает на ваш вопрос (ы):

При моем подходе я получаю ошибки проверки в функции schemaParseErrorHandler, но без номеров строк или столбцов. Как я могу получить эту информацию?

и

Итак, как правильно сделать проверку, чтобы информация об ошибках включала номера строк и столбцов?

, поскольку в выводе четко отображаются строки с номером 22 * ​​1066 * и столбец 0 , где произошел неожиданный empty space из-за отсутствия <.

...