postgresql/contrib/xml2/xslt_proc.c

191 lines
3.8 KiB
C
Raw Normal View History

/*
2010-07-07 03:19:02 +08:00
* $PostgreSQL: pgsql/contrib/xml2/xslt_proc.c,v 1.21 2010/07/06 19:18:55 momjian Exp $
*
* XSLT processing functions (requiring libxslt)
*
* John Gray, for Torchbox 2003-04-01
*/
#include "postgres.h"
#include "executor/spi.h"
#include "fmgr.h"
#include "funcapi.h"
#include "miscadmin.h"
#include "utils/builtins.h"
#include "utils/xml.h"
#ifdef USE_LIBXSLT
/* 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>
2010-07-07 03:19:02 +08:00
#endif /* USE_LIBXSLT */
/* externally accessible functions */
Datum xslt_process(PG_FUNCTION_ARGS);
#ifdef USE_LIBXSLT
/* declarations to come from xpath.c */
extern void pgxml_parser_init(void);
/* local defs */
static void parse_params(const char **params, text *paramstr);
#define MAXPARAMS 20 /* must be even, see parse_params() */
2010-07-07 03:19:02 +08:00
#endif /* USE_LIBXSLT */
PG_FUNCTION_INFO_V1(xslt_process);
2004-08-29 13:07:03 +08:00
Datum
xslt_process(PG_FUNCTION_ARGS)
{
#ifdef USE_LIBXSLT
text *doct = PG_GETARG_TEXT_P(0);
text *ssheet = PG_GETARG_TEXT_P(1);
text *paramstr;
2004-08-29 13:07:03 +08:00
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;
if (fcinfo->nargs == 3)
{
paramstr = PG_GETARG_TEXT_P(2);
parse_params(params, paramstr);
}
else
2005-10-15 10:49:52 +08:00
/* No parameters */
2004-08-29 13:07:03 +08:00
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(text_to_cstring(doct));
2004-08-29 13:07:03 +08:00
if (doctree == NULL)
xml_ereport(ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
"error parsing XML document");
2004-08-29 13:07:03 +08:00
/* Same for stylesheet */
if (VARDATA(ssheet)[0] == '<')
{
2004-08-29 13:07:03 +08:00
ssdoc = xmlParseMemory((char *) VARDATA(ssheet),
VARSIZE(ssheet) - VARHDRSZ);
if (ssdoc == NULL)
{
xmlFreeDoc(doctree);
xml_ereport(ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
"error parsing stylesheet as XML document");
2004-08-29 13:07:03 +08:00
}
stylesheet = xsltParseStylesheetDoc(ssdoc);
}
2004-08-29 13:07:03 +08:00
else
stylesheet = xsltParseStylesheetFile((xmlChar *) text_to_cstring(ssheet));
2004-08-29 13:07:03 +08:00
if (stylesheet == NULL)
{
xmlFreeDoc(doctree);
xsltCleanupGlobals();
xml_ereport(ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
"failed to parse stylesheet");
2004-08-29 13:07:03 +08:00
}
restree = xsltApplyStylesheet(stylesheet, doctree, params);
resstat = xsltSaveResultToString(&resstr, &reslen, restree, stylesheet);
xsltFreeStylesheet(stylesheet);
xmlFreeDoc(restree);
xmlFreeDoc(doctree);
xsltCleanupGlobals();
if (resstat < 0)
PG_RETURN_NULL();
PG_RETURN_TEXT_P(cstring_to_text_with_len((char *) resstr, reslen));
2010-07-07 03:19:02 +08:00
#else /* !USE_LIBXSLT */
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("xslt_process() is not available without libxslt")));
PG_RETURN_NULL();
2010-07-07 03:19:02 +08:00
#endif /* USE_LIBXSLT */
}
#ifdef USE_LIBXSLT
static void
2004-08-29 13:07:03 +08:00
parse_params(const char **params, text *paramstr)
{
2004-08-29 13:07:03 +08:00
char *pos;
char *pstr;
int i;
char *nvsep = "=";
char *itsep = ",";
pstr = text_to_cstring(paramstr);
2004-08-29 13:07:03 +08:00
pos = pstr;
for (i = 0; i < MAXPARAMS; i++)
{
params[i] = pos;
pos = strstr(pos, nvsep);
if (pos != NULL)
{
*pos = '\0';
pos++;
}
else
{
/* No equal sign, so ignore this "parameter" */
/* We'll reset params[i] to NULL below the loop */
2004-08-29 13:07:03 +08:00
break;
}
/* Value */
i++;
/* since MAXPARAMS is even, we still have i < MAXPARAMS */
2004-08-29 13:07:03 +08:00
params[i] = pos;
pos = strstr(pos, itsep);
if (pos != NULL)
{
*pos = '\0';
pos++;
}
else
{
i++;
2004-08-29 13:07:03 +08:00
break;
}
2004-08-29 13:07:03 +08:00
}
params[i] = NULL;
}
2010-07-07 03:19:02 +08:00
#endif /* USE_LIBXSLT */