Annotation of embedaddon/libxml2/doc/examples/xpath2.c, revision 1.1.1.1

1.1       misho       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 xpath2.res ; rm xpath2.tmp
                      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>