From 1934b0c0fa8dff467955ae51118b69716a75f62b Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Wed, 7 Oct 2009 10:25:06 +0200 Subject: [PATCH] Adding a --xpath option to xmllint * xmllint.c: runs in --noout mode and dumps the result of the XPath argument query. Still need to be expanded in some ways to allow namespace binding. --- xmllint.c | 139 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 130 insertions(+), 9 deletions(-) diff --git a/xmllint.c b/xmllint.c index 6e4138e9..cb845c78 100644 --- a/xmllint.c +++ b/xmllint.c @@ -108,15 +108,16 @@ typedef enum { XMLLINT_RETURN_OK = 0, /* No error */ - XMLLINT_ERR_UNCLASS, /* Unclassified */ - XMLLINT_ERR_DTD, /* Error in DTD */ - XMLLINT_ERR_VALID, /* Validation error */ - XMLLINT_ERR_RDFILE, /* CtxtReadFile error */ - XMLLINT_ERR_SCHEMACOMP, /* Schema compilation */ - XMLLINT_ERR_OUT, /* Error writing output */ - XMLLINT_ERR_SCHEMAPAT, /* Error in schema pattern */ - XMLLINT_ERR_RDREGIS, /* Error in Reader registration */ - XMLLINT_ERR_MEM /* Out of memory error */ + XMLLINT_ERR_UNCLASS = 1, /* Unclassified */ + XMLLINT_ERR_DTD = 2, /* Error in DTD */ + XMLLINT_ERR_VALID = 3, /* Validation error */ + XMLLINT_ERR_RDFILE = 4, /* CtxtReadFile error */ + XMLLINT_ERR_SCHEMACOMP = 5, /* Schema compilation */ + XMLLINT_ERR_OUT = 6, /* Error writing output */ + XMLLINT_ERR_SCHEMAPAT = 7, /* Error in schema pattern */ + XMLLINT_ERR_RDREGIS = 8, /* Error in Reader registration */ + XMLLINT_ERR_MEM = 9, /* Out of memory error */ + XMLLINT_ERR_XPATH = 10 /* XPath evaluation error */ } xmllintReturnCode; #ifdef LIBXML_DEBUG_ENABLED static int shell = 0; @@ -201,6 +202,9 @@ static const char *pattern = NULL; static xmlPatternPtr patternc = NULL; static xmlStreamCtxtPtr patstream = NULL; #endif +#ifdef LIBXML_XPATH_ENABLED +static const char *xpathquery = NULL; +#endif static int options = XML_PARSE_COMPACT; static int sax = 0; static int oldxml10 = 0; @@ -2050,6 +2054,100 @@ static void walkDoc(xmlDocPtr doc) { } #endif /* LIBXML_READER_ENABLED */ +#ifdef LIBXML_XPATH_ENABLED +/************************************************************************ + * * + * XPath Query * + * * + ************************************************************************/ + +static void doXPathDump(xmlXPathObjectPtr cur) { + switch(cur->type) { + case XPATH_NODESET: { + int i; + xmlNodePtr node; +#ifdef LIBXML_OUTPUT_ENABLED + xmlSaveCtxtPtr ctxt; + + if (cur->nodesetval->nodeNr <= 0) { + fprintf(stderr, "XPath set is empty\n"); + progresult = XMLLINT_ERR_XPATH; + break; + } + ctxt = xmlSaveToFd(1, NULL, 0); + if (ctxt == NULL) { + fprintf(stderr, "Out of memory for XPath\n"); + progresult = XMLLINT_ERR_MEM; + return; + } + for (i = 0;i < cur->nodesetval->nodeNr;i++) { + node = cur->nodesetval->nodeTab[i]; + xmlSaveTree(ctxt, node); + } + xmlSaveClose(ctxt); +#else + printf("xpath returned %d nodes\n", cur->nodesetval->nodeNr); +#endif + break; + } + case XPATH_BOOLEAN: + if (cur->boolval) printf("true"); + else printf("false"); + break; + case XPATH_NUMBER: + switch (xmlXPathIsInf(cur->floatval)) { + case 1: + printf("Infinity"); + break; + case -1: + printf("-Infinity"); + break; + default: + if (xmlXPathIsNaN(cur->floatval)) { + printf("NaN"); + } else { + printf("%0g", cur->floatval); + } + } + break; + case XPATH_STRING: + printf("%s", (const char *) cur->stringval); + break; + case XPATH_UNDEFINED: + fprintf(stderr, "XPath Object is uninitialized\n"); + progresult = XMLLINT_ERR_XPATH; + break; + default: + fprintf(stderr, "XPath object of unexpected type\n"); + progresult = XMLLINT_ERR_XPATH; + break; + } +} + +static void doXPathQuery(xmlDocPtr doc, const char *query) { + xmlXPathContextPtr ctxt; + xmlXPathObjectPtr res; + + ctxt = xmlXPathNewContext(doc); + if (ctxt == NULL) { + fprintf(stderr, "Out of memory for XPath\n"); + progresult = XMLLINT_ERR_MEM; + return; + } + ctxt->node = xmlDocGetRootElement(doc); + res = xmlXPathEval(BAD_CAST query, ctxt); + xmlXPathFreeContext(ctxt); + + if (res == NULL) { + fprintf(stderr, "XPath evaluation failure\n"); + progresult = XMLLINT_ERR_XPATH; + return; + } + doXPathDump(res); + xmlXPathFreeObject(res); +} +#endif /* LIBXML_XPATH_ENABLED */ + /************************************************************************ * * * Tree Test processing * @@ -2318,6 +2416,12 @@ static void parseAndPrintFile(char *filename, xmlParserCtxtPtr rectxt) { } #endif +#ifdef LIBXML_XPATH_ENABLED + if (xpathquery != NULL) { + doXPathQuery(doc, xpathquery); + } +#endif + #ifdef LIBXML_DEBUG_ENABLED #ifdef LIBXML_XPATH_ENABLED /* @@ -2945,6 +3049,9 @@ static void usage(const char *name) { #endif printf("\t--sax: do not build a tree but work just at the SAX level\n"); printf("\t--oldxml10: use XML-1.0 parsing rules before the 5th edition\n"); +#ifdef LIBXML_XPATH_ENABLED + printf("\t--xpath expr: evaluate the XPath expression, inply --noout\n"); +#endif printf("\nLibxml project home page: http://xmlsoft.org/\n"); printf("To report bugs or get some help check: http://xmlsoft.org/bugs.html\n"); @@ -3284,6 +3391,13 @@ main(int argc, char **argv) { (!strcmp(argv[i], "--pattern"))) { i++; pattern = argv[i]; +#endif +#ifdef LIBXML_XPATH_ENABLED + } else if ((!strcmp(argv[i], "-xpath")) || + (!strcmp(argv[i], "--xpath"))) { + i++; + noout++; + xpathquery = argv[i]; #endif } else if ((!strcmp(argv[i], "-oldxml10")) || (!strcmp(argv[i], "--oldxml10"))) { @@ -3515,6 +3629,13 @@ main(int argc, char **argv) { i++; continue; } +#endif +#ifdef LIBXML_XPATH_ENABLED + if ((!strcmp(argv[i], "-xpath")) || + (!strcmp(argv[i], "--xpath"))) { + i++; + continue; + } #endif if ((timing) && (repeat)) startTimer();