generated from sethub/template
[libxml2]Add libxml2 library
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
/gjobread
|
||||
/io1
|
||||
/io2
|
||||
/parse1
|
||||
/parse2
|
||||
/parse3
|
||||
/parse4
|
||||
/reader1
|
||||
/reader2
|
||||
/reader3
|
||||
/reader4
|
||||
/testWriter
|
||||
/tree1
|
||||
/tree2
|
||||
/xpath1
|
||||
/xpath2
|
||||
@@ -0,0 +1,44 @@
|
||||
EXTRA_DIST = \
|
||||
gjobs.xml \
|
||||
meson.build \
|
||||
test1.xml \
|
||||
test2.xml \
|
||||
test3.xml
|
||||
|
||||
check_PROGRAMS = \
|
||||
gjobread \
|
||||
io1 \
|
||||
io2 \
|
||||
parse1 \
|
||||
parse2 \
|
||||
parse3 \
|
||||
parse4 \
|
||||
reader1 \
|
||||
reader2 \
|
||||
reader3 \
|
||||
reader4 \
|
||||
testWriter \
|
||||
tree1 \
|
||||
tree2 \
|
||||
xpath1 \
|
||||
xpath2
|
||||
|
||||
AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include
|
||||
LDADD = $(top_builddir)/libxml2.la
|
||||
|
||||
gjobread_SOURCES=gjobread.c
|
||||
io1_SOURCES = io1.c
|
||||
io2_SOURCES = io2.c
|
||||
parse1_SOURCES = parse1.c
|
||||
parse2_SOURCES = parse2.c
|
||||
parse3_SOURCES = parse3.c
|
||||
parse4_SOURCES = parse4.c
|
||||
reader1_SOURCES = reader1.c
|
||||
reader2_SOURCES = reader2.c
|
||||
reader3_SOURCES = reader3.c
|
||||
reader4_SOURCES = reader4.c
|
||||
testWriter_SOURCES = testWriter.c
|
||||
tree1_SOURCES = tree1.c
|
||||
tree2_SOURCES = tree2.c
|
||||
xpath1_SOURCES = xpath1.c
|
||||
xpath2_SOURCES = xpath2.c
|
||||
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
* gjobread.c : a small test program for gnome jobs XML format
|
||||
*
|
||||
* See Copyright for the status of this software.
|
||||
*
|
||||
* Daniel.Veillard@w3.org
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/*
|
||||
* This example should compile and run indifferently with libxml-1.8.8 +
|
||||
* and libxml2-2.1.0 +
|
||||
* Check the COMPAT comments below
|
||||
*/
|
||||
|
||||
/*
|
||||
* COMPAT using xml-config --cflags to get the include path this will
|
||||
* work with both
|
||||
*/
|
||||
#include <libxml/xmlmemory.h>
|
||||
#include <libxml/parser.h>
|
||||
|
||||
#define DEBUG(x) printf(x)
|
||||
|
||||
/*
|
||||
* A person record
|
||||
* an xmlChar * is really an UTF8 encoded char string (0 terminated)
|
||||
*/
|
||||
typedef struct person {
|
||||
xmlChar *name;
|
||||
xmlChar *email;
|
||||
xmlChar *company;
|
||||
xmlChar *organisation;
|
||||
xmlChar *smail;
|
||||
xmlChar *webPage;
|
||||
xmlChar *phone;
|
||||
} person, *personPtr;
|
||||
|
||||
/*
|
||||
* And the code needed to parse it
|
||||
*/
|
||||
static personPtr
|
||||
parsePerson(xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur) {
|
||||
personPtr ret = NULL;
|
||||
|
||||
DEBUG("parsePerson\n");
|
||||
/*
|
||||
* allocate the struct
|
||||
*/
|
||||
ret = (personPtr) malloc(sizeof(person));
|
||||
if (ret == NULL) {
|
||||
fprintf(stderr,"out of memory\n");
|
||||
return(NULL);
|
||||
}
|
||||
memset(ret, 0, sizeof(person));
|
||||
|
||||
/* We don't care what the top level element name is */
|
||||
/* COMPAT xmlChildrenNode is a macro unifying libxml1 and libxml2 names */
|
||||
cur = cur->xmlChildrenNode;
|
||||
while (cur != NULL) {
|
||||
if ((!xmlStrcmp(cur->name, (const xmlChar *)"Person")) &&
|
||||
(cur->ns == ns))
|
||||
ret->name = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
|
||||
if ((!xmlStrcmp(cur->name, (const xmlChar *)"Email")) &&
|
||||
(cur->ns == ns))
|
||||
ret->email = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* and to print it
|
||||
*/
|
||||
static void
|
||||
printPerson(personPtr cur) {
|
||||
if (cur == NULL) return;
|
||||
printf("------ Person\n");
|
||||
if (cur->name) printf(" name: %s\n", cur->name);
|
||||
if (cur->email) printf(" email: %s\n", cur->email);
|
||||
if (cur->company) printf(" company: %s\n", cur->company);
|
||||
if (cur->organisation) printf(" organisation: %s\n", cur->organisation);
|
||||
if (cur->smail) printf(" smail: %s\n", cur->smail);
|
||||
if (cur->webPage) printf(" Web: %s\n", cur->webPage);
|
||||
if (cur->phone) printf(" phone: %s\n", cur->phone);
|
||||
printf("------\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* a Description for a Job
|
||||
*/
|
||||
typedef struct job {
|
||||
xmlChar *projectID;
|
||||
xmlChar *application;
|
||||
xmlChar *category;
|
||||
personPtr contact;
|
||||
int nbDevelopers;
|
||||
personPtr developers[100]; /* using dynamic alloc is left as an exercise */
|
||||
} job, *jobPtr;
|
||||
|
||||
/*
|
||||
* And the code needed to parse it
|
||||
*/
|
||||
static jobPtr
|
||||
parseJob(xmlDocPtr doc, xmlNsPtr ns, xmlNodePtr cur) {
|
||||
jobPtr ret = NULL;
|
||||
|
||||
DEBUG("parseJob\n");
|
||||
/*
|
||||
* allocate the struct
|
||||
*/
|
||||
ret = (jobPtr) malloc(sizeof(job));
|
||||
if (ret == NULL) {
|
||||
fprintf(stderr,"out of memory\n");
|
||||
return(NULL);
|
||||
}
|
||||
memset(ret, 0, sizeof(job));
|
||||
|
||||
/* We don't care what the top level element name is */
|
||||
cur = cur->xmlChildrenNode;
|
||||
while (cur != NULL) {
|
||||
|
||||
if ((!xmlStrcmp(cur->name, (const xmlChar *) "Project")) &&
|
||||
(cur->ns == ns)) {
|
||||
ret->projectID = xmlGetProp(cur, (const xmlChar *) "ID");
|
||||
if (ret->projectID == NULL) {
|
||||
fprintf(stderr, "Project has no ID\n");
|
||||
}
|
||||
}
|
||||
if ((!xmlStrcmp(cur->name, (const xmlChar *) "Application")) &&
|
||||
(cur->ns == ns))
|
||||
ret->application =
|
||||
xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
|
||||
if ((!xmlStrcmp(cur->name, (const xmlChar *) "Category")) &&
|
||||
(cur->ns == ns))
|
||||
ret->category =
|
||||
xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
|
||||
if ((!xmlStrcmp(cur->name, (const xmlChar *) "Contact")) &&
|
||||
(cur->ns == ns))
|
||||
ret->contact = parsePerson(doc, ns, cur);
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* and to print it
|
||||
*/
|
||||
static void
|
||||
printJob(jobPtr cur) {
|
||||
int i;
|
||||
|
||||
if (cur == NULL) return;
|
||||
printf("======= Job\n");
|
||||
if (cur->projectID != NULL) printf("projectID: %s\n", cur->projectID);
|
||||
if (cur->application != NULL) printf("application: %s\n", cur->application);
|
||||
if (cur->category != NULL) printf("category: %s\n", cur->category);
|
||||
if (cur->contact != NULL) printPerson(cur->contact);
|
||||
printf("%d developers\n", cur->nbDevelopers);
|
||||
|
||||
for (i = 0;i < cur->nbDevelopers;i++) printPerson(cur->developers[i]);
|
||||
printf("======= \n");
|
||||
}
|
||||
|
||||
/*
|
||||
* A pool of Gnome Jobs
|
||||
*/
|
||||
typedef struct gjob {
|
||||
int nbJobs;
|
||||
jobPtr jobs[500]; /* using dynamic alloc is left as an exercise */
|
||||
} gJob, *gJobPtr;
|
||||
|
||||
|
||||
static gJobPtr
|
||||
parseGjobFile(char *filename) {
|
||||
xmlDocPtr doc;
|
||||
gJobPtr ret;
|
||||
jobPtr curjob;
|
||||
xmlNsPtr ns;
|
||||
xmlNodePtr cur;
|
||||
|
||||
/*
|
||||
* build an XML tree from a the file;
|
||||
*/
|
||||
doc = xmlReadFile(filename, NULL, XML_PARSE_NOBLANKS);
|
||||
if (doc == NULL) return(NULL);
|
||||
|
||||
/*
|
||||
* Check the document is of the right kind
|
||||
*/
|
||||
|
||||
cur = xmlDocGetRootElement(doc);
|
||||
if (cur == NULL) {
|
||||
fprintf(stderr,"empty document\n");
|
||||
xmlFreeDoc(doc);
|
||||
return(NULL);
|
||||
}
|
||||
ns = xmlSearchNsByHref(doc, cur,
|
||||
(const xmlChar *) "http://www.gnome.org/some-location");
|
||||
if (ns == NULL) {
|
||||
fprintf(stderr,
|
||||
"document of the wrong type, GJob Namespace not found\n");
|
||||
xmlFreeDoc(doc);
|
||||
return(NULL);
|
||||
}
|
||||
if (xmlStrcmp(cur->name, (const xmlChar *) "Helping")) {
|
||||
fprintf(stderr,"document of the wrong type, root node != Helping");
|
||||
xmlFreeDoc(doc);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate the structure to be returned.
|
||||
*/
|
||||
ret = (gJobPtr) malloc(sizeof(gJob));
|
||||
if (ret == NULL) {
|
||||
fprintf(stderr,"out of memory\n");
|
||||
xmlFreeDoc(doc);
|
||||
return(NULL);
|
||||
}
|
||||
memset(ret, 0, sizeof(gJob));
|
||||
|
||||
/*
|
||||
* Now, walk the tree.
|
||||
*/
|
||||
/* First level we expect just Jobs */
|
||||
cur = cur->xmlChildrenNode;
|
||||
while ( cur && xmlIsBlankNode ( cur ) ) {
|
||||
cur = cur -> next;
|
||||
}
|
||||
if ( cur == 0 ) {
|
||||
xmlFreeDoc(doc);
|
||||
free(ret);
|
||||
return ( NULL );
|
||||
}
|
||||
if ((xmlStrcmp(cur->name, (const xmlChar *) "Jobs")) || (cur->ns != ns)) {
|
||||
fprintf(stderr,"document of the wrong type, was '%s', Jobs expected",
|
||||
cur->name);
|
||||
fprintf(stderr,"xmlDocDump follows\n");
|
||||
#ifdef LIBXML_OUTPUT_ENABLED
|
||||
xmlDocDump ( stderr, doc );
|
||||
fprintf(stderr,"xmlDocDump finished\n");
|
||||
#endif /* LIBXML_OUTPUT_ENABLED */
|
||||
xmlFreeDoc(doc);
|
||||
free(ret);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/* Second level is a list of Job, but be laxist */
|
||||
cur = cur->xmlChildrenNode;
|
||||
while (cur != NULL) {
|
||||
if ((!xmlStrcmp(cur->name, (const xmlChar *) "Job")) &&
|
||||
(cur->ns == ns)) {
|
||||
curjob = parseJob(doc, ns, cur);
|
||||
if (curjob != NULL)
|
||||
ret->jobs[ret->nbJobs++] = curjob;
|
||||
if (ret->nbJobs >= 500) break;
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
return(ret);
|
||||
}
|
||||
|
||||
static void
|
||||
handleGjob(gJobPtr cur) {
|
||||
int i;
|
||||
|
||||
/*
|
||||
* Do whatever you want and free the structure.
|
||||
*/
|
||||
printf("%d Jobs registered\n", cur->nbJobs);
|
||||
for (i = 0; i < cur->nbJobs; i++) printJob(cur->jobs[i]);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int i;
|
||||
gJobPtr cur;
|
||||
|
||||
/* COMPAT: Do not generate nodes for formatting spaces */
|
||||
LIBXML_TEST_VERSION
|
||||
|
||||
for (i = 1; i < argc ; i++) {
|
||||
cur = parseGjobFile(argv[i]);
|
||||
if ( cur )
|
||||
handleGjob(cur);
|
||||
else
|
||||
fprintf( stderr, "Error parsing file '%s'\n", argv[i]);
|
||||
|
||||
}
|
||||
|
||||
/* Clean up everything else before quitting. */
|
||||
xmlCleanupParser();
|
||||
|
||||
return(0);
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<?xml version="1.0"?>
|
||||
<gjob:Helping xmlns:gjob="http://www.gnome.org/some-location">
|
||||
<gjob:Jobs>
|
||||
|
||||
<gjob:Job>
|
||||
<gjob:Project ID="3"/>
|
||||
<gjob:Application>GBackup</gjob:Application>
|
||||
<gjob:Category>Development</gjob:Category>
|
||||
|
||||
<gjob:Update>
|
||||
<gjob:Status>Open</gjob:Status>
|
||||
<gjob:Modified>Mon, 07 Jun 1999 20:27:45 -0400 MET DST</gjob:Modified>
|
||||
<gjob:Salary>USD 0.00</gjob:Salary>
|
||||
</gjob:Update>
|
||||
|
||||
<gjob:Developers>
|
||||
<gjob:Developer>
|
||||
</gjob:Developer>
|
||||
</gjob:Developers>
|
||||
|
||||
<gjob:Contact>
|
||||
<gjob:Person>Nathan Clemons</gjob:Person>
|
||||
<gjob:Email>nathan@windsofstorm.net</gjob:Email>
|
||||
<gjob:Company>
|
||||
</gjob:Company>
|
||||
<gjob:Organisation>
|
||||
</gjob:Organisation>
|
||||
<gjob:Webpage>
|
||||
</gjob:Webpage>
|
||||
<gjob:Snailmail>
|
||||
</gjob:Snailmail>
|
||||
<gjob:Phone>
|
||||
</gjob:Phone>
|
||||
</gjob:Contact>
|
||||
|
||||
<gjob:Requirements>
|
||||
The program should be released as free software, under the GPL.
|
||||
</gjob:Requirements>
|
||||
|
||||
<gjob:Skills>
|
||||
</gjob:Skills>
|
||||
|
||||
<gjob:Details>
|
||||
A GNOME based system that will allow a superuser to configure
|
||||
compressed and uncompressed files and/or file systems to be backed
|
||||
up with a supported media in the system. This should be able to
|
||||
perform via find commands generating a list of files that are passed
|
||||
to tar, dd, cpio, cp, gzip, etc., to be directed to the tape machine
|
||||
or via operations performed on the filesystem itself. Email
|
||||
notification and GUI status display very important.
|
||||
</gjob:Details>
|
||||
|
||||
</gjob:Job>
|
||||
|
||||
</gjob:Jobs>
|
||||
</gjob:Helping>
|
||||
|
||||
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* icu.c: Example how to use ICU for character encoding conversion
|
||||
*
|
||||
* This example shows how to use ICU by installing a custom character
|
||||
* encoding converter with xmlCtxtSetCharEncConvImpl, available
|
||||
* since libxml2 2.14.
|
||||
*
|
||||
* This approach makes it possible to use ICU even if libxml2 is
|
||||
* compiled without ICU support. It also makes sure that *only* ICU
|
||||
* is used. Many Linux distros currently ship libxml2 with support
|
||||
* for both ICU and iconv which makes the library's behavior hard to
|
||||
* predict.
|
||||
*
|
||||
* The long-term plan is to make libxml2 only support a single
|
||||
* conversion library internally (iconv on POSIX).
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <libxml/parser.h>
|
||||
#include <unicode/ucnv.h>
|
||||
|
||||
#define ICU_PIVOT_BUF_SIZE 1024
|
||||
|
||||
typedef struct {
|
||||
UConverter *uconv; /* for conversion between an encoding and UTF-16 */
|
||||
UConverter *utf8; /* for conversion between UTF-8 and UTF-16 */
|
||||
UChar *pivot_source;
|
||||
UChar *pivot_target;
|
||||
int isInput;
|
||||
UChar pivot_buf[ICU_PIVOT_BUF_SIZE];
|
||||
} myConvCtxt;
|
||||
|
||||
static xmlCharEncError
|
||||
icuConvert(void *vctxt, unsigned char *out, int *outlen,
|
||||
const unsigned char *in, int *inlen, int flush) {
|
||||
myConvCtxt *cd = vctxt;
|
||||
const char *ucv_in = (const char *) in;
|
||||
char *ucv_out = (char *) out;
|
||||
UConverter *target, *source;
|
||||
UErrorCode err = U_ZERO_ERROR;
|
||||
int ret;
|
||||
|
||||
if ((out == NULL) || (outlen == NULL) || (inlen == NULL) || (in == NULL)) {
|
||||
if (outlen != NULL)
|
||||
*outlen = 0;
|
||||
return XML_ENC_ERR_INTERNAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* The ICU API can consume input, including partial sequences,
|
||||
* even if the output buffer would overflow. The remaining input
|
||||
* must be processed by calling ucnv_convertEx with a possibly
|
||||
* empty input buffer.
|
||||
*/
|
||||
if (cd->isInput) {
|
||||
source = cd->uconv;
|
||||
target = cd->utf8;
|
||||
} else {
|
||||
source = cd->utf8;
|
||||
target = cd->uconv;
|
||||
}
|
||||
|
||||
ucnv_convertEx(target, source, &ucv_out, ucv_out + *outlen,
|
||||
&ucv_in, ucv_in + *inlen, cd->pivot_buf,
|
||||
&cd->pivot_source, &cd->pivot_target,
|
||||
cd->pivot_buf + ICU_PIVOT_BUF_SIZE,
|
||||
/* reset */ 0, flush, &err);
|
||||
|
||||
*inlen = ucv_in - (const char*) in;
|
||||
*outlen = ucv_out - (char *) out;
|
||||
|
||||
if (U_SUCCESS(err)) {
|
||||
ret = XML_ENC_ERR_SUCCESS;
|
||||
} else {
|
||||
switch (err) {
|
||||
case U_TRUNCATED_CHAR_FOUND:
|
||||
/* Should only happen with flush */
|
||||
ret = XML_ENC_ERR_INPUT;
|
||||
break;
|
||||
|
||||
case U_BUFFER_OVERFLOW_ERROR:
|
||||
ret = XML_ENC_ERR_SPACE;
|
||||
break;
|
||||
|
||||
case U_INVALID_CHAR_FOUND:
|
||||
case U_ILLEGAL_CHAR_FOUND:
|
||||
case U_ILLEGAL_ESCAPE_SEQUENCE:
|
||||
case U_UNSUPPORTED_ESCAPE_SEQUENCE:
|
||||
ret = XML_ENC_ERR_INPUT;
|
||||
break;
|
||||
|
||||
case U_MEMORY_ALLOCATION_ERROR:
|
||||
ret = XML_ENC_ERR_MEMORY;
|
||||
break;
|
||||
|
||||
default:
|
||||
ret = XML_ENC_ERR_INTERNAL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static xmlParserErrors
|
||||
icuOpen(const char* name, int isInput, myConvCtxt **out)
|
||||
{
|
||||
UErrorCode status;
|
||||
myConvCtxt *cd;
|
||||
|
||||
*out = NULL;
|
||||
|
||||
cd = xmlMalloc(sizeof(myConvCtxt));
|
||||
if (cd == NULL)
|
||||
return XML_ERR_NO_MEMORY;
|
||||
|
||||
cd->isInput = isInput;
|
||||
cd->pivot_source = cd->pivot_buf;
|
||||
cd->pivot_target = cd->pivot_buf;
|
||||
|
||||
status = U_ZERO_ERROR;
|
||||
cd->uconv = ucnv_open(name, &status);
|
||||
if (U_FAILURE(status))
|
||||
goto error;
|
||||
|
||||
status = U_ZERO_ERROR;
|
||||
if (isInput) {
|
||||
ucnv_setToUCallBack(cd->uconv, UCNV_TO_U_CALLBACK_STOP,
|
||||
NULL, NULL, NULL, &status);
|
||||
}
|
||||
else {
|
||||
ucnv_setFromUCallBack(cd->uconv, UCNV_FROM_U_CALLBACK_STOP,
|
||||
NULL, NULL, NULL, &status);
|
||||
}
|
||||
if (U_FAILURE(status))
|
||||
goto error;
|
||||
|
||||
status = U_ZERO_ERROR;
|
||||
cd->utf8 = ucnv_open("UTF-8", &status);
|
||||
if (U_FAILURE(status))
|
||||
goto error;
|
||||
|
||||
*out = cd;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
if (cd->uconv)
|
||||
ucnv_close(cd->uconv);
|
||||
xmlFree(cd);
|
||||
|
||||
if (status == U_FILE_ACCESS_ERROR)
|
||||
return XML_ERR_UNSUPPORTED_ENCODING;
|
||||
if (status == U_MEMORY_ALLOCATION_ERROR)
|
||||
return XML_ERR_NO_MEMORY;
|
||||
return XML_ERR_SYSTEM;
|
||||
}
|
||||
|
||||
static void
|
||||
icuClose(myConvCtxt *cd)
|
||||
{
|
||||
if (cd == NULL)
|
||||
return;
|
||||
ucnv_close(cd->uconv);
|
||||
ucnv_close(cd->utf8);
|
||||
xmlFree(cd);
|
||||
}
|
||||
|
||||
static void
|
||||
icuConvCtxtDtor(void *vctxt) {
|
||||
icuClose(vctxt);
|
||||
}
|
||||
|
||||
static xmlParserErrors
|
||||
icuConvImpl(void *vctxt, const char *name, xmlCharEncFlags flags,
|
||||
xmlCharEncodingHandler **result) {
|
||||
xmlCharEncConvFunc inFunc = NULL, outFunc = NULL;
|
||||
myConvCtxt *inputCtxt = NULL;
|
||||
myConvCtxt *outputCtxt = NULL;
|
||||
xmlParserErrors ret;
|
||||
|
||||
if (flags & XML_ENC_INPUT) {
|
||||
ret = icuOpen(name, 1, &inputCtxt);
|
||||
if (ret != 0)
|
||||
goto error;
|
||||
inFunc = icuConvert;
|
||||
}
|
||||
|
||||
if (flags & XML_ENC_OUTPUT) {
|
||||
ret = icuOpen(name, 0, &outputCtxt);
|
||||
if (ret != 0)
|
||||
goto error;
|
||||
outFunc = icuConvert;
|
||||
}
|
||||
|
||||
return xmlCharEncNewCustomHandler(name, inFunc, outFunc, icuConvCtxtDtor,
|
||||
inputCtxt, outputCtxt, result);
|
||||
|
||||
error:
|
||||
if (inputCtxt != NULL)
|
||||
icuClose(inputCtxt);
|
||||
if (outputCtxt != NULL)
|
||||
icuClose(outputCtxt);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
main(void) {
|
||||
xmlParserCtxtPtr ctxt;
|
||||
xmlDocPtr doc;
|
||||
const char *xml;
|
||||
xmlChar *content;
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* We use IBM-1051, an alias for HP Roman, as a simple example that
|
||||
* ICU supports, but iconv (typically) doesn't.
|
||||
*
|
||||
* Character code 0xDE is U+00DF Latin Small Letter Sharp S.
|
||||
*/
|
||||
xml = "<doc>\xDE</doc>";
|
||||
|
||||
ctxt = xmlNewParserCtxt();
|
||||
xmlCtxtSetCharEncConvImpl(ctxt, icuConvImpl, NULL);
|
||||
doc = xmlCtxtReadDoc(ctxt, BAD_CAST xml, NULL, "IBM-1051", 0);
|
||||
xmlFreeParserCtxt(ctxt);
|
||||
|
||||
content = xmlNodeGetContent((xmlNodePtr) doc);
|
||||
|
||||
printf("content: %s\n", content);
|
||||
|
||||
if (!xmlStrEqual(content, BAD_CAST "\xC3\x9F")) {
|
||||
fprintf(stderr, "conversion failed\n");
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
xmlFree(content);
|
||||
xmlFreeDoc(doc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,159 @@
|
||||
/**
|
||||
* section: InputOutput
|
||||
* synopsis: Example of custom Input/Output
|
||||
* purpose: Demonstrate the use of xmlRegisterInputCallbacks
|
||||
* to build a custom I/O layer, this is used in an
|
||||
* XInclude method context to show how dynamic document can
|
||||
* be built in a clean way.
|
||||
* usage: io1
|
||||
* test: io1 > io1.tmp && diff io1.tmp $(srcdir)/io1.res
|
||||
* author: Daniel Veillard
|
||||
* copy: see Copyright for the status of this software.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libxml/parser.h>
|
||||
#include <libxml/tree.h>
|
||||
#include <libxml/xinclude.h>
|
||||
#include <libxml/xmlIO.h>
|
||||
|
||||
#ifdef LIBXML_XINCLUDE_ENABLED
|
||||
static const char *result = "<list><people>a</people><people>b</people></list>";
|
||||
static const char *cur = NULL;
|
||||
static int rlen;
|
||||
|
||||
/**
|
||||
* sqlMatch:
|
||||
* @URI: an URI to test
|
||||
*
|
||||
* Check for an sql: query
|
||||
*
|
||||
* Returns 1 if yes and 0 if another Input module should be used
|
||||
*/
|
||||
static int
|
||||
sqlMatch(const char * URI) {
|
||||
if ((URI != NULL) && (!strncmp(URI, "sql:", 4)))
|
||||
return(1);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* sqlOpen:
|
||||
* @URI: an URI to test
|
||||
*
|
||||
* Return a pointer to the sql: query handler, in this example simply
|
||||
* the current pointer...
|
||||
*
|
||||
* Returns an Input context or NULL in case or error
|
||||
*/
|
||||
static void *
|
||||
sqlOpen(const char * URI) {
|
||||
if ((URI == NULL) || (strncmp(URI, "sql:", 4)))
|
||||
return(NULL);
|
||||
cur = result;
|
||||
rlen = strlen(result);
|
||||
return((void *) cur);
|
||||
}
|
||||
|
||||
/**
|
||||
* sqlClose:
|
||||
* @context: the read context
|
||||
*
|
||||
* Close the sql: query handler
|
||||
*
|
||||
* Returns 0 or -1 in case of error
|
||||
*/
|
||||
static int
|
||||
sqlClose(void * context) {
|
||||
if (context == NULL) return(-1);
|
||||
cur = NULL;
|
||||
rlen = 0;
|
||||
return(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* sqlRead:
|
||||
* @context: the read context
|
||||
* @buffer: where to store data
|
||||
* @len: number of bytes to read
|
||||
*
|
||||
* Implement an sql: query read.
|
||||
*
|
||||
* Returns the number of bytes read or -1 in case of error
|
||||
*/
|
||||
static int
|
||||
sqlRead(void * context, char * buffer, int len) {
|
||||
const char *ptr = (const char *) context;
|
||||
|
||||
if ((context == NULL) || (buffer == NULL) || (len < 0))
|
||||
return(-1);
|
||||
|
||||
if (len > rlen) len = rlen;
|
||||
memcpy(buffer, ptr, len);
|
||||
rlen -= len;
|
||||
return(len);
|
||||
}
|
||||
|
||||
static const char *const include = "<?xml version='1.0'?>\n\
|
||||
<document xmlns:xi=\"http://www.w3.org/2003/XInclude\">\n\
|
||||
<p>List of people:</p>\n\
|
||||
<xi:include href=\"sql:select_name_from_people\"/>\n\
|
||||
</document>\n";
|
||||
|
||||
int main(void) {
|
||||
xmlDocPtr doc;
|
||||
|
||||
/*
|
||||
* this initialize the library and check potential ABI mismatches
|
||||
* between the version it was compiled for and the actual shared
|
||||
* library used.
|
||||
*/
|
||||
LIBXML_TEST_VERSION
|
||||
|
||||
/*
|
||||
* register the new I/O handlers
|
||||
*/
|
||||
if (xmlRegisterInputCallbacks(sqlMatch, sqlOpen, sqlRead, sqlClose) < 0) {
|
||||
fprintf(stderr, "failed to register SQL handler\n");
|
||||
exit(1);
|
||||
}
|
||||
/*
|
||||
* parse include into a document
|
||||
*/
|
||||
doc = xmlReadMemory(include, strlen(include), "include.xml", NULL, 0);
|
||||
if (doc == NULL) {
|
||||
fprintf(stderr, "failed to parse the including file\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* apply the XInclude process, this should trigger the I/O just
|
||||
* registered.
|
||||
*/
|
||||
if (xmlXIncludeProcess(doc) <= 0) {
|
||||
fprintf(stderr, "XInclude processing failed\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#ifdef LIBXML_OUTPUT_ENABLED
|
||||
/*
|
||||
* save the output for checking to stdout
|
||||
*/
|
||||
xmlDocDump(stdout, doc);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Free the document
|
||||
*/
|
||||
xmlFreeDoc(doc);
|
||||
|
||||
return(0);
|
||||
}
|
||||
#else
|
||||
int main(void) {
|
||||
fprintf(stderr, "XInclude support not compiled in\n");
|
||||
return(0);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* section: InputOutput
|
||||
* synopsis: Output to char buffer
|
||||
* purpose: Demonstrate the use of xmlDocDumpMemory
|
||||
* to output document to a character buffer
|
||||
* usage: io2
|
||||
* test: io2 > io2.tmp && diff io2.tmp $(srcdir)/io2.res
|
||||
* author: John Fleck
|
||||
* copy: see Copyright for the status of this software.
|
||||
*/
|
||||
|
||||
#include <libxml/parser.h>
|
||||
|
||||
#if defined(LIBXML_OUTPUT_ENABLED)
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
|
||||
xmlNodePtr n;
|
||||
xmlDocPtr doc;
|
||||
xmlChar *xmlbuff;
|
||||
int buffersize;
|
||||
|
||||
/*
|
||||
* Create the document.
|
||||
*/
|
||||
doc = xmlNewDoc(BAD_CAST "1.0");
|
||||
n = xmlNewDocNode(doc, NULL, BAD_CAST "root", NULL);
|
||||
xmlNodeSetContent(n, BAD_CAST "content");
|
||||
xmlDocSetRootElement(doc, n);
|
||||
|
||||
/*
|
||||
* Dump the document to a buffer and print it
|
||||
* for demonstration purposes.
|
||||
*/
|
||||
xmlDocDumpFormatMemory(doc, &xmlbuff, &buffersize, 1);
|
||||
printf("%s", (char *) xmlbuff);
|
||||
|
||||
/*
|
||||
* Free associated memory.
|
||||
*/
|
||||
xmlFree(xmlbuff);
|
||||
xmlFreeDoc(doc);
|
||||
|
||||
return (0);
|
||||
|
||||
}
|
||||
#else
|
||||
#include <stdio.h>
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
"library not configured with output support\n");
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,40 @@
|
||||
examples = [
|
||||
'gjobread',
|
||||
'io1',
|
||||
'io2',
|
||||
'parse1',
|
||||
'parse2',
|
||||
'parse3',
|
||||
'parse4',
|
||||
'reader1',
|
||||
'reader2',
|
||||
'reader3',
|
||||
'reader4',
|
||||
'testWriter',
|
||||
'tree1',
|
||||
'tree2',
|
||||
'xpath1',
|
||||
'xpath2',
|
||||
]
|
||||
|
||||
exes = []
|
||||
foreach example : examples
|
||||
exe = executable(
|
||||
example,
|
||||
files(example + '.c'),
|
||||
dependencies: xml_dep,
|
||||
include_directories: config_dir,
|
||||
build_by_default: false,
|
||||
)
|
||||
exes += exe
|
||||
if example == 'io1'
|
||||
io1 = exe
|
||||
endif
|
||||
endforeach
|
||||
|
||||
# arrange to build examples alongside tests
|
||||
test(
|
||||
'examples',
|
||||
io1,
|
||||
depends: exes,
|
||||
)
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* section: Parsing
|
||||
* synopsis: Parse an XML file to a tree and free it
|
||||
* purpose: Demonstrate the use of xmlReadFile() to read an XML file
|
||||
* into a tree and xmlFreeDoc() to free the resulting tree
|
||||
* usage: parse1 test1.xml
|
||||
* test: parse1 test1.xml
|
||||
* author: Daniel Veillard
|
||||
* copy: see Copyright for the status of this software.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <libxml/parser.h>
|
||||
#include <libxml/tree.h>
|
||||
|
||||
/**
|
||||
* example1Func:
|
||||
* @filename: a filename or an URL
|
||||
*
|
||||
* Parse the resource and free the resulting tree
|
||||
*/
|
||||
static void
|
||||
example1Func(const char *filename) {
|
||||
xmlDocPtr doc; /* the resulting document tree */
|
||||
|
||||
doc = xmlReadFile(filename, NULL, 0);
|
||||
if (doc == NULL) {
|
||||
fprintf(stderr, "Failed to parse %s\n", filename);
|
||||
return;
|
||||
}
|
||||
xmlFreeDoc(doc);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc != 2)
|
||||
return(1);
|
||||
|
||||
/*
|
||||
* this initialize the library and check potential ABI mismatches
|
||||
* between the version it was compiled for and the actual shared
|
||||
* library used.
|
||||
*/
|
||||
LIBXML_TEST_VERSION
|
||||
|
||||
example1Func(argv[1]);
|
||||
|
||||
return(0);
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* section: Parsing
|
||||
* synopsis: Parse and validate an XML file to a tree and free the result
|
||||
* purpose: Create a parser context for an XML file, then parse and validate
|
||||
* the file, creating a tree, check the validation result
|
||||
* and xmlFreeDoc() to free the resulting tree.
|
||||
* usage: parse2 test2.xml
|
||||
* test: parse2 test2.xml
|
||||
* author: Daniel Veillard
|
||||
* copy: see Copyright for the status of this software.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <libxml/parser.h>
|
||||
#include <libxml/tree.h>
|
||||
|
||||
/**
|
||||
* exampleFunc:
|
||||
* @filename: a filename or an URL
|
||||
*
|
||||
* Parse and validate the resource and free the resulting tree
|
||||
*/
|
||||
static void
|
||||
exampleFunc(const char *filename) {
|
||||
xmlParserCtxtPtr ctxt; /* the parser context */
|
||||
xmlDocPtr doc; /* the resulting document tree */
|
||||
|
||||
/* create a parser context */
|
||||
ctxt = xmlNewParserCtxt();
|
||||
if (ctxt == NULL) {
|
||||
fprintf(stderr, "Failed to allocate parser context\n");
|
||||
return;
|
||||
}
|
||||
/* parse the file, activating the DTD validation option */
|
||||
doc = xmlCtxtReadFile(ctxt, filename, NULL, XML_PARSE_DTDVALID);
|
||||
/* check if parsing succeeded */
|
||||
if (doc == NULL) {
|
||||
fprintf(stderr, "Failed to parse %s\n", filename);
|
||||
} else {
|
||||
/* check if validation succeeded */
|
||||
if (ctxt->valid == 0)
|
||||
fprintf(stderr, "Failed to validate %s\n", filename);
|
||||
/* free up the resulting document */
|
||||
xmlFreeDoc(doc);
|
||||
}
|
||||
/* free up the parser context */
|
||||
xmlFreeParserCtxt(ctxt);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc != 2)
|
||||
return(1);
|
||||
|
||||
/*
|
||||
* this initialize the library and check potential ABI mismatches
|
||||
* between the version it was compiled for and the actual shared
|
||||
* library used.
|
||||
*/
|
||||
LIBXML_TEST_VERSION
|
||||
|
||||
exampleFunc(argv[1]);
|
||||
|
||||
return(0);
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* section: Parsing
|
||||
* synopsis: Parse an XML document in memory to a tree and free it
|
||||
* purpose: Demonstrate the use of xmlReadMemory() to read an XML file
|
||||
* into a tree and xmlFreeDoc() to free the resulting tree
|
||||
* usage: parse3
|
||||
* test: parse3
|
||||
* author: Daniel Veillard
|
||||
* copy: see Copyright for the status of this software.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <libxml/parser.h>
|
||||
#include <libxml/tree.h>
|
||||
|
||||
static const char *document = "<doc/>";
|
||||
|
||||
/**
|
||||
* example3Func:
|
||||
* @content: the content of the document
|
||||
* @length: the length in bytes
|
||||
*
|
||||
* Parse the in memory document and free the resulting tree
|
||||
*/
|
||||
static void
|
||||
example3Func(const char *content, int length) {
|
||||
xmlDocPtr doc; /* the resulting document tree */
|
||||
|
||||
/*
|
||||
* The document being in memory, it have no base per RFC 2396,
|
||||
* and the "noname.xml" argument will serve as its base.
|
||||
*/
|
||||
doc = xmlReadMemory(content, length, "noname.xml", NULL, 0);
|
||||
if (doc == NULL) {
|
||||
fprintf(stderr, "Failed to parse document\n");
|
||||
return;
|
||||
}
|
||||
xmlFreeDoc(doc);
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
/*
|
||||
* this initialize the library and check potential ABI mismatches
|
||||
* between the version it was compiled for and the actual shared
|
||||
* library used.
|
||||
*/
|
||||
LIBXML_TEST_VERSION
|
||||
|
||||
example3Func(document, 6);
|
||||
|
||||
return(0);
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
/**
|
||||
* section: Parsing
|
||||
* synopsis: Parse an XML document chunk by chunk to a tree and free it
|
||||
* purpose: Demonstrate the use of xmlCreatePushParserCtxt() and
|
||||
* xmlParseChunk() to read an XML file progressively
|
||||
* into a tree and xmlFreeDoc() to free the resulting tree
|
||||
* usage: parse4 test3.xml
|
||||
* test: parse4 test3.xml
|
||||
* author: Daniel Veillard
|
||||
* copy: see Copyright for the status of this software.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <libxml/parser.h>
|
||||
#include <libxml/tree.h>
|
||||
|
||||
#ifdef LIBXML_PUSH_ENABLED
|
||||
static FILE *desc;
|
||||
|
||||
/**
|
||||
* readPacket:
|
||||
* @mem: array to store the packet
|
||||
* @size: the packet size
|
||||
*
|
||||
* read at most @size bytes from the document and store it in @mem
|
||||
*
|
||||
* Returns the number of bytes read
|
||||
*/
|
||||
static int
|
||||
readPacket(char *mem, int size) {
|
||||
int res;
|
||||
|
||||
res = fread(mem, 1, size, desc);
|
||||
return(res);
|
||||
}
|
||||
|
||||
/**
|
||||
* example4Func:
|
||||
* @filename: a filename or an URL
|
||||
*
|
||||
* Parse the resource and free the resulting tree
|
||||
*/
|
||||
static void
|
||||
example4Func(const char *filename) {
|
||||
xmlParserCtxtPtr ctxt;
|
||||
char chars[4];
|
||||
xmlDocPtr doc; /* the resulting document tree */
|
||||
int res;
|
||||
|
||||
/*
|
||||
* Read a few first byte to check the input used for the
|
||||
* encoding detection at the parser level.
|
||||
*/
|
||||
res = readPacket(chars, 4);
|
||||
if (res <= 0) {
|
||||
fprintf(stderr, "Failed to parse %s\n", filename);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a progressive parsing context, the 2 first arguments
|
||||
* are not used since we want to build a tree and not use a SAX
|
||||
* parsing interface. We also pass the first bytes of the document
|
||||
* to allow encoding detection when creating the parser but this
|
||||
* is optional.
|
||||
*/
|
||||
ctxt = xmlCreatePushParserCtxt(NULL, NULL,
|
||||
chars, res, filename);
|
||||
if (ctxt == NULL) {
|
||||
fprintf(stderr, "Failed to create parser context !\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* loop on the input getting the document data, of course 4 bytes
|
||||
* at a time is not realistic but allows to verify testing on small
|
||||
* documents.
|
||||
*/
|
||||
while ((res = readPacket(chars, 4)) > 0) {
|
||||
xmlParseChunk(ctxt, chars, res, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* there is no more input, indicate the parsing is finished.
|
||||
*/
|
||||
xmlParseChunk(ctxt, chars, 0, 1);
|
||||
|
||||
/*
|
||||
* collect the document back and if it was wellformed
|
||||
* and destroy the parser context.
|
||||
*/
|
||||
doc = ctxt->myDoc;
|
||||
res = ctxt->wellFormed;
|
||||
xmlFreeParserCtxt(ctxt);
|
||||
|
||||
if (!res) {
|
||||
fprintf(stderr, "Failed to parse %s\n", filename);
|
||||
}
|
||||
|
||||
/*
|
||||
* since we don't use the document, destroy it now.
|
||||
*/
|
||||
xmlFreeDoc(doc);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc != 2)
|
||||
return(1);
|
||||
|
||||
/*
|
||||
* this initialize the library and check potential ABI mismatches
|
||||
* between the version it was compiled for and the actual shared
|
||||
* library used.
|
||||
*/
|
||||
LIBXML_TEST_VERSION
|
||||
|
||||
/*
|
||||
* simulate a progressive parsing using the input file.
|
||||
*/
|
||||
desc = fopen(argv[1], "rb");
|
||||
if (desc != NULL) {
|
||||
example4Func(argv[1]);
|
||||
fclose(desc);
|
||||
} else {
|
||||
fprintf(stderr, "Failed to parse %s\n", argv[1]);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
#else /* ! LIBXML_PUSH_ENABLED */
|
||||
int main(void) {
|
||||
fprintf(stderr, "Library not compiled with push parser support\n");
|
||||
return(0);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,99 @@
|
||||
/**
|
||||
* section: xmlReader
|
||||
* synopsis: Parse an XML file with an xmlReader
|
||||
* purpose: Demonstrate the use of xmlReaderForFile() to parse an XML file
|
||||
* and dump the information about the nodes found in the process.
|
||||
* (Note that the XMLReader functions require libxml2 version later
|
||||
* than 2.6.)
|
||||
* usage: reader1 <filename>
|
||||
* test: reader1 test2.xml > reader1.tmp && diff reader1.tmp $(srcdir)/reader1.res
|
||||
* author: Daniel Veillard
|
||||
* copy: see Copyright for the status of this software.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <libxml/xmlreader.h>
|
||||
|
||||
#ifdef LIBXML_READER_ENABLED
|
||||
|
||||
/**
|
||||
* processNode:
|
||||
* @reader: the xmlReader
|
||||
*
|
||||
* Dump information about the current node
|
||||
*/
|
||||
static void
|
||||
processNode(xmlTextReaderPtr reader) {
|
||||
const xmlChar *name, *value;
|
||||
|
||||
name = xmlTextReaderConstName(reader);
|
||||
if (name == NULL)
|
||||
name = BAD_CAST "--";
|
||||
|
||||
value = xmlTextReaderConstValue(reader);
|
||||
|
||||
printf("%d %d %s %d %d",
|
||||
xmlTextReaderDepth(reader),
|
||||
xmlTextReaderNodeType(reader),
|
||||
name,
|
||||
xmlTextReaderIsEmptyElement(reader),
|
||||
xmlTextReaderHasValue(reader));
|
||||
if (value == NULL)
|
||||
printf("\n");
|
||||
else {
|
||||
if (xmlStrlen(value) > 40)
|
||||
printf(" %.40s...\n", value);
|
||||
else
|
||||
printf(" %s\n", value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* streamFile:
|
||||
* @filename: the file name to parse
|
||||
*
|
||||
* Parse and print information about an XML file.
|
||||
*/
|
||||
static void
|
||||
streamFile(const char *filename) {
|
||||
xmlTextReaderPtr reader;
|
||||
int ret;
|
||||
|
||||
reader = xmlReaderForFile(filename, NULL, 0);
|
||||
if (reader != NULL) {
|
||||
ret = xmlTextReaderRead(reader);
|
||||
while (ret == 1) {
|
||||
processNode(reader);
|
||||
ret = xmlTextReaderRead(reader);
|
||||
}
|
||||
xmlFreeTextReader(reader);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "%s : failed to parse\n", filename);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Unable to open %s\n", filename);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc != 2)
|
||||
return(1);
|
||||
|
||||
/*
|
||||
* this initialize the library and check potential ABI mismatches
|
||||
* between the version it was compiled for and the actual shared
|
||||
* library used.
|
||||
*/
|
||||
LIBXML_TEST_VERSION
|
||||
|
||||
streamFile(argv[1]);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
#else
|
||||
int main(void) {
|
||||
fprintf(stderr, "XInclude support not compiled in\n");
|
||||
return(0);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,115 @@
|
||||
/**
|
||||
* section: xmlReader
|
||||
* synopsis: Parse and validate an XML file with an xmlReader
|
||||
* purpose: Demonstrate the use of xmlReaderForFile() to parse an XML file
|
||||
* validating the content in the process and activating options
|
||||
* like entities substitution, and DTD attributes defaulting.
|
||||
* (Note that the XMLReader functions require libxml2 version later
|
||||
* than 2.6.)
|
||||
* usage: reader2 <valid_xml_filename>
|
||||
* test: reader2 test2.xml > reader1.tmp && diff reader1.tmp $(srcdir)/reader1.res
|
||||
* author: Daniel Veillard
|
||||
* copy: see Copyright for the status of this software.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <libxml/xmlreader.h>
|
||||
#include <libxml/parser.h>
|
||||
|
||||
#ifdef LIBXML_READER_ENABLED
|
||||
|
||||
/**
|
||||
* processNode:
|
||||
* @reader: the xmlReader
|
||||
*
|
||||
* Dump information about the current node
|
||||
*/
|
||||
static void
|
||||
processNode(xmlTextReaderPtr reader) {
|
||||
const xmlChar *name, *value;
|
||||
|
||||
name = xmlTextReaderConstName(reader);
|
||||
if (name == NULL)
|
||||
name = BAD_CAST "--";
|
||||
|
||||
value = xmlTextReaderConstValue(reader);
|
||||
|
||||
printf("%d %d %s %d %d",
|
||||
xmlTextReaderDepth(reader),
|
||||
xmlTextReaderNodeType(reader),
|
||||
name,
|
||||
xmlTextReaderIsEmptyElement(reader),
|
||||
xmlTextReaderHasValue(reader));
|
||||
if (value == NULL)
|
||||
printf("\n");
|
||||
else {
|
||||
if (xmlStrlen(value) > 40)
|
||||
printf(" %.40s...\n", value);
|
||||
else
|
||||
printf(" %s\n", value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* streamFile:
|
||||
* @filename: the file name to parse
|
||||
*
|
||||
* Parse, validate and print information about an XML file.
|
||||
*/
|
||||
static void
|
||||
streamFile(const char *filename) {
|
||||
xmlTextReaderPtr reader;
|
||||
int ret;
|
||||
|
||||
|
||||
/*
|
||||
* Pass some special parsing options to activate DTD attribute defaulting,
|
||||
* entities substitution and DTD validation
|
||||
*/
|
||||
reader = xmlReaderForFile(filename, NULL,
|
||||
XML_PARSE_DTDATTR | /* default DTD attributes */
|
||||
XML_PARSE_NOENT | /* substitute entities */
|
||||
XML_PARSE_DTDVALID); /* validate with the DTD */
|
||||
if (reader != NULL) {
|
||||
ret = xmlTextReaderRead(reader);
|
||||
while (ret == 1) {
|
||||
processNode(reader);
|
||||
ret = xmlTextReaderRead(reader);
|
||||
}
|
||||
/*
|
||||
* Once the document has been fully parsed check the validation results
|
||||
*/
|
||||
if (xmlTextReaderIsValid(reader) != 1) {
|
||||
fprintf(stderr, "Document %s does not validate\n", filename);
|
||||
}
|
||||
xmlFreeTextReader(reader);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "%s : failed to parse\n", filename);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Unable to open %s\n", filename);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc != 2)
|
||||
return(1);
|
||||
|
||||
/*
|
||||
* this initialize the library and check potential ABI mismatches
|
||||
* between the version it was compiled for and the actual shared
|
||||
* library used.
|
||||
*/
|
||||
LIBXML_TEST_VERSION
|
||||
|
||||
streamFile(argv[1]);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
#else
|
||||
int main(void) {
|
||||
fprintf(stderr, "XInclude support not compiled in\n");
|
||||
return(0);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* section: xmlReader
|
||||
* synopsis: Show how to extract subdocuments with xmlReader
|
||||
* purpose: Demonstrate the use of xmlTextReaderPreservePattern()
|
||||
* to parse an XML file with the xmlReader while collecting
|
||||
* only some subparts of the document.
|
||||
* (Note that the XMLReader functions require libxml2 version later
|
||||
* than 2.6.)
|
||||
* usage: reader3
|
||||
* test: reader3 > reader3.tmp && diff reader3.tmp $(srcdir)/reader3.res
|
||||
* author: Daniel Veillard
|
||||
* copy: see Copyright for the status of this software.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <libxml/xmlreader.h>
|
||||
|
||||
#if defined(LIBXML_READER_ENABLED) && defined(LIBXML_PATTERN_ENABLED) && defined(LIBXML_OUTPUT_ENABLED)
|
||||
|
||||
|
||||
/**
|
||||
* streamFile:
|
||||
* @filename: the file name to parse
|
||||
*
|
||||
* Parse and print information about an XML file.
|
||||
*
|
||||
* Returns the resulting doc with just the elements preserved.
|
||||
*/
|
||||
static xmlDocPtr
|
||||
extractFile(const char *filename, const xmlChar *pattern) {
|
||||
xmlDocPtr doc;
|
||||
xmlTextReaderPtr reader;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* build an xmlReader for that file
|
||||
*/
|
||||
reader = xmlReaderForFile(filename, NULL, 0);
|
||||
if (reader != NULL) {
|
||||
/*
|
||||
* add the pattern to preserve
|
||||
*/
|
||||
if (xmlTextReaderPreservePattern(reader, pattern, NULL) < 0) {
|
||||
fprintf(stderr, "%s : failed add preserve pattern %s\n",
|
||||
filename, (const char *) pattern);
|
||||
}
|
||||
/*
|
||||
* Parse and traverse the tree, collecting the nodes in the process
|
||||
*/
|
||||
ret = xmlTextReaderRead(reader);
|
||||
while (ret == 1) {
|
||||
ret = xmlTextReaderRead(reader);
|
||||
}
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "%s : failed to parse\n", filename);
|
||||
xmlFreeTextReader(reader);
|
||||
return(NULL);
|
||||
}
|
||||
/*
|
||||
* get the resulting nodes
|
||||
*/
|
||||
doc = xmlTextReaderCurrentDoc(reader);
|
||||
/*
|
||||
* Free up the reader
|
||||
*/
|
||||
xmlFreeTextReader(reader);
|
||||
} else {
|
||||
fprintf(stderr, "Unable to open %s\n", filename);
|
||||
return(NULL);
|
||||
}
|
||||
return(doc);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
const char *filename = "test3.xml";
|
||||
const char *pattern = "preserved";
|
||||
xmlDocPtr doc;
|
||||
|
||||
if (argc == 3) {
|
||||
filename = argv[1];
|
||||
pattern = argv[2];
|
||||
}
|
||||
|
||||
/*
|
||||
* this initialize the library and check potential ABI mismatches
|
||||
* between the version it was compiled for and the actual shared
|
||||
* library used.
|
||||
*/
|
||||
LIBXML_TEST_VERSION
|
||||
|
||||
doc = extractFile(filename, (const xmlChar *) pattern);
|
||||
if (doc != NULL) {
|
||||
/*
|
||||
* output the result.
|
||||
*/
|
||||
xmlDocDump(stdout, doc);
|
||||
/*
|
||||
* don't forget to free up the doc
|
||||
*/
|
||||
xmlFreeDoc(doc);
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
#else
|
||||
int main(void) {
|
||||
fprintf(stderr, "Reader, Pattern or output support not compiled in\n");
|
||||
return(0);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* section: xmlReader
|
||||
* synopsis: Parse multiple XML files reusing an xmlReader
|
||||
* purpose: Demonstrate the use of xmlReaderForFile() and
|
||||
* xmlReaderNewFile to parse XML files while reusing the reader object
|
||||
* and parser context. (Note that the XMLReader functions require
|
||||
* libxml2 version later than 2.6.)
|
||||
* usage: reader4 <filename> [ filename ... ]
|
||||
* test: reader4 test1.xml test2.xml test3.xml > reader4.tmp && diff reader4.tmp $(srcdir)/reader4.res
|
||||
* author: Graham Bennett
|
||||
* copy: see Copyright for the status of this software.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <libxml/xmlreader.h>
|
||||
|
||||
#ifdef LIBXML_READER_ENABLED
|
||||
|
||||
static void processDoc(xmlTextReaderPtr readerPtr) {
|
||||
int ret;
|
||||
xmlDocPtr docPtr;
|
||||
const xmlChar *URL;
|
||||
|
||||
ret = xmlTextReaderRead(readerPtr);
|
||||
while (ret == 1) {
|
||||
ret = xmlTextReaderRead(readerPtr);
|
||||
}
|
||||
|
||||
/*
|
||||
* One can obtain the document pointer to get interesting
|
||||
* information about the document like the URL, but one must also
|
||||
* be sure to clean it up at the end (see below).
|
||||
*/
|
||||
docPtr = xmlTextReaderCurrentDoc(readerPtr);
|
||||
if (NULL == docPtr) {
|
||||
fprintf(stderr, "failed to obtain document\n");
|
||||
return;
|
||||
}
|
||||
|
||||
URL = docPtr->URL;
|
||||
if (NULL == URL) {
|
||||
fprintf(stderr, "Failed to obtain URL\n");
|
||||
}
|
||||
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "%s: Failed to parse\n", URL);
|
||||
return;
|
||||
}
|
||||
|
||||
printf("%s: Processed ok\n", (const char *)URL);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
xmlTextReaderPtr readerPtr;
|
||||
int i;
|
||||
xmlDocPtr docPtr;
|
||||
|
||||
if (argc < 2)
|
||||
return(1);
|
||||
|
||||
/*
|
||||
* this initialises the library and check potential ABI mismatches
|
||||
* between the version it was compiled for and the actual shared
|
||||
* library used.
|
||||
*/
|
||||
LIBXML_TEST_VERSION
|
||||
|
||||
/*
|
||||
* Create a new reader for the first file and process the
|
||||
* document.
|
||||
*/
|
||||
readerPtr = xmlReaderForFile(argv[1], NULL, 0);
|
||||
if (NULL == readerPtr) {
|
||||
fprintf(stderr, "%s: failed to create reader\n", argv[1]);
|
||||
return(1);
|
||||
}
|
||||
processDoc(readerPtr);
|
||||
|
||||
/*
|
||||
* The reader can be reused for subsequent files.
|
||||
*/
|
||||
for (i=2; i < argc; ++i) {
|
||||
xmlReaderNewFile(readerPtr, argv[i], NULL, 0);
|
||||
if (NULL == readerPtr) {
|
||||
fprintf(stderr, "%s: failed to create reader\n", argv[i]);
|
||||
return(1);
|
||||
}
|
||||
processDoc(readerPtr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Since we've called xmlTextReaderCurrentDoc, we now have to
|
||||
* clean up after ourselves. We only have to do this the last
|
||||
* time, because xmlReaderNewFile calls xmlCtxtReset which takes
|
||||
* care of it.
|
||||
*/
|
||||
docPtr = xmlTextReaderCurrentDoc(readerPtr);
|
||||
if (docPtr != NULL)
|
||||
xmlFreeDoc(docPtr);
|
||||
|
||||
/*
|
||||
* Clean up the reader.
|
||||
*/
|
||||
xmlFreeTextReader(readerPtr);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
#else
|
||||
int main(void) {
|
||||
fprintf(stderr, "xmlReader support not compiled in\n");
|
||||
return(0);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1 @@
|
||||
<doc/>
|
||||
@@ -0,0 +1,13 @@
|
||||
<!DOCTYPE doc [
|
||||
<!ELEMENT doc (src | dest)*>
|
||||
<!ELEMENT src EMPTY>
|
||||
<!ELEMENT dest EMPTY>
|
||||
<!ATTLIST src ref IDREF #IMPLIED>
|
||||
<!ATTLIST dest id ID #IMPLIED>
|
||||
]>
|
||||
<doc>
|
||||
<src ref="foo"/>
|
||||
<dest id="foo"/>
|
||||
<src ref="foo"/>
|
||||
</doc>
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
<doc>
|
||||
<parent>
|
||||
<discarded>
|
||||
<discarded/>
|
||||
</discarded>
|
||||
<preserved/>
|
||||
This text node must be discarded
|
||||
<discarded>
|
||||
<discarded/>
|
||||
</discarded>
|
||||
<preserved>
|
||||
content1
|
||||
<child1></child1>
|
||||
<child2>content2</child2>
|
||||
<preserved>too</preserved>
|
||||
<child2>content3</child2>
|
||||
<preserved></preserved>
|
||||
<child2>content4</child2>
|
||||
<preserved/>
|
||||
<child2>content5</child2>
|
||||
content6
|
||||
</preserved>
|
||||
This text node must be discarded
|
||||
<discarded>
|
||||
<discarded/>
|
||||
</discarded>
|
||||
This text node must be discarded
|
||||
<preserved></preserved>
|
||||
This text node must be discarded
|
||||
<preserved/>
|
||||
This text node must be discarded
|
||||
<discarded>
|
||||
<discarded/>
|
||||
</discarded>
|
||||
This text node must be discarded
|
||||
</parent>
|
||||
</doc>
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* section: Tree
|
||||
* synopsis: Navigates a tree to print element names
|
||||
* purpose: Parse a file to a tree, use xmlDocGetRootElement() to
|
||||
* get the root element, then walk the document and print
|
||||
* all the element name in document order.
|
||||
* usage: tree1 filename_or_URL
|
||||
* test: tree1 test2.xml > tree1.tmp && diff tree1.tmp $(srcdir)/tree1.res
|
||||
* author: Dodji Seketeli
|
||||
* copy: see Copyright for the status of this software.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <libxml/parser.h>
|
||||
#include <libxml/tree.h>
|
||||
|
||||
/*
|
||||
*To compile this file using gcc you can type
|
||||
*gcc `xml2-config --cflags --libs` -o xmlexample libxml2-example.c
|
||||
*/
|
||||
|
||||
/**
|
||||
* print_element_names:
|
||||
* @a_node: the initial xml node to consider.
|
||||
*
|
||||
* Prints the names of the all the xml elements
|
||||
* that are siblings or children of a given xml node.
|
||||
*/
|
||||
static void
|
||||
print_element_names(xmlNode * a_node)
|
||||
{
|
||||
xmlNode *cur_node = NULL;
|
||||
|
||||
for (cur_node = a_node; cur_node; cur_node = cur_node->next) {
|
||||
if (cur_node->type == XML_ELEMENT_NODE) {
|
||||
printf("node type: Element, name: %s\n", cur_node->name);
|
||||
}
|
||||
|
||||
print_element_names(cur_node->children);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Simple example to parse a file called "file.xml",
|
||||
* walk down the DOM, and print the name of the
|
||||
* xml elements nodes.
|
||||
*/
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
xmlDoc *doc = NULL;
|
||||
xmlNode *root_element = NULL;
|
||||
|
||||
if (argc != 2)
|
||||
return(1);
|
||||
|
||||
/*
|
||||
* this initialize the library and check potential ABI mismatches
|
||||
* between the version it was compiled for and the actual shared
|
||||
* library used.
|
||||
*/
|
||||
LIBXML_TEST_VERSION
|
||||
|
||||
/*parse the file and get the DOM */
|
||||
doc = xmlReadFile(argv[1], NULL, 0);
|
||||
|
||||
if (doc == NULL) {
|
||||
printf("error: could not parse file %s\n", argv[1]);
|
||||
}
|
||||
|
||||
/*Get the root element node */
|
||||
root_element = xmlDocGetRootElement(doc);
|
||||
|
||||
print_element_names(root_element);
|
||||
|
||||
/*free the document */
|
||||
xmlFreeDoc(doc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* section: Tree
|
||||
* synopsis: Creates a tree
|
||||
* purpose: Shows how to create document, nodes and dump it to stdout or file.
|
||||
* usage: tree2 <filename> -Default output: stdout
|
||||
* test: tree2 > tree2.tmp && diff tree2.tmp $(srcdir)/tree2.res
|
||||
* author: Lucas Brasilino <brasilino@recife.pe.gov.br>
|
||||
* copy: see Copyright for the status of this software
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <libxml/parser.h>
|
||||
#include <libxml/tree.h>
|
||||
|
||||
#if defined(LIBXML_OUTPUT_ENABLED)
|
||||
|
||||
/*
|
||||
*To compile this file using gcc you can type
|
||||
*gcc `xml2-config --cflags --libs` -o tree2 tree2.c
|
||||
*/
|
||||
|
||||
/* A simple example how to create DOM. Libxml2 automagically
|
||||
* allocates the necessary amount of memory to it.
|
||||
*/
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
xmlDocPtr doc = NULL; /* document pointer */
|
||||
xmlNodePtr root_node = NULL, node = NULL, node1 = NULL;/* node pointers */
|
||||
char buff[256];
|
||||
int i, j;
|
||||
|
||||
LIBXML_TEST_VERSION;
|
||||
|
||||
/*
|
||||
* Creates a new document, a node and set it as a root node
|
||||
*/
|
||||
doc = xmlNewDoc(BAD_CAST "1.0");
|
||||
root_node = xmlNewDocNode(doc, NULL, BAD_CAST "root", NULL);
|
||||
xmlDocSetRootElement(doc, root_node);
|
||||
|
||||
/*
|
||||
* Creates a DTD declaration. Isn't mandatory.
|
||||
*/
|
||||
xmlCreateIntSubset(doc, BAD_CAST "root", NULL, BAD_CAST "tree2.dtd");
|
||||
|
||||
/*
|
||||
* xmlNewChild() creates a new node, which is "attached" as child node
|
||||
* of root_node node.
|
||||
*/
|
||||
xmlNewChild(root_node, NULL, BAD_CAST "node1",
|
||||
BAD_CAST "content of node 1");
|
||||
/*
|
||||
* The same as above, but the new child node doesn't have a content
|
||||
*/
|
||||
xmlNewChild(root_node, NULL, BAD_CAST "node2", NULL);
|
||||
|
||||
/*
|
||||
* xmlNewProp() creates attributes, which is "attached" to an node.
|
||||
* It returns xmlAttrPtr, which isn't used here.
|
||||
*/
|
||||
node =
|
||||
xmlNewChild(root_node, NULL, BAD_CAST "node3",
|
||||
BAD_CAST "this node has attributes");
|
||||
xmlNewProp(node, BAD_CAST "attribute", BAD_CAST "yes");
|
||||
xmlNewProp(node, BAD_CAST "foo", BAD_CAST "bar");
|
||||
|
||||
/*
|
||||
* Here goes another way to create nodes. xmlNewNode() and xmlNewText
|
||||
* creates a node and a text node separately. They are "attached"
|
||||
* by xmlAddChild()
|
||||
*/
|
||||
node = xmlNewDocNode(doc, NULL, BAD_CAST "node4", NULL);
|
||||
node1 = xmlNewDocText(doc, BAD_CAST
|
||||
"other way to create content (which is also a node)");
|
||||
xmlAddChild(node, node1);
|
||||
xmlAddChild(root_node, node);
|
||||
|
||||
/*
|
||||
* A simple loop that "automates" nodes creation
|
||||
*/
|
||||
for (i = 5; i < 7; i++) {
|
||||
snprintf(buff, sizeof(buff), "node%d", i);
|
||||
node = xmlNewChild(root_node, NULL, BAD_CAST buff, NULL);
|
||||
for (j = 1; j < 4; j++) {
|
||||
snprintf(buff, sizeof(buff), "node%d%d", i, j);
|
||||
node1 = xmlNewChild(node, NULL, BAD_CAST buff, NULL);
|
||||
xmlNewProp(node1, BAD_CAST "odd", BAD_CAST((j % 2) ? "no" : "yes"));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Dumping document to stdio or file
|
||||
*/
|
||||
xmlSaveFormatFileEnc(argc > 1 ? argv[1] : "-", doc, "UTF-8", 1);
|
||||
|
||||
/*free the document */
|
||||
xmlFreeDoc(doc);
|
||||
|
||||
return(0);
|
||||
}
|
||||
#else
|
||||
int main(void) {
|
||||
fprintf(stderr, "output support not compiled in\n");
|
||||
return(0);
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,243 @@
|
||||
/**
|
||||
* section: XPath
|
||||
* synopsis: Evaluate XPath expression and prints result node set.
|
||||
* purpose: Shows how to evaluate XPath expression and register
|
||||
* known namespaces in XPath context.
|
||||
* usage: xpath1 <xml-file> <xpath-expr> [<known-ns-list>]
|
||||
* test: xpath1 test3.xml '//child2' > xpath1.tmp && diff xpath1.tmp $(srcdir)/xpath1.res
|
||||
* author: Aleksey Sanin
|
||||
* 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)
|
||||
|
||||
|
||||
static void usage(const char *name);
|
||||
int execute_xpath_expression(const char* filename, const xmlChar* xpathExpr, const xmlChar* nsList);
|
||||
int register_namespaces(xmlXPathContextPtr xpathCtx, const xmlChar* nsList);
|
||||
void print_xpath_nodes(xmlNodeSetPtr nodes, FILE* output);
|
||||
|
||||
int
|
||||
main(int argc, char **argv) {
|
||||
/* Parse command line and process file */
|
||||
if((argc < 3) || (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(execute_xpath_expression(argv[1], BAD_CAST argv[2], (argc > 3) ? BAD_CAST argv[3] : NULL) < 0) {
|
||||
usage(argv[0]);
|
||||
return(-1);
|
||||
}
|
||||
|
||||
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> [<known-ns-list>]\n", name);
|
||||
fprintf(stderr, "where <known-ns-list> is a list of known namespaces\n");
|
||||
fprintf(stderr, "in \"<prefix1>=<href1> <prefix2>=href2> ...\" format\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* execute_xpath_expression:
|
||||
* @filename: the input XML filename.
|
||||
* @xpathExpr: the xpath expression for evaluation.
|
||||
* @nsList: the optional list of known namespaces in
|
||||
* "<prefix1>=<href1> <prefix2>=href2> ..." format.
|
||||
*
|
||||
* Parses input XML file, evaluates XPath expression and prints results.
|
||||
*
|
||||
* Returns 0 on success and a negative value otherwise.
|
||||
*/
|
||||
int
|
||||
execute_xpath_expression(const char* filename, const xmlChar* xpathExpr, const xmlChar* nsList) {
|
||||
xmlDocPtr doc;
|
||||
xmlXPathContextPtr xpathCtx;
|
||||
xmlXPathObjectPtr xpathObj;
|
||||
|
||||
assert(filename);
|
||||
assert(xpathExpr);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
||||
/* Register namespaces from list (if any) */
|
||||
if((nsList != NULL) && (register_namespaces(xpathCtx, nsList) < 0)) {
|
||||
fprintf(stderr,"Error: failed to register namespaces list \"%s\"\n", nsList);
|
||||
xmlXPathFreeContext(xpathCtx);
|
||||
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);
|
||||
}
|
||||
|
||||
/* Print results */
|
||||
print_xpath_nodes(xpathObj->nodesetval, stdout);
|
||||
|
||||
/* Cleanup */
|
||||
xmlXPathFreeObject(xpathObj);
|
||||
xmlXPathFreeContext(xpathCtx);
|
||||
xmlFreeDoc(doc);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* register_namespaces:
|
||||
* @xpathCtx: the pointer to an XPath context.
|
||||
* @nsList: the list of known namespaces in
|
||||
* "<prefix1>=<href1> <prefix2>=href2> ..." format.
|
||||
*
|
||||
* Registers namespaces from @nsList in @xpathCtx.
|
||||
*
|
||||
* Returns 0 on success and a negative value otherwise.
|
||||
*/
|
||||
int
|
||||
register_namespaces(xmlXPathContextPtr xpathCtx, const xmlChar* nsList) {
|
||||
xmlChar* nsListDup;
|
||||
xmlChar* prefix;
|
||||
xmlChar* href;
|
||||
xmlChar* next;
|
||||
|
||||
assert(xpathCtx);
|
||||
assert(nsList);
|
||||
|
||||
nsListDup = xmlStrdup(nsList);
|
||||
if(nsListDup == NULL) {
|
||||
fprintf(stderr, "Error: unable to strdup namespaces list\n");
|
||||
return(-1);
|
||||
}
|
||||
|
||||
next = nsListDup;
|
||||
while(next != NULL) {
|
||||
/* skip spaces */
|
||||
while((*next) == ' ') next++;
|
||||
if((*next) == '\0') break;
|
||||
|
||||
/* find prefix */
|
||||
prefix = next;
|
||||
next = (xmlChar*)xmlStrchr(next, '=');
|
||||
if(next == NULL) {
|
||||
fprintf(stderr,"Error: invalid namespaces list format\n");
|
||||
xmlFree(nsListDup);
|
||||
return(-1);
|
||||
}
|
||||
*(next++) = '\0';
|
||||
|
||||
/* find href */
|
||||
href = next;
|
||||
next = (xmlChar*)xmlStrchr(next, ' ');
|
||||
if(next != NULL) {
|
||||
*(next++) = '\0';
|
||||
}
|
||||
|
||||
/* do register namespace */
|
||||
if(xmlXPathRegisterNs(xpathCtx, prefix, href) != 0) {
|
||||
fprintf(stderr,"Error: unable to register NS with prefix=\"%s\" and href=\"%s\"\n", prefix, href);
|
||||
xmlFree(nsListDup);
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
|
||||
xmlFree(nsListDup);
|
||||
return(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* print_xpath_nodes:
|
||||
* @nodes: the nodes set.
|
||||
* @output: the output file handle.
|
||||
*
|
||||
* Prints the @nodes content to @output.
|
||||
*/
|
||||
void
|
||||
print_xpath_nodes(xmlNodeSetPtr nodes, FILE* output) {
|
||||
xmlNodePtr cur;
|
||||
int size;
|
||||
int i;
|
||||
|
||||
assert(output);
|
||||
size = (nodes) ? nodes->nodeNr : 0;
|
||||
|
||||
fprintf(output, "Result (%d nodes):\n", size);
|
||||
for(i = 0; i < size; ++i) {
|
||||
assert(nodes->nodeTab[i]);
|
||||
|
||||
if(nodes->nodeTab[i]->type == XML_NAMESPACE_DECL) {
|
||||
xmlNsPtr ns;
|
||||
|
||||
ns = (xmlNsPtr)nodes->nodeTab[i];
|
||||
cur = (xmlNodePtr)ns->next;
|
||||
if(cur->ns) {
|
||||
fprintf(output, "= namespace \"%s\"=\"%s\" for node %s:%s\n",
|
||||
ns->prefix, ns->href, cur->ns->href, cur->name);
|
||||
} else {
|
||||
fprintf(output, "= namespace \"%s\"=\"%s\" for node %s\n",
|
||||
ns->prefix, ns->href, cur->name);
|
||||
}
|
||||
} else if(nodes->nodeTab[i]->type == XML_ELEMENT_NODE) {
|
||||
cur = nodes->nodeTab[i];
|
||||
if(cur->ns) {
|
||||
fprintf(output, "= element node \"%s:%s\"\n",
|
||||
cur->ns->href, cur->name);
|
||||
} else {
|
||||
fprintf(output, "= element node \"%s\"\n",
|
||||
cur->name);
|
||||
}
|
||||
} else {
|
||||
cur = nodes->nodeTab[i];
|
||||
fprintf(output, "= node \"%s\": type %d\n", cur->name, cur->type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
int main(void) {
|
||||
fprintf(stderr, "XPath support not compiled in\n");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,183 @@
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
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");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user