2009-03-04 12 views
4

Мне удалось разобрать ОК. Но теперь мне не удается получить значения , которые мне нужны. Я могу получить элемент и атрибуты. Но не может получить значения. Я хотел бы получить значение кадра в этом XML является 20.Geting xml данные с использованием XML-парсера expat

/* track the current level in the xml tree */ 
static int depth = 0; 
/* first when start element is encountered */ 
void start_element(void *data, const char *element, const char **attribute) 
{ 
int i; 

for(i = 0; i < depth; i++) 
{ 
    printf(" "); 
} 

printf("%s", element); 

for(i = 0; attribute[i]; i += 2) 
{ 
    printf(" %s= '%s'", attribute[i], attribute[i + 1]); 
} 

printf("\n"); 
depth++; 
} 

/* decrement the current level of the tree */ 
void end_element(void *data, const char *el) 
{ 
depth--; 
} 
int parse_xml(char *buff, size_t buff_size) 
{ 
    FILE *fp; 
    fp = fopen("start_indication.xml", "r"); 
    if(fp == NULL) 
    { 
    printf("Failed to open file\n"); 
    return 1; 
    } 

    XML_Parser parser = XML_ParserCreate(NULL); 
    int done; 
    XML_SetElementHandler(parser, start_element, end_element); 

    memset(buff, 0, buff_size); 
    printf("strlen(buff) before parsing: %d\n", strlen(buff)); 

    size_t file_size = 0; 
    file_size = fread(buff, sizeof(char), buff_size, fp); 

    /* parse the xml */ 
    if(XML_Parse(parser, buff, strlen(buff), XML_TRUE) == XML_STATUS_ERROR) 
    { 
     printf("Error: %s\n", XML_ErrorString(XML_GetErrorCode(parser))); 
    } 

    fclose(fp); 
    XML_ParserFree(parser); 

    return 0; 
} 



<data> 
    <header length="4"> 
      <item name="time" type="time">16</item> 
      <item name="ref" type="string">3843747</item> 
      <item name="port" type="int16">0</item> 
      <item name="frame" type="int16">20</item> 
    </header> 
</data> 

Output from parsing 


Element: data 
Element: header length= '4' 
Element: item name= 'time' type= 'time' 
Element: item name= 'ref' type= 'string' 
Element: item name= 'port' type= 'int16' 
Element: item name= 'frame' type= 'int16' 

ответ

11

Это довольно трудно с эмигрантом. expat лучше, когда вас интересует только структура, а не содержание элементов. Почему бы не использовать libxml вместо этого? Каковы ваши причины использовать парсер, основанный на четности, например, expat, а не на основе дерева?

В любом случае, способ сделать это - установить обработчик символов. Вот пример, основанный на коде:

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

#define BUFFER_SIZE 100000 

/* track the current level in the xml tree */ 
static int  depth = 0; 

static char *last_content; 

/* first when start element is encountered */ 
void 
start_element(void *data, const char *element, const char **attribute) 
{ 
    int    i; 

    for (i = 0; i < depth; i++) { 
     printf(" "); 
    } 

    printf("%s", element); 

    for (i = 0; attribute[i]; i += 2) { 
     printf(" %s= '%s'", attribute[i], attribute[i + 1]); 
    } 

    printf("\n"); 
    depth++; 
} 

/* decrement the current level of the tree */ 
void 
end_element(void *data, const char *el) 
{ 
    int    i; 
    for (i = 0; i < depth; i++) { 
     printf(" "); 
    } 
    printf("Content of element %s was \"%s\"\n", el, last_content); 
    depth--; 
} 

void 
handle_data(void *data, const char *content, int length) 
{ 
    char   *tmp = malloc(length); 
    strncpy(tmp, content, length); 
    tmp[length] = '\0'; 
    data = (void *) tmp; 
    last_content = tmp;   /* TODO: concatenate the text nodes? */ 
} 

int 
parse_xml(char *buff, size_t buff_size) 
{ 
    FILE   *fp; 
    fp = fopen("start_indication.xml", "r"); 
    if (fp == NULL) { 
     printf("Failed to open file\n"); 
     return 1; 
    } 

    XML_Parser  parser = XML_ParserCreate(NULL); 
    XML_SetElementHandler(parser, start_element, end_element); 
    XML_SetCharacterDataHandler(parser, handle_data); 

    memset(buff, 0, buff_size); 
    printf("strlen(buff) before parsing: %d\n", strlen(buff)); 

    size_t   file_size = 0; 
    file_size = fread(buff, sizeof(char), buff_size, fp); 

    /* parse the xml */ 
    if (XML_Parse(parser, buff, strlen(buff), XML_TRUE) == XML_STATUS_ERROR) { 
     printf("Error: %s\n", XML_ErrorString(XML_GetErrorCode(parser))); 
    } 

    fclose(fp); 
    XML_ParserFree(parser); 

    return 0; 
} 

int 
main(int argc, char **argv) 
{ 
    int    result; 
    char   buffer[BUFFER_SIZE]; 
    result = parse_xml(buffer, BUFFER_SIZE); 
    printf("Result is %i\n", result); 
    return 0; 
} 
+1

В методе «handle_data» размер таНос должна быть длина + 1. – Hyndrix

+0

'handle_data' необходимо объединить текст, поскольку данные элемента могут быть разделены на несколько вызовов. Цитата: [http://www.xml.com/pub/a/1999/09/expat/reference.html#chardatahandler] _В отдельном блоке смежного текста без разметки все равно может появиться последовательность вызовов для этого обработчик. Другими словами, если вы ищете шаблон в тексте, он может быть разделен на вызовы этого обработчика. _ Также вам не нужно 'data = (void *) tmp;' потому что вы используете глобальную переменную для передачи данных. – FractalSpace

11

«ценность» 20 является символом данных «20» в элементе, чей тэг «элемент» и чье имя атрибута «кадр».

Для получения событий с символьными данными зарегистрируйте обратный вызов с помощью функции XML_SetCharacterDataHandler.

Этот обратный вызов получит данные символа. Парсер может разделить персональные данные - как правило, для обработки доступа к концу буфера или для объектов (поэтому для foo&amp;bar ваш обработчик получит три вызова - «foo», «&» и «bar»), поэтому вам нужно вставить если вам нужны все данные.

Вы знаете, когда у вас есть все данные символа внутри узла, когда вы получаете следующий элемент, начинаете или закрываете обратный вызов.

Когда у вас есть все данные символа, вы можете его обработать.

Автономный пример упрощен из кода:

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

static const char* xml = 
    "<data>\n"\ 
    " <header length=\"4\">\n"\ 
    "   <item name=\"time\" type=\"time\">16</item>\n"\ 
    "   <item name=\"ref\" type=\"string\">3843747</item>\n"\ 
    "   <item name=\"port\" type=\"int16\">0</item>\n"\ 
    "   <item name=\"frame\" type=\"int16\">20</item>\n"\ 
    " </header>\n"\ 
    "</data>\n"; 

void reset_char_data_buffer(); 
void process_char_data_buffer(); 
static bool grab_next_value; 

void start_element(void *data, const char *element, const char **attribute) { 
    process_char_data_buffer(); 
    reset_char_data_buffer(); 

    if (strcmp("item", element) == 0) { 
     size_t matched = 0; 

     for (size_t i = 0; attribute[i]; i += 2) { 
      if ((strcmp("name", attribute[i]) == 0) && (strcmp("frame", attribute[i+1]) == 0)) 
       ++matched; 

      if ((strcmp("type", attribute[i]) == 0) && (strcmp("int16", attribute[i+1]) == 0)) 
       ++matched; 
     } 

     if (matched == 2) { 
      printf("this is the element you are looking for\n"); 
      grab_next_value = true; 
     } 
    } 
} 

void end_element(void *data, const char *el) { 
    process_char_data_buffer(); 
    reset_char_data_buffer(); 
} 

static char char_data_buffer[1024]; 
static size_t offs; 
static bool overflow; 

void reset_char_data_buffer (void) { 
    offs = 0; 
    overflow = false; 
    grab_next_value = false; 
} 

// pastes parts of the node together 
void char_data (void *userData, const XML_Char *s, int len) { 
    if (!overflow) { 
     if (len + offs >= sizeof(char_data_buffer)) { 
      overflow = true; 
     } else { 
      memcpy(char_data_buffer + offs, s, len); 
      offs += len; 
     } 
    } 
} 

// if the element is the one we're after, convert the character data to 
// an integer value 
void process_char_data_buffer (void) { 
    if (offs > 0) { 
     char_data_buffer[ offs ] = '\0'; 

     printf("character data: %s\n", char_data_buffer); 

     if (grab_next_value) { 
      int value = atoi(char_data_buffer); 

      printf("the value is %d\n", value); 
     } 
    } 
} 

int main (void) { 
    XML_Parser parser = XML_ParserCreate(NULL); 

    XML_SetElementHandler(parser, start_element, end_element); 
    XML_SetCharacterDataHandler(parser, char_data); 

    reset_char_data_buffer(); 

    if (XML_Parse(parser, xml, strlen(xml), XML_TRUE) == XML_STATUS_ERROR) 
     printf("Error: %s\n", XML_ErrorString(XML_GetErrorCode(parser))); 

    XML_ParserFree(parser); 

    return 0; 
}