2009-03-04 17 views
4

Ich habe es geschafft, OK zu parsen. Aber jetzt habe ich Probleme, die Werte zu bekommen, die ich brauche. Ich kann das Element und die Attribute bekommen. Kann aber die Werte nicht bekommen. Ich möchte den Wert des Rahmens in diesem xml treten ist 20.XML-Daten mit Xml-Parser exportieren 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' 

Antwort

11

Es mit Expat ziemlich schwierig ist. Expat ist besser, wenn Sie nur an der Struktur, nicht am Inhalt der Elemente interessiert sind. Warum nicht stattdessen libxml verwenden? Was sind Ihre Gründe für die Verwendung eines even-basierten Parsers wie Expat statt eines Baum-basierten?

Wie auch immer, die Art, dies zu tun ist, einen Zeichendatenhandler zu setzen. Hier ist ein Beispiel, basierend auf Ihren 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; 
} 
+1

Bei dem Verfahren "handle_data" sollte die malloc Größe Länge + 1 sein. – Hyndrix

+0

'handle_data' muss Text verketten, da die Elementdaten in mehreren Aufrufen aufgeteilt werden können. Zitat: [http://www.xml.com/pub/a/1999/09/expat/reference.html#chardatahandler] _Ein einzelner Block von zusammenhängendem Text ohne Markup kann immer noch zu einer Folge von Aufrufen führen Handler. Mit anderen Worten, wenn Sie nach einem Muster im Text suchen, kann es auf Aufrufe dieses Handlers aufgeteilt werden. _ Sie brauchen auch nicht 'data = (void *) tmp;', weil Sie globale Variable verwenden, um Daten herumzugeben. – FractalSpace

11

Der ‚Wert‘ 20 ist die Zeichendaten „20“ in das Element, dessen Tag-Name ist „Element“, und dessen Name Attribut „Rahmen“.

Um Zeichendatenereignisse zu empfangen, registrieren Sie einen Rückruf mit der Funktion XML_SetCharacterDataHandler.

Dieser Rückruf empfängt die Zeichendaten. Der Parser kann Zeichendaten teilen - normalerweise, um das Ende eines Puffers zu erreichen, oder für Entitäten (also für foo&amp;bar erhält Ihr Handler drei Aufrufe - "foo", "&" und "bar"), also müssen Sie die einfügen string Teile wieder zusammen, wenn Sie die gesamten Daten benötigen.

Sie wissen, wann Sie alle Zeichendaten in einem Knoten haben, wenn Sie das nächste Element starten oder schließen Callback.

Wenn Sie alle Zeichendaten haben, können Sie sie verarbeiten.

Ein Stand-alone-Beispiel aus dem Code vereinfacht:

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