/* XPath の練習用 * libxml2 の XPath Examples の xpath1.c を改造。オリジナルコード: * http://xmlsoft.org/examples/index.html#XPath * 改造内容: * ・各ノードの属性リストも表示 * ・XSLT 関数(count や substring など)や、計算式にも対応 */ #include #include #include #include #include #include #include #include #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, const xmlChar* nsList); int register_namespaces(xmlXPathContextPtr xpathCtx, const xmlChar* nsList); 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], (argc > 3) ? BAD_CAST argv[3] : NULL) < 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 []\n", name); fprintf(stderr, "where is a list of known namespaces\n"); fprintf(stderr, "in \"= =href2> ...\" format\n"); } /** * execute_xpath_expression: * @filename: the input XML filename. * @xpathExpr: the xpath expression for evaluation. * @nsList: the optional list of known namespaces in * "= =href2> ..." format. * * 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, const xmlChar* nsList) { 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); } /* Register namespaces from list (if any) */ if((nsList != NULL) && (register_namespaces(xpathCtx, nsList) < 0)) { fprintf(stderr,"Error: failed to register namespaces list \"%s\"\n", nsList); xmlXPathFreeContext(xpathCtx); 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 */ switch (xpathObj->type) { case XPATH_NODESET: print_xpath_nodes(xpathObj->nodesetval, stdout); break; case XPATH_NUMBER: printf("%f\n", xpathObj->floatval); break; case XPATH_BOOLEAN: printf("%s\n", (xpathObj->boolval)?"true":"false"); break; case XPATH_STRING: printf("%s\n", xpathObj->stringval); } /* Cleanup */ xmlXPathFreeObject(xpathObj); xmlXPathFreeContext(xpathCtx); xmlFreeDoc(doc); return(0); } /** * register_namespaces: * @xpathCtx: the pointer to an XPath context. * @nsList: the list of known namespaces in * "= =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); } void print_xmlAttrs(xmlAttrPtr attrs, FILE*output) { xmlAttrPtr p = attrs; if (!p) { return; } for (; p; p=p->next) { if (p->ns) { fprintf(output, " (%s):%s=\"%s\"", p->ns->href, p->name, p->children->content); } else { fprintf(output, " %s=\"%s\"", p->name, p->children->content); } } } /** * 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; fprintf(output, "Result (%d nodes):\n", size); for(i = 0; i < size; ++i) { assert(nodes->nodeTab[i]); if(nodes->nodeTab[i]->type == XML_NAMESPACE_DECL) { xmlNsPtr ns; ns = (xmlNsPtr)nodes->nodeTab[i]; cur = (xmlNodePtr)ns->next; if(cur->ns) { fprintf(output, "= namespace \"%s\"=\"%s\" for node %s:%s\n", ns->prefix, ns->href, cur->ns->href, cur->name); } else { fprintf(output, "= namespace \"%s\"=\"%s\" for node %s\n", ns->prefix, ns->href, cur->name); } } else if(nodes->nodeTab[i]->type == XML_ELEMENT_NODE) { cur = nodes->nodeTab[i]; if(cur->ns) { // fprintf(output, "= element node \"%s:%s\"\n", fprintf(output, "<(%s):%s", cur->ns->href, cur->name); if (cur->properties) { print_xmlAttrs(cur->properties, output); } fprintf(output, "/>\n"); } else { fprintf(output, "<%s", cur->name); if (cur->properties) { print_xmlAttrs(cur->properties, output); } fprintf(output, "/>\n"); } } else { cur = nodes->nodeTab[i]; switch (cur->type) { case 3: //fprintf(output, "text\n"); if (cur->content) { fprintf(output, "%s\n", cur->content); } break; case 2: //fprintf(output, "attribute\n"); if (cur->children && cur->children->content) { fprintf(output, "%s\n", cur->children->content); } } } } } #else int main(void) { fprintf(stderr, "XPath support not compiled in\n"); exit(1); } #endif