113498266Sopenharmony_ci/*************************************************************************** 213498266Sopenharmony_ci * _ _ ____ _ 313498266Sopenharmony_ci * Project ___| | | | _ \| | 413498266Sopenharmony_ci * / __| | | | |_) | | 513498266Sopenharmony_ci * | (__| |_| | _ <| |___ 613498266Sopenharmony_ci * \___|\___/|_| \_\_____| 713498266Sopenharmony_ci * 813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 913498266Sopenharmony_ci * 1013498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which 1113498266Sopenharmony_ci * you should have received as part of this distribution. The terms 1213498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html. 1313498266Sopenharmony_ci * 1413498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell 1513498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is 1613498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file. 1713498266Sopenharmony_ci * 1813498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 1913498266Sopenharmony_ci * KIND, either express or implied. 2013498266Sopenharmony_ci * 2113498266Sopenharmony_ci * SPDX-License-Identifier: curl 2213498266Sopenharmony_ci * 2313498266Sopenharmony_ci ***************************************************************************/ 2413498266Sopenharmony_ci/* <DESC> 2513498266Sopenharmony_ci * Stream-parse a document using the streaming Expat parser. 2613498266Sopenharmony_ci * </DESC> 2713498266Sopenharmony_ci */ 2813498266Sopenharmony_ci/* Written by David Strauss 2913498266Sopenharmony_ci * 3013498266Sopenharmony_ci * Expat => https://libexpat.github.io/ 3113498266Sopenharmony_ci * 3213498266Sopenharmony_ci * gcc -Wall -I/usr/local/include xmlstream.c -lcurl -lexpat -o xmlstream 3313498266Sopenharmony_ci * 3413498266Sopenharmony_ci */ 3513498266Sopenharmony_ci 3613498266Sopenharmony_ci#include <stdio.h> 3713498266Sopenharmony_ci#include <stdlib.h> 3813498266Sopenharmony_ci#include <string.h> 3913498266Sopenharmony_ci#include <assert.h> 4013498266Sopenharmony_ci 4113498266Sopenharmony_ci#include <expat.h> 4213498266Sopenharmony_ci#include <curl/curl.h> 4313498266Sopenharmony_ci 4413498266Sopenharmony_cistruct MemoryStruct { 4513498266Sopenharmony_ci char *memory; 4613498266Sopenharmony_ci size_t size; 4713498266Sopenharmony_ci}; 4813498266Sopenharmony_ci 4913498266Sopenharmony_cistruct ParserStruct { 5013498266Sopenharmony_ci int ok; 5113498266Sopenharmony_ci size_t tags; 5213498266Sopenharmony_ci size_t depth; 5313498266Sopenharmony_ci struct MemoryStruct characters; 5413498266Sopenharmony_ci}; 5513498266Sopenharmony_ci 5613498266Sopenharmony_cistatic void startElement(void *userData, const XML_Char *name, 5713498266Sopenharmony_ci const XML_Char **atts) 5813498266Sopenharmony_ci{ 5913498266Sopenharmony_ci struct ParserStruct *state = (struct ParserStruct *) userData; 6013498266Sopenharmony_ci state->tags++; 6113498266Sopenharmony_ci state->depth++; 6213498266Sopenharmony_ci 6313498266Sopenharmony_ci /* Get a clean slate for reading in character data. */ 6413498266Sopenharmony_ci free(state->characters.memory); 6513498266Sopenharmony_ci state->characters.memory = NULL; 6613498266Sopenharmony_ci state->characters.size = 0; 6713498266Sopenharmony_ci} 6813498266Sopenharmony_ci 6913498266Sopenharmony_cistatic void characterDataHandler(void *userData, const XML_Char *s, int len) 7013498266Sopenharmony_ci{ 7113498266Sopenharmony_ci struct ParserStruct *state = (struct ParserStruct *) userData; 7213498266Sopenharmony_ci struct MemoryStruct *mem = &state->characters; 7313498266Sopenharmony_ci 7413498266Sopenharmony_ci char *ptr = realloc(mem->memory, mem->size + len + 1); 7513498266Sopenharmony_ci if(!ptr) { 7613498266Sopenharmony_ci /* Out of memory. */ 7713498266Sopenharmony_ci fprintf(stderr, "Not enough memory (realloc returned NULL).\n"); 7813498266Sopenharmony_ci state->ok = 0; 7913498266Sopenharmony_ci return; 8013498266Sopenharmony_ci } 8113498266Sopenharmony_ci 8213498266Sopenharmony_ci mem->memory = ptr; 8313498266Sopenharmony_ci memcpy(&(mem->memory[mem->size]), s, len); 8413498266Sopenharmony_ci mem->size += len; 8513498266Sopenharmony_ci mem->memory[mem->size] = 0; 8613498266Sopenharmony_ci} 8713498266Sopenharmony_ci 8813498266Sopenharmony_cistatic void endElement(void *userData, const XML_Char *name) 8913498266Sopenharmony_ci{ 9013498266Sopenharmony_ci struct ParserStruct *state = (struct ParserStruct *) userData; 9113498266Sopenharmony_ci state->depth--; 9213498266Sopenharmony_ci 9313498266Sopenharmony_ci printf("%5lu %10lu %s\n", state->depth, state->characters.size, name); 9413498266Sopenharmony_ci} 9513498266Sopenharmony_ci 9613498266Sopenharmony_cistatic size_t parseStreamCallback(void *contents, size_t length, size_t nmemb, 9713498266Sopenharmony_ci void *userp) 9813498266Sopenharmony_ci{ 9913498266Sopenharmony_ci XML_Parser parser = (XML_Parser) userp; 10013498266Sopenharmony_ci size_t real_size = length * nmemb; 10113498266Sopenharmony_ci struct ParserStruct *state = (struct ParserStruct *) XML_GetUserData(parser); 10213498266Sopenharmony_ci 10313498266Sopenharmony_ci /* Only parse if we are not already in a failure state. */ 10413498266Sopenharmony_ci if(state->ok && XML_Parse(parser, contents, real_size, 0) == 0) { 10513498266Sopenharmony_ci int error_code = XML_GetErrorCode(parser); 10613498266Sopenharmony_ci fprintf(stderr, "Parsing response buffer of length %lu failed" 10713498266Sopenharmony_ci " with error code %d (%s).\n", 10813498266Sopenharmony_ci real_size, error_code, XML_ErrorString(error_code)); 10913498266Sopenharmony_ci state->ok = 0; 11013498266Sopenharmony_ci } 11113498266Sopenharmony_ci 11213498266Sopenharmony_ci return real_size; 11313498266Sopenharmony_ci} 11413498266Sopenharmony_ci 11513498266Sopenharmony_ciint main(void) 11613498266Sopenharmony_ci{ 11713498266Sopenharmony_ci CURL *curl_handle; 11813498266Sopenharmony_ci CURLcode res; 11913498266Sopenharmony_ci XML_Parser parser; 12013498266Sopenharmony_ci struct ParserStruct state; 12113498266Sopenharmony_ci 12213498266Sopenharmony_ci /* Initialize the state structure for parsing. */ 12313498266Sopenharmony_ci memset(&state, 0, sizeof(struct ParserStruct)); 12413498266Sopenharmony_ci state.ok = 1; 12513498266Sopenharmony_ci 12613498266Sopenharmony_ci /* Initialize a namespace-aware parser. */ 12713498266Sopenharmony_ci parser = XML_ParserCreateNS(NULL, '\0'); 12813498266Sopenharmony_ci XML_SetUserData(parser, &state); 12913498266Sopenharmony_ci XML_SetElementHandler(parser, startElement, endElement); 13013498266Sopenharmony_ci XML_SetCharacterDataHandler(parser, characterDataHandler); 13113498266Sopenharmony_ci 13213498266Sopenharmony_ci /* Initialize a libcurl handle. */ 13313498266Sopenharmony_ci curl_global_init(CURL_GLOBAL_DEFAULT); 13413498266Sopenharmony_ci curl_handle = curl_easy_init(); 13513498266Sopenharmony_ci curl_easy_setopt(curl_handle, CURLOPT_URL, 13613498266Sopenharmony_ci "https://www.w3schools.com/xml/simple.xml"); 13713498266Sopenharmony_ci curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, parseStreamCallback); 13813498266Sopenharmony_ci curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)parser); 13913498266Sopenharmony_ci 14013498266Sopenharmony_ci printf("Depth Characters Closing Tag\n"); 14113498266Sopenharmony_ci 14213498266Sopenharmony_ci /* Perform the request and any follow-up parsing. */ 14313498266Sopenharmony_ci res = curl_easy_perform(curl_handle); 14413498266Sopenharmony_ci if(res != CURLE_OK) { 14513498266Sopenharmony_ci fprintf(stderr, "curl_easy_perform() failed: %s\n", 14613498266Sopenharmony_ci curl_easy_strerror(res)); 14713498266Sopenharmony_ci } 14813498266Sopenharmony_ci else if(state.ok) { 14913498266Sopenharmony_ci /* Expat requires one final call to finalize parsing. */ 15013498266Sopenharmony_ci if(XML_Parse(parser, NULL, 0, 1) == 0) { 15113498266Sopenharmony_ci int error_code = XML_GetErrorCode(parser); 15213498266Sopenharmony_ci fprintf(stderr, "Finalizing parsing failed with error code %d (%s).\n", 15313498266Sopenharmony_ci error_code, XML_ErrorString(error_code)); 15413498266Sopenharmony_ci } 15513498266Sopenharmony_ci else { 15613498266Sopenharmony_ci printf(" --------------\n"); 15713498266Sopenharmony_ci printf(" %lu tags total\n", state.tags); 15813498266Sopenharmony_ci } 15913498266Sopenharmony_ci } 16013498266Sopenharmony_ci 16113498266Sopenharmony_ci /* Clean up. */ 16213498266Sopenharmony_ci free(state.characters.memory); 16313498266Sopenharmony_ci XML_ParserFree(parser); 16413498266Sopenharmony_ci curl_easy_cleanup(curl_handle); 16513498266Sopenharmony_ci curl_global_cleanup(); 16613498266Sopenharmony_ci 16713498266Sopenharmony_ci return 0; 16813498266Sopenharmony_ci} 169