/**
 * synopsis: 	Evaluate XPath expression and prints resulting text (non-text
                nodes are ignored).
 * purpose: 	Extract text content from XML files
 * usage:	xpath <xml-file> <xpath-expr> [<known-ns-list>]
 * author: 	Aleksey Sanin. Modified by Stephane Bortzmeyer
 * copy: 	see Copyright for the status of this software.
 */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>

#include <libxml/tree.h>
#include <libxml/parser.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>

#if defined(LIBXML_XPATH_ENABLED) && defined(LIBXML_SAX1_ENABLED)


static void     usage(const char *name);
int             execute_xpath_expression(const char *filename, const xmlChar * xpathExpr);
void            print_xpath_nodes(xmlNodeSetPtr nodes, FILE * output);

int
main(int argc, char **argv)
{
	/* Parse command line and process file */
	if ((argc < 3) || (argc > 4)) {
		fprintf(stderr, "Error: wrong number of arguments.\n");
		usage(argv[0]);
		return (-1);
	}
	/* Init libxml */
	xmlInitParser();
	LIBXML_TEST_VERSION

	/* Do the main job */
		if (execute_xpath_expression(argv[1], BAD_CAST argv[2]) < 0) {
		usage(argv[0]);
		return (-1);
	}
	/* Shutdown libxml */
	xmlCleanupParser();

	/*
         * this is to debug memory for regression tests
         */
	xmlMemoryDump();
	return 0;
}

/**
 * usage:
 * @name:		the program name.
 *
 * Prints usage information.
 */
static void
usage(const char *name)
{
	assert(name);

	fprintf(stderr, "Usage: %s <xml-file> <xpath-expr>\n", name);
	fprintf(stderr, "in \"<prefix1>=<href1> <prefix2>=href2> ...\" format\n");
}

/**
 * execute_xpath_expression:
 * @filename:		the input XML filename.
 * @xpathExpr:		the xpath expression for evaluation.
 *
 * Parses input XML file, evaluates XPath expression and prints results.
 *
 * Returns 0 on success and a negative value otherwise.
 */
int
execute_xpath_expression(const char *filename, const xmlChar * xpathExpr)
{
	xmlDocPtr       doc;
	xmlXPathContextPtr xpathCtx;
	xmlXPathObjectPtr xpathObj;

	assert(filename);
	assert(xpathExpr);

	/* Load XML document */
	doc = xmlParseFile(filename);
	if (doc == NULL) {
		fprintf(stderr, "Error: unable to parse file \"%s\"\n", filename);
		return (-1);
	}
	/* Create xpath evaluation context */
	xpathCtx = xmlXPathNewContext(doc);
	if (xpathCtx == NULL) {
		fprintf(stderr, "Error: unable to create new XPath context\n");
		xmlFreeDoc(doc);
		return (-1);
	}
	/* Evaluate xpath expression */
	xpathObj = xmlXPathEvalExpression(xpathExpr, xpathCtx);
	if (xpathObj == NULL) {
		fprintf(stderr, "Error: unable to evaluate xpath expression \"%s\"\n", xpathExpr);
		xmlXPathFreeContext(xpathCtx);
		xmlFreeDoc(doc);
		return (-1);
	}
	/* Print results */
	print_xpath_nodes(xpathObj->nodesetval, stdout);

	/* Cleanup */
	xmlXPathFreeObject(xpathObj);
	xmlXPathFreeContext(xpathCtx);
	xmlFreeDoc(doc);

	return (0);
}

/**
 * print_xpath_nodes:
 * @nodes:		the nodes set.
 * @output:		the output file handle.
 *
 * Prints the @nodes content to @output.
 */
void
print_xpath_nodes(xmlNodeSetPtr nodes, FILE * output)
{
	xmlNodePtr      cur;
	int             size;
	int             i;

	assert(output);
	size = (nodes) ? nodes->nodeNr : 0;

	for (i = 0; i < size; ++i) {
		assert(nodes->nodeTab[i]);

		if (nodes->nodeTab[i]->type == XML_TEXT_NODE) {
			cur = nodes->nodeTab[i];
			fprintf(output, "%s\n",
				cur->content);
		}
	}
}

#else
int 
main(void)
{
	fprintf(stderr, "XPath support not compiled in\n");
	exit(1);
}
#endif

