1
0
mirror of https://gitlab.gnome.org/GNOME/libxml2.git synced 2025-03-16 02:50:07 +03:00
libxml2/doc/examples/xpath2.c
Daniel Richard G 6842ee810e More cleanups to the documentation part of libxml2
doc/Makefile.am:

* Build what's in doc/ before doc/devhelp/, as the dependency graph flows
   that way

* Add "--path $(srcdir)" so that xsltproc can find DTDs in srcdir

* Replaced $(top_srcdir)/doc with an equivalent $(srcdir)

* Qualified libxml2-api.xml with $(srcdir) as it's always generated there

* Rewrote the dependencies for libxml2-api.xml so that xmlversion.h
   doesn't throw everything off

doc/devhelp/Makefile.am:

* Use Automake constructs to install the HTML files instead of an
   install-data-local rule

* Reorganized the file a bit (hello whitespace!)

* EXTRA_DIST doesn't need to list so many files now that dist_devhelp_DATA
   is being used

* Only print "Rebuilding devhelp files" if rebuilding is actually
   occurring

doc/examples/index.py:

* Make the "this file is auto-generated" banner more prominent

* Autotools updates: Use AM_CPPFLAGS/AM_CFLAGS instead of INCLUDES

* Got rid of DEPS as it's not needed (Automake already sees the dependency
   on libxml2.la by way of LDADD(S))

* Replaced LDADDS with LDADD, which is applied to all programs listed
   in the file. Since all the test programs have the same link
   dependencies, this way is more concise yet equivalent.

* Remove the *.tmp files via "make clean" instead of having the test
   programs do it themselves (more on this later)

* Invoke index.py in srcdir, as it pretty much needs to run there

* Restructured the index.html rule so that only the xmllint invocation is
   allowed to fail

* Use $(MKDIR_P) instead of $(mkinstalldirs), $(VAR) instead of @VAR@

* Remove symlinks for test?.xml in an out-of-source build

* Sort lists for neatness

* Better formatting for EXTRA_DIST and noinst_PROGRAMS variables

* Simplified the Automake bits printed for each program: *_LDFLAGS doesn't
   need to be specified as it's empty anyway, *_DEPENDENCIES is redundant,
   *_LDADD isn't needed due to the global LDADD

* Added a bit that symlinks in test?.xml from srcdir in out-of-source
   builds. This allows the reader4 test to read these files in the current
   directory, which ensures that the output always looks the same (i.e.
   does not contain references to srcdir)

* Don't hide the test program invocation (or else it's hard to tell which
   test failed), and don't use superfluous parentheses

* NOTE: If you check in these changes, be sure to run this script and also
   check in the updated files that it generates!

doc/examples/*.c:

* Updated the test: lines so that

   + "&&" is used to separate commands instead of ";" so that errors are
     not masked

   + reference files are qualified with $(srcdir)/

   + no "rm" takes place -- these are a problem because (1) if a test
     fails, it's useful to have the output file ready for inspection; (2)
     the "rm" invocation masks a potential non-zero exit status from diff

     (This is why I added the CLEANFILES line above)

doc/examples/io1.res:

* Updated this ref file so that the test passes. (This is correct, right?)

doc/examples/reader4.res:

* Changed this back to its original form, as the symlinking of test?.xml
   means this file no longer has to contain path prefixes on the filenames

doc/examples/testWriter.c:

* Changed the output filenames to *.tmp instead of *.res, partly for
   consistency, partly to not have to add special cases to CLEANFILES

doc/examples/xpath1.c:

* Removed the "./" prefix on the test invocation, which is redundant as
   index.py already adds one
2012-08-17 09:58:38 +08:00

191 lines
5.2 KiB
C

/**
* section: XPath
* synopsis: Load a document, locate subelements with XPath, modify
* said elements and save the resulting document.
* purpose: Shows how to make a full round-trip from a load/edit/save
* usage: xpath2 <xml-file> <xpath-expr> <new-value>
* test: xpath2 test3.xml '//discarded' discarded > xpath2.tmp && diff xpath2.tmp $(srcdir)/xpath2.res
* author: Aleksey Sanin and Daniel Veillard
* copy: see Copyright for the status of this software.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <libxml/tree.h>
#include <libxml/parser.h>
#include <libxml/xpath.h>
#include <libxml/xpathInternals.h>
#if defined(LIBXML_XPATH_ENABLED) && defined(LIBXML_SAX1_ENABLED) && \
defined(LIBXML_OUTPUT_ENABLED)
static void usage(const char *name);
static int example4(const char *filename, const xmlChar * xpathExpr,
const xmlChar * value);
static void update_xpath_nodes(xmlNodeSetPtr nodes, const xmlChar * value);
int
main(int argc, char **argv) {
/* Parse command line and process file */
if (argc != 4) {
fprintf(stderr, "Error: wrong number of arguments.\n");
usage(argv[0]);
return(-1);
}
/* Init libxml */
xmlInitParser();
LIBXML_TEST_VERSION
/* Do the main job */
if (example4(argv[1], BAD_CAST argv[2], BAD_CAST argv[3])) {
usage(argv[0]);
return(-1);
}
/* Shutdown libxml */
xmlCleanupParser();
/*
* this is to debug memory for regression tests
*/
xmlMemoryDump();
return 0;
}
/**
* usage:
* @name: the program name.
*
* Prints usage information.
*/
static void
usage(const char *name) {
assert(name);
fprintf(stderr, "Usage: %s <xml-file> <xpath-expr> <value>\n", name);
}
/**
* example4:
* @filename: the input XML filename.
* @xpathExpr: the xpath expression for evaluation.
* @value: the new node content.
*
* Parses input XML file, evaluates XPath expression and update the nodes
* then print the result.
*
* Returns 0 on success and a negative value otherwise.
*/
static int
example4(const char* filename, const xmlChar* xpathExpr, const xmlChar* value) {
xmlDocPtr doc;
xmlXPathContextPtr xpathCtx;
xmlXPathObjectPtr xpathObj;
assert(filename);
assert(xpathExpr);
assert(value);
/* Load XML document */
doc = xmlParseFile(filename);
if (doc == NULL) {
fprintf(stderr, "Error: unable to parse file \"%s\"\n", filename);
return(-1);
}
/* Create xpath evaluation context */
xpathCtx = xmlXPathNewContext(doc);
if(xpathCtx == NULL) {
fprintf(stderr,"Error: unable to create new XPath context\n");
xmlFreeDoc(doc);
return(-1);
}
/* Evaluate xpath expression */
xpathObj = xmlXPathEvalExpression(xpathExpr, xpathCtx);
if(xpathObj == NULL) {
fprintf(stderr,"Error: unable to evaluate xpath expression \"%s\"\n", xpathExpr);
xmlXPathFreeContext(xpathCtx);
xmlFreeDoc(doc);
return(-1);
}
/* update selected nodes */
update_xpath_nodes(xpathObj->nodesetval, value);
/* Cleanup of XPath data */
xmlXPathFreeObject(xpathObj);
xmlXPathFreeContext(xpathCtx);
/* dump the resulting document */
xmlDocDump(stdout, doc);
/* free the document */
xmlFreeDoc(doc);
return(0);
}
/**
* update_xpath_nodes:
* @nodes: the nodes set.
* @value: the new value for the node(s)
*
* Prints the @nodes content to @output.
*/
static void
update_xpath_nodes(xmlNodeSetPtr nodes, const xmlChar* value) {
int size;
int i;
assert(value);
size = (nodes) ? nodes->nodeNr : 0;
/*
* NOTE: the nodes are processed in reverse order, i.e. reverse document
* order because xmlNodeSetContent can actually free up descendant
* of the node and such nodes may have been selected too ! Handling
* in reverse order ensure that descendant are accessed first, before
* they get removed. Mixing XPath and modifications on a tree must be
* done carefully !
*/
for(i = size - 1; i >= 0; i--) {
assert(nodes->nodeTab[i]);
xmlNodeSetContent(nodes->nodeTab[i], value);
/*
* All the elements returned by an XPath query are pointers to
* elements from the tree *except* namespace nodes where the XPath
* semantic is different from the implementation in libxml2 tree.
* As a result when a returned node set is freed when
* xmlXPathFreeObject() is called, that routine must check the
* element type. But node from the returned set may have been removed
* by xmlNodeSetContent() resulting in access to freed data.
* This can be exercised by running
* valgrind xpath2 test3.xml '//discarded' discarded
* There is 2 ways around it:
* - make a copy of the pointers to the nodes from the result set
* then call xmlXPathFreeObject() and then modify the nodes
* or
* - remove the reference to the modified nodes from the node set
* as they are processed, if they are not namespace nodes.
*/
if (nodes->nodeTab[i]->type != XML_NAMESPACE_DECL)
nodes->nodeTab[i] = NULL;
}
}
#else
int main(void) {
fprintf(stderr, "XPath support not compiled in\n");
exit(1);
}
#endif