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>