Geting xml data using expat XML parser

I managed to make out well. But now I have problems getting the values โ€‹โ€‹that I need. I can get the element and attributes. But can not get the value. I would like to get the frame value in this xml, this is 20.

/* 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' 
+4
source share
2 answers

Expat is pretty tricky. expat is better when you are only interested in the structure, not the content of the elements. Why not use libxml instead? What are your reasons for using an even expression parser like expat rather than a tree?

In any case, the way to do this is to install a character data handler. Here is an example based on your code:

 #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; } 
+11
source

โ€œValueโ€ 20 is the character data โ€œ20โ€ in an element whose tag is โ€œelementโ€ and whose name attribute is โ€œframeโ€.

To receive personal data events, register a callback using the XML_SetCharacterDataHandler function.

This callback will receive character data. The parser can split character data - usually for processing to the end of the buffer or for entities (therefore for foo&amp;bar your handler will receive three calls - "foo", "&" and "bar"), so you have to insert parts of the string again if you need all the data.

You know, when you have all the character data inside a node, when you get the next element, start or close the callback.

When you have all the data for a symbol, you can process it.

A separate example is simplified from your code:

 #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; } 
+11
source

All Articles