Annotation of embedaddon/libxml2/doc/examples/xpath2.c, revision 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>