【问题标题】:libxml2 get xsd validation errorslibxml2 获取 xsd 验证错误
【发布时间】:2019-01-10 08:56:38
【问题描述】:

我正在使用 xmlTextReader 来处理大型 xml 文件。现在我需要根据 xsd 模式验证实例。 libxml2 的 api 有点混乱,这是怎么做的。

使用我的方法,我在 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 时崩溃。

那么如何正确进行验证,使错误信息包括行号和列号?

【问题讨论】:

    标签: c validation xsd libxml2


    【解决方案1】:

    所以,当我查看libxml2 documentation 时,你的问题让我思考,

    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
    }
    

    我们可以清楚地看到,xmlGetLastError() 函数返回的xmlErrorPtr 清楚地包含有关文件名和行号和列号的信息。

        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.xmlshiporder.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 文件中故意出错,如下所示:

    • 这里是 partial-sn-p 来自 buggy 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之前缺少的&lt;

    现在我再次运行程序,

    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 行第 0 列,其中由于缺少&lt; 而出现了意外的empty space

    【讨论】:

    • 有趣的是,我没有得到行号或列号(它总是 0)。也许我的 libxml2 版本已经过时了。我用的是 2.7.8 版本,你的是哪个版本的?
    • 还有 2.7.8 lrwxrwxrwx 1 root root 16 Oct 10 2015 /usr/lib/libxml2.so -&gt; libxml2.so.2.7.8
    • 您是否使用我的代码(有一些小改动)和我的示例 *.xsd 和 *.xml 文件进行了测试?
    • 是的,我拿走了你的代码和文件,我得到了正确的解析器消息,但是 err->line 和 err->int2 是 0。
    • 那么它不可能与代码有关,因为代码有效(至少在我的系统上)。顺便说一句,我在 Ubuntu 18.04 上运行并使用 gcc 7.3.0 编译。 您在shiporder.xml 文件中更改了什么以产生错误?,或者您可以以某种方式共享修改后的shiporder.xml。也许我可以在我这边重复测试,如果它显示相同或不同。
    猜你喜欢
    • 2016-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多