Question

J'ai réussi à analyser ok. Mais maintenant, j'ai du mal à comprendre les valeurs ce dont j'ai besoin. Je peux obtenir l'élément et les attributs. Mais ne peut pas obtenir les valeurs. Je voudrais obtenir la valeur de frame dans ce xml, il est 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'
Était-ce utile?

La solution

C'est assez difficile avec les expatriés. Expat est préférable lorsque vous ne vous intéressez qu'à la structure, pas au contenu des éléments. Pourquoi ne pas utiliser plutôt libxml ? Quelles sont vos raisons d'utiliser un analyseur syntaxique de type pair comme expat, plutôt qu'un arborescence?

Quoi qu’il en soit, la façon de le faire est de définir un gestionnaire de données de caractères. Voici un exemple, basé sur votre 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;
}

Autres conseils

La "valeur" 20 correspond aux données de caractère "20". dans l'élément dont le nom est "article" et dont l'attribut name est "frame".

Pour recevoir des événements de données de caractère, enregistrez un rappel avec le XML_SetCharacterDataHandler , fonction.

Ce rappel recevra les données de caractères. L'analyseur peut diviser des données de caractère - généralement pour gérer la fin d'une mémoire tampon ou pour des entités (donc pour foo & amp; bar , votre gestionnaire obtiendra trois appels - "foo", "& amp; ; "et"; "), vous devez donc recoller les parties de chaîne si vous avez besoin de l’ensemble des données.

Vous savez que lorsque vous avez toutes les données de caractère dans un nœud lorsque vous recevez le prochain élément start, callback ou close.

Lorsque vous avez toutes les données de caractères, vous pouvez les traiter.

Un exemple autonome simplifié à partir de votre 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;
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top