diff options
author | Bruce Momjian | 2004-03-05 03:24:50 +0000 |
---|---|---|
committer | Bruce Momjian | 2004-03-05 03:24:50 +0000 |
commit | 0ae49736876305a19c4450bfdd0d2acab5a0b52d (patch) | |
tree | 6f3a3e70840b611cc56133787644ae92dc5dc594 /contrib/xml/xslt_proc.c | |
parent | d41f6901d2df680935c5b513939a4fcb3360b6b6 (diff) |
Thanks to the generous support of Torchbox (http://www.torchbox.com), I
have been able to significantly improve the contrib/xml XPath
integration code.
New features:
* XPath set-returning function allows multiple results from an several
XPath queries to be used as a virtual table.
* Using libxslt, XSLT transformations (with and without parameters) are
supported. (Caution: This support allows generic URL fetching from
within the backend as well).
I've removed the old code so that it is all libxml based. Rather than
attach as a patch, I've put the tar.gz (10k!) at
http://www.azuli.co.uk/pgxml-1.0.tar.gz
(all files in archive are xml/....).
I think this is worth replacing the contrib version with, even though
the function names have changed (though the same functionality is
there), because it includes a SRF and some SPI usage, in addition to
linking to an external library. And it isn't a big module! Obviously, I
understand that people might prefer to move it elsewhere, or might have
reservations about replacing an existing contrib module with an
incompatible one. I'm open to suggestions.
John Gray
Diffstat (limited to 'contrib/xml/xslt_proc.c')
-rw-r--r-- | contrib/xml/xslt_proc.c | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/contrib/xml/xslt_proc.c b/contrib/xml/xslt_proc.c new file mode 100644 index 0000000000..64f9736622 --- /dev/null +++ b/contrib/xml/xslt_proc.c @@ -0,0 +1,184 @@ +/* XSLT processing functions (requiring libxslt) */ +/* John Gray, for Torchbox 2003-04-01 */ + +#include "postgres.h" +#include "fmgr.h" +#include "executor/spi.h" +#include "funcapi.h" +#include "miscadmin.h" + +/* libxml includes */ + +#include <libxml/xpath.h> +#include <libxml/tree.h> +#include <libxml/xmlmemory.h> + +/* libxslt includes */ + +#include <libxslt/xslt.h> +#include <libxslt/xsltInternals.h> +#include <libxslt/transform.h> +#include <libxslt/xsltutils.h> + + +/* declarations to come from xpath.c */ + +extern void elog_error(int level, char *explain, int force); +extern void pgxml_parser_init(); +extern xmlChar *pgxml_texttoxmlchar(text *textstring); + +#define GET_STR(textp) DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(textp))) + +/* local defs */ +static void parse_params(const char **params, text *paramstr); + +Datum xslt_process(PG_FUNCTION_ARGS); + + +#define MAXPARAMS 20 + +PG_FUNCTION_INFO_V1(xslt_process); + +Datum xslt_process(PG_FUNCTION_ARGS) { + + + const char *params[MAXPARAMS + 1]; /* +1 for the terminator */ + xsltStylesheetPtr stylesheet = NULL; + xmlDocPtr doctree; + xmlDocPtr restree; + xmlDocPtr ssdoc = NULL; + xmlChar *resstr; + int resstat; + int reslen; + + text *doct = PG_GETARG_TEXT_P(0); + text *ssheet = PG_GETARG_TEXT_P(1); + text *paramstr; + text *tres; + + + if (fcinfo->nargs == 3) + { + paramstr = PG_GETARG_TEXT_P(2); + parse_params(params,paramstr); + } + else /* No parameters */ + { + params[0] = NULL; + } + + /* Setup parser */ + pgxml_parser_init(); + + /* Check to see if document is a file or a literal */ + + if (VARDATA(doct)[0] == '<') + { + doctree = xmlParseMemory((char *) VARDATA(doct), VARSIZE(doct)-VARHDRSZ); + } + else + { + doctree = xmlParseFile(GET_STR(doct)); + } + + if (doctree == NULL) + { + xmlCleanupParser(); + elog_error(ERROR,"Error parsing XML document",0); + + PG_RETURN_NULL(); + } + + /* Same for stylesheet */ + if (VARDATA(ssheet)[0] == '<') + { + ssdoc = xmlParseMemory((char *) VARDATA(ssheet), + VARSIZE(ssheet)-VARHDRSZ); + if (ssdoc == NULL) + { + xmlFreeDoc(doctree); + xmlCleanupParser(); + elog_error(ERROR,"Error parsing stylesheet as XML document",0); + PG_RETURN_NULL(); + } + + stylesheet = xsltParseStylesheetDoc(ssdoc); + } + else + { + stylesheet = xsltParseStylesheetFile(GET_STR(ssheet)); + } + + + if (stylesheet == NULL) + { + xmlFreeDoc(doctree); + xsltCleanupGlobals(); + xmlCleanupParser(); + elog_error(ERROR,"Failed to parse stylesheet",0); + PG_RETURN_NULL(); + } + + restree = xsltApplyStylesheet(stylesheet, doctree, params); + resstat = xsltSaveResultToString(&resstr, &reslen, restree, stylesheet); + + xsltFreeStylesheet(stylesheet); + xmlFreeDoc(restree); + xmlFreeDoc(doctree); + + xsltCleanupGlobals(); + xmlCleanupParser(); + + if (resstat < 0) { + PG_RETURN_NULL(); + } + + tres = palloc(reslen + VARHDRSZ); + memcpy(VARDATA(tres),resstr,reslen); + VARATT_SIZEP(tres) = reslen + VARHDRSZ; + + PG_RETURN_TEXT_P(tres); +} + + +void parse_params(const char **params, text *paramstr) +{ + char *pos; + char *pstr; + + int i; + char *nvsep="="; + char *itsep=","; + + pstr = GET_STR(paramstr); + + pos=pstr; + + for (i=0; i < MAXPARAMS; i++) + { + params[i] = pos; + pos = strstr(pos,nvsep); + if (pos != NULL) { + *pos = '\0'; + pos++; + } else { + params[i]=NULL; + break; + } + /* Value */ + i++; + params[i]=pos; + pos = strstr(pos,itsep); + if (pos != NULL) { + *pos = '\0'; + pos++; + } else { + break; + } + + } + if (i < MAXPARAMS) + { + params[i+1]=NULL; + } +} |