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) |