xpath1.c

最終更新:2009/11/20

xpath1.c

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
Copyright (C) KAKU PROJECT (2009)KAKU PROJECT (2009)