1 | /**
|
---|
2 | * section: XPath
|
---|
3 | * synopsis: Evaluate XPath expression and prints result node set.
|
---|
4 | * purpose: Shows how to evaluate XPath expression and register
|
---|
5 | * known namespaces in XPath context.
|
---|
6 | * usage: xpath1 <xml-file> <xpath-expr> [<known-ns-list>]
|
---|
7 | * test: ./xpath1 test3.xml '//child2' > xpath1.tmp ; diff xpath1.tmp xpath1.res ; rm xpath1.tmp
|
---|
8 | * author: Aleksey Sanin
|
---|
9 | * copy: see Copyright for the status of this software.
|
---|
10 | */
|
---|
11 | #include <stdlib.h>
|
---|
12 | #include <stdio.h>
|
---|
13 | #include <string.h>
|
---|
14 | #include <assert.h>
|
---|
15 |
|
---|
16 | #include <libxml/tree.h>
|
---|
17 | #include <libxml/parser.h>
|
---|
18 | #include <libxml/xpath.h>
|
---|
19 | #include <libxml/xpathInternals.h>
|
---|
20 |
|
---|
21 | #if defined(LIBXML_XPATH_ENABLED) && defined(LIBXML_SAX1_ENABLED)
|
---|
22 |
|
---|
23 |
|
---|
24 | static void usage(const char *name);
|
---|
25 | int execute_xpath_expression(const char* filename, const xmlChar* xpathExpr, const xmlChar* nsList);
|
---|
26 | int register_namespaces(xmlXPathContextPtr xpathCtx, const xmlChar* nsList);
|
---|
27 | void print_xpath_nodes(xmlNodeSetPtr nodes, FILE* output);
|
---|
28 |
|
---|
29 | int
|
---|
30 | main(int argc, char **argv) {
|
---|
31 | /* Parse command line and process file */
|
---|
32 | if((argc < 3) || (argc > 4)) {
|
---|
33 | fprintf(stderr, "Error: wrong number of arguments.\n");
|
---|
34 | usage(argv[0]);
|
---|
35 | return(-1);
|
---|
36 | }
|
---|
37 |
|
---|
38 | /* Init libxml */
|
---|
39 | xmlInitParser();
|
---|
40 | LIBXML_TEST_VERSION
|
---|
41 |
|
---|
42 | /* Do the main job */
|
---|
43 | if(execute_xpath_expression(argv[1], BAD_CAST argv[2], (argc > 3) ? BAD_CAST argv[3] : NULL) < 0) {
|
---|
44 | usage(argv[0]);
|
---|
45 | return(-1);
|
---|
46 | }
|
---|
47 |
|
---|
48 | /* Shutdown libxml */
|
---|
49 | xmlCleanupParser();
|
---|
50 |
|
---|
51 | /*
|
---|
52 | * this is to debug memory for regression tests
|
---|
53 | */
|
---|
54 | xmlMemoryDump();
|
---|
55 | return 0;
|
---|
56 | }
|
---|
57 |
|
---|
58 | /**
|
---|
59 | * usage:
|
---|
60 | * @name: the program name.
|
---|
61 | *
|
---|
62 | * Prints usage information.
|
---|
63 | */
|
---|
64 | static void
|
---|
65 | usage(const char *name) {
|
---|
66 | assert(name);
|
---|
67 |
|
---|
68 | fprintf(stderr, "Usage: %s <xml-file> <xpath-expr> [<known-ns-list>]\n", name);
|
---|
69 | fprintf(stderr, "where <known-ns-list> is a list of known namespaces\n");
|
---|
70 | fprintf(stderr, "in \"<prefix1>=<href1> <prefix2>=href2> ...\" format\n");
|
---|
71 | }
|
---|
72 |
|
---|
73 | /**
|
---|
74 | * execute_xpath_expression:
|
---|
75 | * @filename: the input XML filename.
|
---|
76 | * @xpathExpr: the xpath expression for evaluation.
|
---|
77 | * @nsList: the optional list of known namespaces in
|
---|
78 | * "<prefix1>=<href1> <prefix2>=href2> ..." format.
|
---|
79 | *
|
---|
80 | * Parses input XML file, evaluates XPath expression and prints results.
|
---|
81 | *
|
---|
82 | * Returns 0 on success and a negative value otherwise.
|
---|
83 | */
|
---|
84 | int
|
---|
85 | execute_xpath_expression(const char* filename, const xmlChar* xpathExpr, const xmlChar* nsList) {
|
---|
86 | xmlDocPtr doc;
|
---|
87 | xmlXPathContextPtr xpathCtx;
|
---|
88 | xmlXPathObjectPtr xpathObj;
|
---|
89 |
|
---|
90 | assert(filename);
|
---|
91 | assert(xpathExpr);
|
---|
92 |
|
---|
93 | /* Load XML document */
|
---|
94 | doc = xmlParseFile(filename);
|
---|
95 | if (doc == NULL) {
|
---|
96 | fprintf(stderr, "Error: unable to parse file \"%s\"\n", filename);
|
---|
97 | return(-1);
|
---|
98 | }
|
---|
99 |
|
---|
100 | /* Create xpath evaluation context */
|
---|
101 | xpathCtx = xmlXPathNewContext(doc);
|
---|
102 | if(xpathCtx == NULL) {
|
---|
103 | fprintf(stderr,"Error: unable to create new XPath context\n");
|
---|
104 | xmlFreeDoc(doc);
|
---|
105 | return(-1);
|
---|
106 | }
|
---|
107 |
|
---|
108 | /* Register namespaces from list (if any) */
|
---|
109 | if((nsList != NULL) && (register_namespaces(xpathCtx, nsList) < 0)) {
|
---|
110 | fprintf(stderr,"Error: failed to register namespaces list \"%s\"\n", nsList);
|
---|
111 | xmlXPathFreeContext(xpathCtx);
|
---|
112 | xmlFreeDoc(doc);
|
---|
113 | return(-1);
|
---|
114 | }
|
---|
115 |
|
---|
116 | /* Evaluate xpath expression */
|
---|
117 | xpathObj = xmlXPathEvalExpression(xpathExpr, xpathCtx);
|
---|
118 | if(xpathObj == NULL) {
|
---|
119 | fprintf(stderr,"Error: unable to evaluate xpath expression \"%s\"\n", xpathExpr);
|
---|
120 | xmlXPathFreeContext(xpathCtx);
|
---|
121 | xmlFreeDoc(doc);
|
---|
122 | return(-1);
|
---|
123 | }
|
---|
124 |
|
---|
125 | /* Print results */
|
---|
126 | print_xpath_nodes(xpathObj->nodesetval, stdout);
|
---|
127 |
|
---|
128 | /* Cleanup */
|
---|
129 | xmlXPathFreeObject(xpathObj);
|
---|
130 | xmlXPathFreeContext(xpathCtx);
|
---|
131 | xmlFreeDoc(doc);
|
---|
132 |
|
---|
133 | return(0);
|
---|
134 | }
|
---|
135 |
|
---|
136 | /**
|
---|
137 | * register_namespaces:
|
---|
138 | * @xpathCtx: the pointer to an XPath context.
|
---|
139 | * @nsList: the list of known namespaces in
|
---|
140 | * "<prefix1>=<href1> <prefix2>=href2> ..." format.
|
---|
141 | *
|
---|
142 | * Registers namespaces from @nsList in @xpathCtx.
|
---|
143 | *
|
---|
144 | * Returns 0 on success and a negative value otherwise.
|
---|
145 | */
|
---|
146 | int
|
---|
147 | register_namespaces(xmlXPathContextPtr xpathCtx, const xmlChar* nsList) {
|
---|
148 | xmlChar* nsListDup;
|
---|
149 | xmlChar* prefix;
|
---|
150 | xmlChar* href;
|
---|
151 | xmlChar* next;
|
---|
152 |
|
---|
153 | assert(xpathCtx);
|
---|
154 | assert(nsList);
|
---|
155 |
|
---|
156 | nsListDup = xmlStrdup(nsList);
|
---|
157 | if(nsListDup == NULL) {
|
---|
158 | fprintf(stderr, "Error: unable to strdup namespaces list\n");
|
---|
159 | return(-1);
|
---|
160 | }
|
---|
161 |
|
---|
162 | next = nsListDup;
|
---|
163 | while(next != NULL) {
|
---|
164 | /* skip spaces */
|
---|
165 | while((*next) == ' ') next++;
|
---|
166 | if((*next) == '\0') break;
|
---|
167 |
|
---|
168 | /* find prefix */
|
---|
169 | prefix = next;
|
---|
170 | next = (xmlChar*)xmlStrchr(next, '=');
|
---|
171 | if(next == NULL) {
|
---|
172 | fprintf(stderr,"Error: invalid namespaces list format\n");
|
---|
173 | xmlFree(nsListDup);
|
---|
174 | return(-1);
|
---|
175 | }
|
---|
176 | *(next++) = '\0';
|
---|
177 |
|
---|
178 | /* find href */
|
---|
179 | href = next;
|
---|
180 | next = (xmlChar*)xmlStrchr(next, ' ');
|
---|
181 | if(next != NULL) {
|
---|
182 | *(next++) = '\0';
|
---|
183 | }
|
---|
184 |
|
---|
185 | /* do register namespace */
|
---|
186 | if(xmlXPathRegisterNs(xpathCtx, prefix, href) != 0) {
|
---|
187 | fprintf(stderr,"Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", prefix, href);
|
---|
188 | xmlFree(nsListDup);
|
---|
189 | return(-1);
|
---|
190 | }
|
---|
191 | }
|
---|
192 |
|
---|
193 | xmlFree(nsListDup);
|
---|
194 | return(0);
|
---|
195 | }
|
---|
196 |
|
---|
197 | /**
|
---|
198 | * print_xpath_nodes:
|
---|
199 | * @nodes: the nodes set.
|
---|
200 | * @output: the output file handle.
|
---|
201 | *
|
---|
202 | * Prints the @nodes content to @output.
|
---|
203 | */
|
---|
204 | void
|
---|
205 | print_xpath_nodes(xmlNodeSetPtr nodes, FILE* output) {
|
---|
206 | xmlNodePtr cur;
|
---|
207 | int size;
|
---|
208 | int i;
|
---|
209 |
|
---|
210 | assert(output);
|
---|
211 | size = (nodes) ? nodes->nodeNr : 0;
|
---|
212 |
|
---|
213 | fprintf(output, "Result (%d nodes):\n", size);
|
---|
214 | for(i = 0; i < size; ++i) {
|
---|
215 | assert(nodes->nodeTab[i]);
|
---|
216 |
|
---|
217 | if(nodes->nodeTab[i]->type == XML_NAMESPACE_DECL) {
|
---|
218 | xmlNsPtr ns;
|
---|
219 |
|
---|
220 | ns = (xmlNsPtr)nodes->nodeTab[i];
|
---|
221 | cur = (xmlNodePtr)ns->next;
|
---|
222 | if(cur->ns) {
|
---|
223 | fprintf(output, "= namespace \"%s\"=\"%s\" for node %s:%s\n",
|
---|
224 | ns->prefix, ns->href, cur->ns->href, cur->name);
|
---|
225 | } else {
|
---|
226 | fprintf(output, "= namespace \"%s\"=\"%s\" for node %s\n",
|
---|
227 | ns->prefix, ns->href, cur->name);
|
---|
228 | }
|
---|
229 | } else if(nodes->nodeTab[i]->type == XML_ELEMENT_NODE) {
|
---|
230 | cur = nodes->nodeTab[i];
|
---|
231 | if(cur->ns) {
|
---|
232 | fprintf(output, "= element node \"%s:%s\"\n",
|
---|
233 | cur->ns->href, cur->name);
|
---|
234 | } else {
|
---|
235 | fprintf(output, "= element node \"%s\"\n",
|
---|
236 | cur->name);
|
---|
237 | }
|
---|
238 | } else {
|
---|
239 | cur = nodes->nodeTab[i];
|
---|
240 | fprintf(output, "= node \"%s\": type %d\n", cur->name, cur->type);
|
---|
241 | }
|
---|
242 | }
|
---|
243 | }
|
---|
244 |
|
---|
245 | #else
|
---|
246 | int main(void) {
|
---|
247 | fprintf(stderr, "XPath support not compiled in\n");
|
---|
248 | exit(1);
|
---|
249 | }
|
---|
250 | #endif
|
---|