XML CharacterDataHandler回调被多次调用unpextedly

时间:2017-02-08 23:49:02

标签: c xml expat-parser

我正在学习libexpat。我使用API​​拼凑了这个例子以获得基本的熟悉度:

守则

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

void start(void* userData, const char* name, const char* argv[])
{
  std::cout << "name: " << name << std::endl;

  int i = 0;

  while (argv[i])
  {
    std::cout << "argv[" << i << "] == " << argv[i++] << std::endl;
  }
}

void end(void* userData, const char* name)
{
}

void value(void* userData, const char* val, int len)
{
  char str[len+1];
  strncpy(str, val, len);
  str[len] = '\0';

  std::cout << "value: " << str << std::endl;
}

int main(int argc, char* argv[], char* envz[])
{
  XML_Parser parser = XML_ParserCreate(NULL);
  XML_SetElementHandler(parser, start, end);
  XML_SetCharacterDataHandler(parser, value);

  int bytesRead = 0;
  char val[1024] = {};
  FILE* fp = fopen("./catalog.xml", "r");
  std::cout << "fp == 0x" << (void*)fp << std::endl;

  do
  {
    bytesRead = fread(val, 1, sizeof(val), fp);
    std::cout << "In while loop bytesRead==" << bytesRead << std::endl;

    if (0 == XML_Parse(parser, val, bytesRead, (bytesRead < sizeof(val))))
    {
      break;
    }
  }
  while (1);

  XML_ParserFree(parser);
  std::cout << __FUNCTION__ << " end" << std::endl;

  return 0;
}

的catalog.xml

<CATALOG>
    <CD key1="value1" key2="value2">
        <TITLE>Empire Burlesque</TITLE>
        <ARTIST>Bob Dylan</ARTIST>
        <YEAR>1995</YEAR>
    </CD>
</CATALOG>

生成文件

xml: xml.o
        g++ xml.o -lexpat -o xml

xml.o: main.cpp Makefile
        g++ -g -c main.cpp -o xml.o

输出

fp == 0x0x22beb50
In while loop bytesRead==148
name: CATALOG
value: 

value:     
name: CD
argv[1] == key1
argv[2] == value1
argv[3] == key2
argv[4] == value2
value: 

value: 
name: TITLE
value: Empire Burlesque
value: 

value: 
name: ARTIST
value: Bob Dylan
value: 

value: 
name: YEAR
value: 1995
value: 

value:     
value: 

In while loop bytesRead==0
main end

问题

从输出中看来,我为XML_SetCharacterDataHandler()安装的回调被CATALOG,CD,TITLE和ARTIST xml标签调用两次,然后YEAR标签多次调用 - 有人可以解释这个行为?从注意到的catalog.xml,我不清楚为什么(或将来)有多个值与任何XML标签相关联。

谢谢。

引用

根据上述示例代码,归功于this site

1 个答案:

答案 0 :(得分:1)

expat解析器可能将文本节点拆分为对字符数据处理程序的多次调用。要正确处理文本节点,您必须在多个调用上累积文本,并在收到包含标记的“结束”事件时对其进行处理。

一般来说,即使是在不同的解析器和不同的语言中也是如此 - 即在Java中也是如此。

例如参见http://marcomaggi.github.io/docs/expat.html#using-comm

  

与XML解析器的任何面向事件的接口的常见首次错误是期望通过对字符数据处理程序的单个调用来报告元素中包含的所有文本。与许多其他XML解析器一样,Expat将这些数据报告为一系列调用;在完成不同的回调之前,无法知道何时到达序列的结尾。

同样来自the expat documentation

  

没有标记的单个连续文本块仍可能导致对此处理程序的一系列调用。换句话说,如果您在文本中搜索模式,则可能会分配对此处理程序的调用。