xpath1.c
最終更新:2009/11/20
001: /* XPath の練習用 002: * libxml2 の XPath Examples の xpath1.c を改造。オリジナルコード: 003: * http://xmlsoft.org/examples/index.html#XPath 004: * 改造内容: 005: * ・各ノードの属性リストも表示 006: * ・XSLT 関数(count や substring など)や、計算式にも対応 007: */ 008: #include <stdlib.h> 009: #include <stdio.h> 010: #include <string.h> 011: #include <assert.h> 012: 013: #include <libxml/tree.h> 014: #include <libxml/parser.h> 015: #include <libxml/xpath.h> 016: #include <libxml/xpathInternals.h> 017: 018: #if defined(LIBXML_XPATH_ENABLED) && defined(LIBXML_SAX1_ENABLED) 019: 020: 021: static void usage(const char *name); 022: int execute_xpath_expression(const char* filename, const xmlChar* xpathExpr, const xmlChar* nsList); 023: int register_namespaces(xmlXPathContextPtr xpathCtx, const xmlChar* nsList); 024: void print_xpath_nodes(xmlNodeSetPtr nodes, FILE* output); 025: 026: int 027: main(int argc, char **argv) { 028: /* Parse command line and process file */ 029: if((argc < 3) || (argc > 4)) { 030: fprintf(stderr, "Error: wrong number of arguments.\n"); 031: usage(argv[0]); 032: return(-1); 033: } 034: 035: /* Init libxml */ 036: xmlInitParser(); 037: LIBXML_TEST_VERSION 038: 039: /* Do the main job */ 040: if(execute_xpath_expression(argv[1], BAD_CAST argv[2], (argc > 3) ? BAD_CAST argv[3] : NULL) < 0) { 041: usage(argv[0]); 042: return(-1); 043: } 044: 045: /* Shutdown libxml */ 046: xmlCleanupParser(); 047: 048: /* 049: * this is to debug memory for regression tests 050: */ 051: xmlMemoryDump(); 052: return 0; 053: } 054: 055: /** 056: * usage: 057: * @name: the program name. 058: * 059: * Prints usage information. 060: */ 061: static void 062: usage(const char *name) { 063: assert(name); 064: 065: fprintf(stderr, "Usage: %s <xml-file> <xpath-expr> [<known-ns-list>]\n", name); 066: fprintf(stderr, "where <known-ns-list> is a list of known namespaces\n"); 067: fprintf(stderr, "in \"<prefix1>=<href1> <prefix2>=href2> ...\" format\n"); 068: } 069: 070: /** 071: * execute_xpath_expression: 072: * @filename: the input XML filename. 073: * @xpathExpr: the xpath expression for evaluation. 074: * @nsList: the optional list of known namespaces in 075: * "<prefix1>=<href1> <prefix2>=href2> ..." format. 076: * 077: * Parses input XML file, evaluates XPath expression and prints results. 078: * 079: * Returns 0 on success and a negative value otherwise. 080: */ 081: int 082: execute_xpath_expression(const char* filename, const xmlChar* xpathExpr, const xmlChar* nsList) { 083: xmlDocPtr doc; 084: xmlXPathContextPtr xpathCtx; 085: xmlXPathObjectPtr xpathObj; 086: 087: assert(filename); 088: assert(xpathExpr); 089: 090: /* Load XML document */ 091: doc = xmlParseFile(filename); 092: if (doc == NULL) { 093: fprintf(stderr, "Error: unable to parse file \"%s\"\n", filename); 094: return(-1); 095: } 096: 097: /* Create xpath evaluation context */ 098: xpathCtx = xmlXPathNewContext(doc); 099: if(xpathCtx == NULL) { 100: fprintf(stderr,"Error: unable to create new XPath context\n"); 101: xmlFreeDoc(doc); 102: return(-1); 103: } 104: 105: /* Register namespaces from list (if any) */ 106: if((nsList != NULL) && (register_namespaces(xpathCtx, nsList) < 0)) { 107: fprintf(stderr,"Error: failed to register namespaces list \"%s\"\n", nsList); 108: xmlXPathFreeContext(xpathCtx); 109: xmlFreeDoc(doc); 110: return(-1); 111: } 112: 113: /* Evaluate xpath expression */ 114: xpathObj = xmlXPathEvalExpression(xpathExpr, xpathCtx); 115: if(xpathObj == NULL) { 116: fprintf(stderr,"Error: unable to evaluate xpath expression \"%s\"\n", xpathExpr); 117: xmlXPathFreeContext(xpathCtx); 118: xmlFreeDoc(doc); 119: return(-1); 120: } 121: 122: /* Print results */ 123: switch (xpathObj->type) { 124: case XPATH_NODESET: 125: print_xpath_nodes(xpathObj->nodesetval, stdout); 126: break; 127: case XPATH_NUMBER: 128: printf("%f\n", xpathObj->floatval); 129: break; 130: case XPATH_BOOLEAN: 131: printf("%s\n", (xpathObj->boolval)?"true":"false"); 132: break; 133: case XPATH_STRING: 134: printf("%s\n", xpathObj->stringval); 135: } 136: 137: /* Cleanup */ 138: xmlXPathFreeObject(xpathObj); 139: xmlXPathFreeContext(xpathCtx); 140: xmlFreeDoc(doc); 141: 142: return(0); 143: } 144: 145: /** 146: * register_namespaces: 147: * @xpathCtx: the pointer to an XPath context. 148: * @nsList: the list of known namespaces in 149: * "<prefix1>=<href1> <prefix2>=href2> ..." format. 150: * 151: * Registers namespaces from @nsList in @xpathCtx. 152: * 153: * Returns 0 on success and a negative value otherwise. 154: */ 155: int 156: register_namespaces(xmlXPathContextPtr xpathCtx, const xmlChar* nsList) { 157: xmlChar* nsListDup; 158: xmlChar* prefix; 159: xmlChar* href; 160: xmlChar* next; 161: 162: assert(xpathCtx); 163: assert(nsList); 164: 165: nsListDup = xmlStrdup(nsList); 166: if(nsListDup == NULL) { 167: fprintf(stderr, "Error: unable to strdup namespaces list\n"); 168: return(-1); 169: } 170: 171: next = nsListDup; 172: while(next != NULL) { 173: /* skip spaces */ 174: while((*next) == ' ') next++; 175: if((*next) == '\0') break; 176: 177: /* find prefix */ 178: prefix = next; 179: next = (xmlChar*)xmlStrchr(next, '='); 180: if(next == NULL) { 181: fprintf(stderr,"Error: invalid namespaces list format\n"); 182: xmlFree(nsListDup); 183: return(-1); 184: } 185: *(next++) = '\0'; 186: 187: /* find href */ 188: href = next; 189: next = (xmlChar*)xmlStrchr(next, ' '); 190: if(next != NULL) { 191: *(next++) = '\0'; 192: } 193: 194: /* do register namespace */ 195: if(xmlXPathRegisterNs(xpathCtx, prefix, href) != 0) { 196: fprintf(stderr,"Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", prefix, href); 197: xmlFree(nsListDup); 198: return(-1); 199: } 200: } 201: 202: xmlFree(nsListDup); 203: return(0); 204: } 205: 206: void print_xmlAttrs(xmlAttrPtr attrs, FILE*output) { 207: xmlAttrPtr p = attrs; 208: if (!p) { 209: return; 210: } 211: for (; p; p=p->next) { 212: if (p->ns) { 213: fprintf(output, " (%s):%s=\"%s\"", p->ns->href, p->name, p->children->content); 214: } else { 215: fprintf(output, " %s=\"%s\"", p->name, p->children->content); 216: } 217: } 218: } 219: 220: /** 221: * print_xpath_nodes: 222: * @nodes: the nodes set. 223: * @output: the output file handle. 224: * 225: * Prints the @nodes content to @output. 226: */ 227: void 228: print_xpath_nodes(xmlNodeSetPtr nodes, FILE* output) { 229: xmlNodePtr cur; 230: int size; 231: int i; 232: 233: assert(output); 234: size = (nodes) ? nodes->nodeNr : 0; 235: 236: fprintf(output, "Result (%d nodes):\n", size); 237: for(i = 0; i < size; ++i) { 238: assert(nodes->nodeTab[i]); 239: 240: if(nodes->nodeTab[i]->type == XML_NAMESPACE_DECL) { 241: xmlNsPtr ns; 242: 243: ns = (xmlNsPtr)nodes->nodeTab[i]; 244: cur = (xmlNodePtr)ns->next; 245: if(cur->ns) { 246: fprintf(output, "= namespace \"%s\"=\"%s\" for node %s:%s\n", 247: ns->prefix, ns->href, cur->ns->href, cur->name); 248: } else { 249: fprintf(output, "= namespace \"%s\"=\"%s\" for node %s\n", 250: ns->prefix, ns->href, cur->name); 251: } 252: } else 253: if(nodes->nodeTab[i]->type == XML_ELEMENT_NODE) { 254: cur = nodes->nodeTab[i]; 255: if(cur->ns) { 256: // fprintf(output, "= element node \"%s:%s\"\n", 257: fprintf(output, "<(%s):%s", cur->ns->href, cur->name); 258: if (cur->properties) { 259: print_xmlAttrs(cur->properties, output); 260: } 261: fprintf(output, "/>\n"); 262: } else { 263: fprintf(output, "<%s", cur->name); 264: if (cur->properties) { 265: print_xmlAttrs(cur->properties, output); 266: } 267: fprintf(output, "/>\n"); 268: } 269: } else { 270: cur = nodes->nodeTab[i]; 271: switch (cur->type) { 272: case 3: 273: //fprintf(output, "text\n"); 274: if (cur->content) { 275: fprintf(output, "%s\n", cur->content); 276: } 277: break; 278: case 2: 279: //fprintf(output, "attribute\n"); 280: if (cur->children && cur->children->content) { 281: fprintf(output, "%s\n", cur->children->content); 282: } 283: } 284: } 285: } 286: } 287: 288: #else 289: int main(void) { 290: fprintf(stderr, "XPath support not compiled in\n"); 291: exit(1); 292: } 293: #endif
KAKU PROJECT (2009) |