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