使用 C 中的 Expat 库解析 XML 文件

1 c xml

我搜索了如何使用Expat库解析 XML 文件,但发现对初学者没有任何用处。

我想要的只是从配置文件中读取三个数字 6、7 和 8。

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
    <board_height> 6 </board_height>
    <board_width> 7 </board_width>
    <maximum_highscores> 8 </maximum_highscores>    
</Configuration>
Run Code Online (Sandbox Code Playgroud)

Jac*_*din 5

Expat是一个流式XML 解析器。因此,它会分块解析文档,并且由您(程序员)在解析时(而不是之后)维护状态、监视进度并捕获所需的数据。

您需要构建三个主要处理程序:

  1. XML_StartElementHandler
  2. XML_EndElementHandler
  3. XML_CharacterDataHandler

您将在 中找到这些函数的函数签名expat.h。第一个函数在找到起始标签 ( <tag>) 时调用,第二个函数在找到结束标签 ( </tag>) 时调用,第三个函数捕获标签之间的文本。这是一种基本但快速的解析技术。

以下是使用 Expat 2.1 的概念证明:

#include <expat.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#ifdef XML_LARGE_SIZE
#if defined(XML_USE_MSC_EXTENSIONS) && _MSC_VER < 1400
#define XML_FMT_INT_MOD "I64"
#else
#define XML_FMT_INT_MOD "ll"
#endif
#else
#define XML_FMT_INT_MOD "l"
#endif

struct setting {
    const char *key;
    char *value;
} config[] = {
    {"board_height", NULL}, {"board_width", NULL}, {"maximum_highscores", NULL}
};

struct setting *current_setting;

int
key_cmp(void const *ld, void const *rd)
{
    struct setting const *const l = ld;
    struct setting const *const r = rd;
    return strcmp(l->key, r->key);
}

void XMLCALL
handler(void *userData, const XML_Char *s, int len)
{
    if(len == 0){
        return;
    }

    if(!current_setting){
        return;
    }

    char *value = malloc((len+1) * sizeof(XML_Char));
    strncpy(value, s, len);
    current_setting->value = value;
}

static void XMLCALL
startElement(void *userData, const char *name, const char **atts)
{
    struct setting key = { .key = name };
    current_setting = bsearch(&key, config, sizeof(config)/sizeof(config[0]), sizeof(config[0]), key_cmp);
}

static void XMLCALL
endElement(void *userData, const char *name)
{
    current_setting = NULL;
}

int
main(int argc, char *argv[])
{
    char buf[BUFSIZ];

    XML_Parser parser = XML_ParserCreate(NULL);

    int done;
    int depth = 0;

    XML_SetUserData(parser, &depth);
    XML_SetElementHandler(parser, startElement, endElement);
    XML_SetCharacterDataHandler(parser, handler);

    FILE *fp = fopen("config.xml", "r");

    do {
        int len = (int)fread(buf, 1, sizeof(buf), fp);
        done = len < sizeof(buf);
        if (XML_Parse(parser, buf, len, done) == XML_STATUS_ERROR) {
            fprintf(stderr,
                    "%s at line %" XML_FMT_INT_MOD "u\n",
                    XML_ErrorString(XML_GetErrorCode(parser)),
                    XML_GetCurrentLineNumber(parser));
            return 1;
        }
    } while (!done);

    XML_ParserFree(parser);

    int i;
    for (i = 0; i < (sizeof(config)/sizeof(config[0])); i++) {
        struct setting current = config[i];
        printf("%s: %s\n", current.key, current.value);
        free(current.value);
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

该程序打开一个文件config.xml进行读取,设置适当的 Expat 处理程序,并复制它找到的“值”字符串(假设键是 XML 标记)。

提供的代码只是一个示例。我不是专业的 C 程序员。