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 $(srcdir)/xpath1.res 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 251