File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / libxml2 / doc / examples / xpath2.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Sun Jun 15 19:53:36 2014 UTC (10 years, 3 months ago) by misho
Branches: libxml2, MAIN
CVS tags: v2_9_1p0, v2_9_1, HEAD
libxml2 2.9.1

    1: /** 
    2:  * section: 	XPath
    3:  * synopsis: 	Load a document, locate subelements with XPath, modify
    4:  *              said elements and save the resulting document.
    5:  * purpose: 	Shows how to make a full round-trip from a load/edit/save
    6:  * usage:	xpath2 <xml-file> <xpath-expr> <new-value>
    7:  * test:	xpath2 test3.xml '//discarded' discarded > xpath2.tmp && diff xpath2.tmp $(srcdir)/xpath2.res
    8:  * author: 	Aleksey Sanin and Daniel Veillard
    9:  * copy: 	see Copyright for the status of this software.
   10:  */
   11: #include <stdlib.h>
   12: #include <stdio.h>
   13: #include <string.h>
   14: #include <assert.h>
   15: 
   16: #include <libxml/tree.h>
   17: #include <libxml/parser.h>
   18: #include <libxml/xpath.h>
   19: #include <libxml/xpathInternals.h>
   20: 
   21: #if defined(LIBXML_XPATH_ENABLED) && defined(LIBXML_SAX1_ENABLED) && \
   22:     defined(LIBXML_OUTPUT_ENABLED)
   23: 
   24: 
   25: static void usage(const char *name);
   26: static int example4(const char *filename, const xmlChar * xpathExpr,
   27:                     const xmlChar * value);
   28: static void update_xpath_nodes(xmlNodeSetPtr nodes, const xmlChar * value);
   29: 
   30: 
   31: int 
   32: main(int argc, char **argv) {
   33:     /* Parse command line and process file */
   34:     if (argc != 4) {
   35: 	fprintf(stderr, "Error: wrong number of arguments.\n");
   36: 	usage(argv[0]);
   37: 	return(-1);
   38:     } 
   39:     
   40:     /* Init libxml */     
   41:     xmlInitParser();
   42:     LIBXML_TEST_VERSION
   43: 
   44:     /* Do the main job */
   45:     if (example4(argv[1], BAD_CAST argv[2], BAD_CAST argv[3])) {
   46: 	usage(argv[0]);
   47: 	return(-1);
   48:     }
   49: 
   50:     /* Shutdown libxml */
   51:     xmlCleanupParser();
   52:     
   53:     /*
   54:      * this is to debug memory for regression tests
   55:      */
   56:     xmlMemoryDump();
   57:     return 0;
   58: }
   59: 
   60: /**
   61:  * usage:
   62:  * @name:		the program name.
   63:  *
   64:  * Prints usage information.
   65:  */
   66: static void 
   67: usage(const char *name) {
   68:     assert(name);
   69:     
   70:     fprintf(stderr, "Usage: %s <xml-file> <xpath-expr> <value>\n", name);
   71: }
   72: 
   73: /**
   74:  * example4:
   75:  * @filename:		the input XML filename.
   76:  * @xpathExpr:		the xpath expression for evaluation.
   77:  * @value:		the new node content.
   78:  *
   79:  * Parses input XML file, evaluates XPath expression and update the nodes
   80:  * then print the result.
   81:  *
   82:  * Returns 0 on success and a negative value otherwise.
   83:  */
   84: static int 
   85: example4(const char* filename, const xmlChar* xpathExpr, const xmlChar* value) {
   86:     xmlDocPtr doc;
   87:     xmlXPathContextPtr xpathCtx; 
   88:     xmlXPathObjectPtr xpathObj; 
   89:     
   90:     assert(filename);
   91:     assert(xpathExpr);
   92:     assert(value);
   93: 
   94:     /* Load XML document */
   95:     doc = xmlParseFile(filename);
   96:     if (doc == NULL) {
   97: 	fprintf(stderr, "Error: unable to parse file \"%s\"\n", filename);
   98: 	return(-1);
   99:     }
  100: 
  101:     /* Create xpath evaluation context */
  102:     xpathCtx = xmlXPathNewContext(doc);
  103:     if(xpathCtx == NULL) {
  104:         fprintf(stderr,"Error: unable to create new XPath context\n");
  105:         xmlFreeDoc(doc); 
  106:         return(-1);
  107:     }
  108:     
  109:     /* Evaluate xpath expression */
  110:     xpathObj = xmlXPathEvalExpression(xpathExpr, xpathCtx);
  111:     if(xpathObj == NULL) {
  112:         fprintf(stderr,"Error: unable to evaluate xpath expression \"%s\"\n", xpathExpr);
  113:         xmlXPathFreeContext(xpathCtx); 
  114:         xmlFreeDoc(doc); 
  115:         return(-1);
  116:     }
  117: 
  118:     /* update selected nodes */
  119:     update_xpath_nodes(xpathObj->nodesetval, value);
  120: 
  121:     
  122:     /* Cleanup of XPath data */
  123:     xmlXPathFreeObject(xpathObj);
  124:     xmlXPathFreeContext(xpathCtx); 
  125: 
  126:     /* dump the resulting document */
  127:     xmlDocDump(stdout, doc);
  128: 
  129: 
  130:     /* free the document */
  131:     xmlFreeDoc(doc); 
  132:     
  133:     return(0);
  134: }
  135: 
  136: /**
  137:  * update_xpath_nodes:
  138:  * @nodes:		the nodes set.
  139:  * @value:		the new value for the node(s)
  140:  *
  141:  * Prints the @nodes content to @output.
  142:  */
  143: static void
  144: update_xpath_nodes(xmlNodeSetPtr nodes, const xmlChar* value) {
  145:     int size;
  146:     int i;
  147:     
  148:     assert(value);
  149:     size = (nodes) ? nodes->nodeNr : 0;
  150:     
  151:     /*
  152:      * NOTE: the nodes are processed in reverse order, i.e. reverse document
  153:      *       order because xmlNodeSetContent can actually free up descendant
  154:      *       of the node and such nodes may have been selected too ! Handling
  155:      *       in reverse order ensure that descendant are accessed first, before
  156:      *       they get removed. Mixing XPath and modifications on a tree must be
  157:      *       done carefully !
  158:      */
  159:     for(i = size - 1; i >= 0; i--) {
  160: 	assert(nodes->nodeTab[i]);
  161: 	
  162: 	xmlNodeSetContent(nodes->nodeTab[i], value);
  163: 	/*
  164: 	 * All the elements returned by an XPath query are pointers to
  165: 	 * elements from the tree *except* namespace nodes where the XPath
  166: 	 * semantic is different from the implementation in libxml2 tree.
  167: 	 * As a result when a returned node set is freed when
  168: 	 * xmlXPathFreeObject() is called, that routine must check the
  169: 	 * element type. But node from the returned set may have been removed
  170: 	 * by xmlNodeSetContent() resulting in access to freed data.
  171: 	 * This can be exercised by running
  172: 	 *       valgrind xpath2 test3.xml '//discarded' discarded
  173: 	 * There is 2 ways around it:
  174: 	 *   - make a copy of the pointers to the nodes from the result set 
  175: 	 *     then call xmlXPathFreeObject() and then modify the nodes
  176: 	 * or
  177: 	 *   - remove the reference to the modified nodes from the node set
  178: 	 *     as they are processed, if they are not namespace nodes.
  179: 	 */
  180: 	if (nodes->nodeTab[i]->type != XML_NAMESPACE_DECL)
  181: 	    nodes->nodeTab[i] = NULL;
  182:     }
  183: }
  184: 
  185: #else
  186: int main(void) {
  187:     fprintf(stderr, "XPath support not compiled in\n");
  188:     exit(1);
  189: }
  190: #endif

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>