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