1 /** 2 * section: InputOutput 3 * synopsis: Example of custom Input/Output 4 * purpose: Demonstrate the use of xmlRegisterInputCallbacks 5 * to build a custom I/O layer, this is used in an 6 * XInclude method context to show how dynamic document can 7 * be built in a clean way. 8 * usage: io1 9 * test: io1 > io1.tmp && diff io1.tmp $(srcdir)/io1.res 10 * author: Daniel Veillard 11 * copy: see Copyright for the status of this software. 12 */ 13 14 #include <stdio.h> 15 #include <string.h> 16 #include <libxml/parser.h> 17 #include <libxml/tree.h> 18 #include <libxml/xinclude.h> 19 #include <libxml/xmlIO.h> 20 21 #ifdef LIBXML_XINCLUDE_ENABLED 22 static const char *result = "<list><people>a</people><people>b</people></list>"; 23 static const char *cur = NULL; 24 static int rlen; 25 26 /** 27 * sqlMatch: 28 * @URI: an URI to test 29 * 30 * Check for an sql: query 31 * 32 * Returns 1 if yes and 0 if another Input module should be used 33 */ 34 static int 35 sqlMatch(const char * URI) { 36 if ((URI != NULL) && (!strncmp(URI, "sql:", 4))) 37 return(1); 38 return(0); 39 } 40 41 /** 42 * sqlOpen: 43 * @URI: an URI to test 44 * 45 * Return a pointer to the sql: query handler, in this example simply 46 * the current pointer... 47 * 48 * Returns an Input context or NULL in case or error 49 */ 50 static void * 51 sqlOpen(const char * URI) { 52 if ((URI == NULL) || (strncmp(URI, "sql:", 4))) 53 return(NULL); 54 cur = result; 55 rlen = strlen(result); 56 return((void *) cur); 57 } 58 59 /** 60 * sqlClose: 61 * @context: the read context 62 * 63 * Close the sql: query handler 64 * 65 * Returns 0 or -1 in case of error 66 */ 67 static int 68 sqlClose(void * context) { 69 if (context == NULL) return(-1); 70 cur = NULL; 71 rlen = 0; 72 return(0); 73 } 74 75 /** 76 * sqlRead: 77 * @context: the read context 78 * @buffer: where to store data 79 * @len: number of bytes to read 80 * 81 * Implement an sql: query read. 82 * 83 * Returns the number of bytes read or -1 in case of error 84 */ 85 static int 86 sqlRead(void * context, char * buffer, int len) { 87 const char *ptr = (const char *) context; 88 89 if ((context == NULL) || (buffer == NULL) || (len < 0)) 90 return(-1); 91 92 if (len > rlen) len = rlen; 93 memcpy(buffer, ptr, len); 94 rlen -= len; 95 return(len); 96 } 97 98 const char *include = "<?xml version='1.0'?>\n\ 99 <document xmlns:xi=\"http://www.w3.org/2003/XInclude\">\n\ 100 <p>List of people:</p>\n\ 101 <xi:include href=\"sql:select_name_from_people\"/>\n\ 102 </document>\n"; 103 104 int main(void) { 105 xmlDocPtr doc; 106 107 /* 108 * this initialize the library and check potential ABI mismatches 109 * between the version it was compiled for and the actual shared 110 * library used. 111 */ 112 LIBXML_TEST_VERSION 113 114 /* 115 * register the new I/O handlers 116 */ 117 if (xmlRegisterInputCallbacks(sqlMatch, sqlOpen, sqlRead, sqlClose) < 0) { 118 fprintf(stderr, "failed to register SQL handler\n"); 119 exit(1); 120 } 121 /* 122 * parse include into a document 123 */ 124 doc = xmlReadMemory(include, strlen(include), "include.xml", NULL, 0); 125 if (doc == NULL) { 126 fprintf(stderr, "failed to parse the including file\n"); 127 exit(1); 128 } 129 130 /* 131 * apply the XInclude process, this should trigger the I/O just 132 * registered. 133 */ 134 if (xmlXIncludeProcess(doc) <= 0) { 135 fprintf(stderr, "XInclude processing failed\n"); 136 exit(1); 137 } 138 139 #ifdef LIBXML_OUTPUT_ENABLED 140 /* 141 * save the output for checking to stdout 142 */ 143 xmlDocDump(stdout, doc); 144 #endif 145 146 /* 147 * Free the document 148 */ 149 xmlFreeDoc(doc); 150 151 /* 152 * Cleanup function for the XML library. 153 */ 154 xmlCleanupParser(); 155 /* 156 * this is to debug memory for regression tests 157 */ 158 xmlMemoryDump(); 159 return(0); 160 } 161 #else 162 int main(void) { 163 fprintf(stderr, "XInclude support not compiled in\n"); 164 exit(1); 165 } 166 #endif 167