2009-03-04 14 views
4

私はokを解析することができました。しかし今、私が必要とする値 を得ることができません。要素と属性を取得できます。しかし値を得ることはできません。 私はそれはそれはexpatのでは極めて困難である20xmlパーサを使用して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

であるこのXMLでフレームの値を取得したいと思います。 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

は、malloc関数の大きさは、長さ+ 1であるべきです。 – Hyndrix

+0

'handle_data'は、要素データが複数の呼び出しで分割される可能性があるため、テキストを連結する必要があります。引用:[http://www.xml.com/pub/a/1999/09/expat/reference.html#chardatahandler] _マークアップのない連続したテキストの単一のブロックでも、この一連の呼び出しが行われることがありますハンドラ。言い換えると、テキスト内のパターンを検索している場合、このハンドラへの呼び出しで分割される可能性があります。 _ グローバル変数を使ってデータを渡すので、 'data =(void *)tmp;'は必要ありません。 – FractalSpace

11

「の値20」は、タグ名「アイテム」は、その名の属性「フレーム」である要素内の文字データ「20」です。

文字データイベントを受信するには、XML_SetCharacterDataHandler関数でコールバックを登録します。

このコールバックは文字データを受け取ります。パーサは、文字データを分割することができます。通常、バッファの最後に到達するか、エンティティに対して処理されます(foo&amp;barの場合、ハンドラは "foo"、 "&"、 "bar"の3つの呼び出しを受け取ります)。あなたがデータの全体を必要とするならば、もう一度一緒に弦のパーツを作りなさい。

次の要素の開始または終了のコールバックを受け取ったときに、ノード内にすべての文字データがあるとわかります。

すべての文字データがある場合は、それを処理できます。コードから簡略

スタンドアロン例:メソッド「引数にしてhandle_data」で

#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; 
} 
関連する問題