+
+/* Run an XPath query on XML on stdin, print results to stdout. */
+static void
+do_xpath (const char *query)
+{
+ xmlDocPtr doc;
+ xmlXPathContextPtr xpathCtx;
+ xmlXPathObjectPtr xpathObj;
+ xmlNodeSetPtr nodes;
+ char *r;
+ size_t i;
+ xmlSaveCtxtPtr saveCtx;
+ xmlDocPtr wrdoc;
+ xmlNodePtr wrnode;
+
+ doc = xmlReadFd (STDIN_FILENO, NULL, "utf8", 0);
+ if (doc == NULL) {
+ fprintf (stderr, _("%s: unable to parse XML from stdin\n"), program_name);
+ exit (EXIT_FAILURE);
+ }
+
+ xpathCtx = xmlXPathNewContext (doc);
+ if (xpathCtx == NULL) {
+ fprintf (stderr, _("%s: unable to create new XPath context\n"),
+ program_name);
+ exit (EXIT_FAILURE);
+ }
+
+ xpathObj = xmlXPathEvalExpression (BAD_CAST query, xpathCtx);
+ if (xpathObj == NULL) {
+ fprintf (stderr, _("%s: unable to evaluate XPath expression\n"),
+ program_name);
+ exit (EXIT_FAILURE);
+ }
+
+ switch (xpathObj->type) {
+ case XPATH_NODESET:
+ nodes = xpathObj->nodesetval;
+
+ saveCtx = xmlSaveToFd (STDOUT_FILENO, NULL, XML_SAVE_NO_DECL);
+ if (saveCtx == NULL) {
+ fprintf (stderr, _("%s: xmlSaveToFd failed\n"), program_name);
+ exit (EXIT_FAILURE);
+ }
+
+ for (i = 0; i < (size_t) nodes->nodeNr; ++i) {
+ wrdoc = xmlNewDoc (BAD_CAST "1.0");
+ if (wrdoc == NULL) {
+ fprintf (stderr, _("%s: xmlNewDoc failed\n"), program_name);
+ exit (EXIT_FAILURE);
+ }
+ wrnode = xmlCopyNode (nodes->nodeTab[i], 1);
+ if (wrnode == NULL) {
+ fprintf (stderr, _("%s: xmlCopyNode failed\n"), program_name);
+ exit (EXIT_FAILURE);
+ }
+
+ xmlDocSetRootElement (wrdoc, wrnode);
+
+ if (xmlSaveDoc (saveCtx, wrdoc) == -1) {
+ fprintf (stderr, _("%s: xmlSaveDoc failed\n"), program_name);
+ exit (EXIT_FAILURE);
+ }
+
+ xmlFreeDoc (wrdoc);
+ }
+
+ xmlSaveClose (saveCtx);
+
+ break;
+
+ case XPATH_STRING:
+ r = (char *) xpathObj->stringval;
+ printf ("%s", r);
+ i = strlen (r);
+ if (i > 0 && r[i-1] != '\n')
+ printf ("\n");
+ break;
+
+ case XPATH_UNDEFINED: /* grrrrr ... switch-enum is a useless warning */
+ case XPATH_BOOLEAN:
+ case XPATH_NUMBER:
+ case XPATH_POINT:
+ case XPATH_RANGE:
+ case XPATH_LOCATIONSET:
+ case XPATH_USERS:
+ case XPATH_XSLT_TREE:
+ default:
+ r = (char *) xmlXPathCastToString (xpathObj);
+ printf ("%s\n", r);
+ free (r);
+ }
+
+ xmlXPathFreeObject (xpathObj);
+ xmlXPathFreeContext (xpathCtx);
+ xmlFreeDoc (doc);
+
+ exit (EXIT_SUCCESS);
+}