xpath1.c 6.5 KB

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