File : xpath_demo.c
Description: A demo C program to print the text of a node from a xpath expression
Usage: xpath_demo.c xml_file xpath_expression
Dependence: libxml2
How to make:
cc -o xpath_demo -L/usr/local/lib -R/usr/local/lib -lxml2 -I/usr/local/include/libxml2 xpath_demo.c
*/
#include <libxml/parser.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h> /* for function xmlXPathRegisterNs */
#include <assert.h>
/* Function Prototype */
int register_namespaces(xmlXPathContextPtr xpathCtx, const xmlChar* nsList);
/* ===================================================================== */
int main(int argc, char **argv) {
xmlDocPtr doc;
/* xmlNodeSetPtr nodeset; */
xmlXPathObjectPtr result;
xmlNode *node;
xmlChar *node_text;
xmlXPathContextPtr context;
char *filename;
xmlChar *xpath_expression;
xmlChar *nsList;
if ((argc != 3) && (argc != 4)) {
fprintf(stderr, "Usage: %s xml_file xpath_expression [<known-ns-list>]\n", argv[0]);
fprintf(stderr, "where <known-ns-list> is a list of known namespaces\n");
fprintf(stderr, "in \"<prefix1>=<href1> <prefix2>=href2> ...\" format\n");
return(1);
}
filename = argv[1];
xpath_expression = (xmlChar*) argv[2];
fprintf (stderr, "DEBUG: LIBXML_VERSION is " LIBXML_VERSION_STRING "\n");
doc = xmlParseFile(filename);
if (doc == NULL ) {
fprintf(stderr, "Error: Document not parsed successfully.\n");
xmlCleanupParser();
return 1;
}
context = xmlXPathNewContext(doc);
if (context == NULL) {
fprintf(stderr, "Error in xmlXPathNewContext\n");
xmlFreeDoc(doc);
xmlCleanupParser();
return 2;
}
if (argc == 4) {
nsList = (xmlChar*) argv[3];
if (register_namespaces(context, nsList) < 0) {
fprintf(stderr,"Error: failed to register namespaces list \"%s\"\n", nsList);
xmlXPathFreeContext(context);
xmlFreeDoc(doc);
xmlCleanupParser();
return 3;
}
}
result = xmlXPathEvalExpression(xpath_expression, context);
xmlXPathFreeContext (context);
if (result == NULL) {
fprintf(stderr, "Error in xmlXPathEvalExpression\n");
xmlFreeDoc(doc);
xmlCleanupParser();
return 4;
}
/*
xmlXPathEvalExpression() call returns a set of ALL the nodes that match the expression
We are only interested in the first node returned
*/
if (xmlXPathNodeSetIsEmpty(result->nodesetval)) {
printf ("Empty\n");
xmlXPathFreeObject(result);
xmlFreeDoc(doc);
xmlCleanupParser();
return 5;
}
/* Retrieve the data */
node = result->nodesetval->nodeTab[0];
node_text = xmlNodeGetContent(node);
/* xmlNodeGetContent retrieves the text values of all children too. This is correct */
fprintf (stderr, "DEBUG: node-type: %d node-name: %s\n" ,node->type, node->name);
xmlAttr *attr = node->properties;
while ( attr ) {
fprintf (stderr, "DEBUG: attribute-name:%s attribute-value:%s\n" , attr->name, attr->children->content);
attr = attr->next;
} /* while */
printf ("node-text: \"%s\"\n", node_text);
xmlFree (node_text);
xmlXPathFreeObject(result);
/* Final clean up */
xmlFreeDoc(doc);
xmlCleanupParser();
return (0);
} /* main */
/**************************************************************************************/
/* The following fucnction is extracted from http://www.xmlsoft.org/examples/xpath1.c */
/**************************************************************************************/
/**
* register_namespaces:
* @xpathCtx: the pointer to an XPath context.
* @nsList: the list of known namespaces in
* "<prefix1>=<href1> <prefix2>=href2> ..." format.
*
* Registers namespaces from @nsList in @xpathCtx.
*
* Returns 0 on success and a negative value otherwise.
*/
int
register_namespaces(xmlXPathContextPtr xpathCtx, const xmlChar* nsList) {
xmlChar* nsListDup;
xmlChar* prefix;
xmlChar* href;
xmlChar* next;
assert(xpathCtx);
assert(nsList);
nsListDup = xmlStrdup(nsList);
if(nsListDup == NULL) {
fprintf(stderr, "Error: unable to strdup namespaces list\n");
return(-1);
}
next = nsListDup;
while(next != NULL) {
/* skip spaces */
while((*next) == ' ') next++;
if((*next) == '\0') break;
/* find prefix */
prefix = next;
next = (xmlChar*)xmlStrchr(next, '=');
if(next == NULL) {
fprintf(stderr,"Error: invalid namespaces list format\n");
xmlFree(nsListDup);
return(-1);
}
*(next++) = '\0';
/* find href */
href = next;
next = (xmlChar*)xmlStrchr(next, ' ');
if(next != NULL) {
*(next++) = '\0';
}
/* do register namespace */
if(xmlXPathRegisterNs(xpathCtx, prefix, href) != 0) {
fprintf(stderr,"Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", prefix, href);
xmlFree(nsListDup);
return(-1);
}
}
xmlFree(nsListDup);
return(0);
}