2009-03-04 99 views
4

我設法解析ok。但現在我無法獲得我需要的值 。我可以獲取元素和屬性。但無法獲得價值。 我想獲得在該XML框架的價值是20使用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」 malloc的大小應爲長度+ 1。 – Hyndrix 2014-02-03 17:37:25

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; 
}