Thread: simple question XML parser C

  1. #16
    Registered User
    Join Date
    Jul 2011
    Posts
    12
    Quote Originally Posted by Salem View Post
    This is your code, with a few additions
    - a character handler
    - showing how to pass user data around, to record bits of information and state as we go.

    Code:
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <expat.h>
    
    #if defined(__amigaos__) && defined(__USE_INLINE__)
    #include <proto/expat.h>
    #endif
    
    #ifdef XML_LARGE_SIZE
    #if defined(XML_USE_MSC_EXTENSIONS) && _MSC_VER < 1400
    #define XML_FMT_INT_MOD "I64"
    #else
    #define XML_FMT_INT_MOD "ll"
    #endif
    #else
    #define XML_FMT_INT_MOD "l"
    #endif
    
    #define BUFFSIZE        8192
    
    char Buff[BUFFSIZE];
    
    int Depth;
    
    typedef enum {
      S_NONE,
      S_IFNAME,
      S_PROTO,
      S_IPADDR,
      S_NETMASK,
    } state_et;
    
    typedef struct {
      state_et  state;
      char  interface[100];
      char  ifname[100];
      char  proto[100];
      char  ipaddr[100];
      char  netmask[100];
    } info_st;
    
    static void XMLCALL
    chardata(void *userData, const XML_Char *s, int len)
    {
      info_st   *info = userData;
      switch ( info->state ) {
        case S_IFNAME:
          strncpy(info->ifname,s,len);
          info->ifname[len] = '\0';
          break;
        case S_PROTO:
          strncpy(info->proto,s,len);
          info->proto[len] = '\0';
          break;
        case S_IPADDR:
          strncpy(info->ipaddr,s,len);
          info->ipaddr[len] = '\0';
          break;
        case S_NETMASK:
          strncpy(info->netmask,s,len);
          info->netmask[len] = '\0';
          break;
      }
      info->state = S_NONE;
    //  printf(">-%.*s-<",len,s);
    }
    
    static void XMLCALL
    start(void *data, const char *el, const char **attr)
    {
      info_st   *info = data;
      int i;
    
      {
        char temp[100];
        if ( sscanf( el, "config_interface_%s", temp) == 1 ) {
          strcpy(info->interface,temp);
        }
        if ( strcmp(el,"ifname")==0) info->state = S_IFNAME;
        if ( strcmp(el,"proto")==0) info->state = S_PROTO;
        if ( strcmp(el,"ipaddr")==0) info->state = S_IPADDR;
        if ( strcmp(el,"netmask")==0) info->state = S_NETMASK;
      }
      for (i = 0; i < Depth; i++)
        printf("  ", data);
    
      printf("%s", el);
    
      for (i = 0; attr[i]; i += 2) {
        printf(" %s='%s'", attr[i], attr[i + 1]);
      }
    
      printf("\n");
      Depth++;
    }
    
    static void XMLCALL
    end(void *data, const char *el)
    {
      info_st   *info = data;
      {
        char temp[100];
        if ( sscanf( el, "config_interface_%s", temp) == 1 ) {
          printf("DATA=%s %s %s %s %s\n",
                 info->interface,
                 info->ifname,
                 info->proto,
                 info->ipaddr,
                 info->netmask);
        }
      }
      Depth--;
    }
    
    int
    main(int argc, char *argv[])
    {
      info_st   info = { 0 };
      XML_Parser p = XML_ParserCreate(NULL);
      if (! p) {
        fprintf(stderr, "Couldn't allocate memory for parser\n");
        exit(-1);
      }
    
      XML_SetElementHandler(p, start, end);
      XML_SetCharacterDataHandler(p,chardata);
      XML_SetUserData(p, &info);
    
      for (;;) {
        int done;
        int len;
    
        len = (int)fread(Buff, 1, BUFFSIZE, stdin);
        if (ferror(stdin)) {
          fprintf(stderr, "Read error\n");
          exit(-1);
        }
        done = feof(stdin);
    
        if (XML_Parse(p, Buff, len, done) == XML_STATUS_ERROR) {
          fprintf(stderr, "Parse error at line %" XML_FMT_INT_MOD "u:\n%s\n",
                  XML_GetCurrentLineNumber(p),
                  XML_ErrorString(XML_GetErrorCode(p)));
          exit(-1);
        }
    
        if (done)
          break;
      }
      XML_ParserFree(p);
      return 0;
    }
    The extra information printed looks like this
    DATA=loopback lo static 127.0.0.1 255.0.0.0
    DATA=lan eth0 static 192.168.1.1 255.255.255.0
    DATA=wifi eth0 static 192.168.2.1 255.255.255.0
    Could I ask another question please?Thanks!
    If I just want to parse the contents of the element Network, what should I do? I tried configure out the XML_setelementhandler, but it dosen't work... So Could you please take a few minutes to answer the question please? Thanks!

  2. #17
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    > If I just want to parse the contents of the element Network, what should I do?
    In the start() function, you add
    Code:
    if ( strcmp(el,"network") ) info->parsingNetwork = true;
    In the end function, you add
    Code:
    if ( strcmp(el,"network") ) {
        info->parsingNetwork = true;
        info->done = true;
    }
    If parsingNetwork is true, then you do the other bits.

    If done becomes true, then you basically stop doing anything at all in start()

    Or perhaps there is some other API you can call from the end() handler to indicate that parsing has been completed.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #18
    Registered User
    Join Date
    Jul 2011
    Posts
    12
    Quote Originally Posted by Salem View Post
    > If I just want to parse the contents of the element Network, what should I do?
    In the start() function, you add
    Code:
    if ( strcmp(el,"network") ) info->parsingNetwork = true;
    In the end function, you add
    Code:
    if ( strcmp(el,"network") ) {
        info->parsingNetwork = true;
        info->done = true;
    }
    If parsingNetwork is true, then you do the other bits.

    If done becomes true, then you basically stop doing anything at all in start()

    Or perhaps there is some other API you can call from the end() handler to indicate that parsing has been completed.
    Thanks for your reply, if I still have questions, I'll ask it after. Thanks a lot!

  4. #19
    Registered User
    Join Date
    Jul 2011
    Posts
    12
    Quote Originally Posted by Salem View Post
    > If I just want to parse the contents of the element Network, what should I do?
    In the start() function, you add
    Code:
    if ( strcmp(el,"network") ) info->parsingNetwork = true;
    In the end function, you add
    Code:
    if ( strcmp(el,"network") ) {
        info->parsingNetwork = true;
        info->done = true;
    }
    If parsingNetwork is true, then you do the other bits.

    If done becomes true, then you basically stop doing anything at all in start()

    Or perhaps there is some other API you can call from the end() handler to indicate that parsing has been completed.
    That's the new code I've wrote, but there is a problem of Info, I tried to configure it out, but It saids info is redefined... so I post the code, and I let you remind me~ Thanks!
    Code:
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <expat.h>
    #include <stdbool.h>
    
    #define bool _Bool
    #define false 0
    #define true 1
    #define __bool_true_false_are_defined 1
    
    #if defined(__amigaos__) && defined(__USE_INLINE__)
    #include <proto/expat.h>
    #endif
    
    #ifdef XML_LARGE_SIZE
    #if defined(XML_USE_MSC_EXTENSIONS) && _MSC_VER < 1400
    #define XML_FMT_INT_MOD "I64"
    #else
    #define XML_FMT_INT_MOD "ll"
    #endif
    #else
    #define XML_FMT_INT_MOD "l"
    #endif
    
    #define BUFFSIZE        8192
    
    char Buff[BUFFSIZE];
    
    int Depth;
    
    typedef enum {
      S_NONE,
      S_IFNAME,
      S_PROTO,
      S_IPADDR,
      S_NETMASK,
    } state_et;
    
    typedef struct {
      state_et  state;
      char  interface[100];
      char  ifname[100];
      char  proto[100];
      char  ipaddr[100];
      char  netmask[100];
      bool  parsingNetwork ;
      bool  done;
    } info_st;
    
    static void XMLCALL
    chardata(void *userData, const XML_Char *s, int len)
    {
      info_st   *info = userData;
      switch ( info->state ) {
        case S_IFNAME:
          strncpy(info->ifname,s,len);
          info->ifname[len] = '\0';
          break;
        case S_PROTO:
          strncpy(info->proto,s,len);
          info->proto[len] = '\0';
          break;
        case S_IPADDR:
          strncpy(info->ipaddr,s,len);
          info->ipaddr[len] = '\0';
          break;
        case S_NETMASK:
          strncpy(info->netmask,s,len);
          info->netmask[len] = '\0';
          break;
      }
      info->state = S_NONE;
    //  printf(">-%.*s-<",len,s);
    }
    
    static void XMLCALL
    start(void *data, const char *el, const char **attr)
    { 
      info_st *info = data;//加上这句
      {
        char temp[100];
        if ( sscanf( el, "config_interface_%s", temp) == 1 ) {
          strcpy(info->interface,temp);
        }
        if ( strcmp(el,"ifname")==0) info->state = S_IFNAME;
        if ( strcmp(el,"proto")==0) info->state = S_PROTO;
        if ( strcmp(el,"ipaddr")==0) info->state = S_IPADDR;
        if ( strcmp(el,"netmask")==0) info->state = S_NETMASK;
      }
      for (i = 0; i < Depth; i++)
        printf("  ", data);//这句话是不是漏了个通配符???
     
      if ( strcmp(el,"network") ) info->parsingNetwork = true;
      //info_st   *info = data;
      int i;
    
      printf("%s", el);
    
      for (i = 0; attr[i]; i += 2) {
        printf(" %s='%s'", attr[i], attr[i + 1]);
      }
    
      printf("\n");
      Depth++;
     
       
    }
    
    static void XMLCALL
    end(void *data, const char *el)
    {
     info_st info = data;
      if ( strcmp(el,"network") )
     {
        info->parsingNetwork = true;
        info->done = true;}
    
      //info_st   *info = data;
      {
        char temp[100];
        if ( sscanf( el, "config_interface_%s", temp) == 1 ) {
          printf("DATA=%s %s %s %s %s\n",
                 info->interface,
                 info->ifname,
                 info->proto,
                 info->ipaddr,
                 info->netmask);
        }
      }
      Depth--;
      
      
    }
    
    
    int
    main(int argc, char *argv[])
    {
      info_st   *info = data;
      XML_Parser p = XML_ParserCreate(NULL);
      if (! p) {
        fprintf(stderr, "Couldn't allocate memory for parser\n");
        exit(-1);
      }
    
      XML_SetElementHandler(p, start, end);
      XML_SetCharacterDataHandler(p,chardata);
      XML_SetUserData(p, &info);
    
      for (;;) {
        int done;
        int len;
    
        len = (int)fread(Buff, 1, BUFFSIZE, stdin);
        if (ferror(stdin)) {
          fprintf(stderr, "Read error\n");
          exit(-1);
        }
        done = feof(stdin);
    
        if (XML_Parse(p, Buff, len, done) == XML_STATUS_ERROR) {
          fprintf(stderr, "Parse error at line %" XML_FMT_INT_MOD "u:\n%s\n",
                  XML_GetCurrentLineNumber(p),
                  XML_ErrorString(XML_GetErrorCode(p)));
          exit(-1);
        }
    
        if (done)
          break;
      }
      XML_ParserFree(p);
      return 0;
    }

  5. #20
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    The diffs between your code, and the thing I posted 2 weeks ago.
    Code:
    $ diff -b xx1.txt xx2.txt 
    4a5,10
    > #include <stdbool.h>
    > 
    > #define bool _Bool
    > #define false 0
    > #define true 1
    > #define __bool_true_false_are_defined 1
    40a47,48
    >   bool  parsingNetwork ;
    >   bool  done;
    72,74c80
    <   info_st   *info = data;
    <   int i;
    < 
    ---
    >   info_st *info = data;//加上这句
    86c92,96
    <     printf("  ", data);
    ---
    >     printf("  ", data);//这句话是不是漏了个通配符???
    >  
    >   if ( strcmp(el,"network") ) info->parsingNetwork = true;
    >   //info_st   *info = data;
    >   int i;
    95a106,107
    >  
    >    
    101c113,119
    <   info_st   *info = data;
    ---
    >  info_st info = data;
    >   if ( strcmp(el,"network") )
    >  {
    >     info->parsingNetwork = true;
    >     info->done = true;}
    > 
    >   //info_st   *info = data;
    113a132,133
    >   
    >   
    115a136
    > 
    119c140
    <   info_st   info = { 0 };
    ---
    >   info_st   *info = data;
    The bits in blue are what you need to change back to the original.

    The 'info' in main has to be a real structure, not just a pointer.
    EVERY callback function gets a pointer to this structure instance.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. A simple C parser problem
    By iZephyr in forum C Programming
    Replies: 1
    Last Post: 01-06-2011, 12:01 AM
  2. Simple parser
    By lruc in forum C Programming
    Replies: 5
    Last Post: 11-19-2009, 12:19 AM
  3. Simple Parser Program
    By ChJees in forum C++ Programming
    Replies: 4
    Last Post: 07-19-2007, 03:21 AM
  4. very simple html parser
    By chad101 in forum C++ Programming
    Replies: 1
    Last Post: 07-26-2006, 07:18 PM
  5. question about parser??
    By newbie02 in forum C++ Programming
    Replies: 1
    Last Post: 07-30-2003, 09:17 AM