Header And Logo

PostgreSQL
| The world's most advanced open source database.

xslt_proc.c

Go to the documentation of this file.
00001 /*
00002  * contrib/xml2/xslt_proc.c
00003  *
00004  * XSLT processing functions (requiring libxslt)
00005  *
00006  * John Gray, for Torchbox 2003-04-01
00007  */
00008 #include "postgres.h"
00009 
00010 #include "executor/spi.h"
00011 #include "fmgr.h"
00012 #include "funcapi.h"
00013 #include "miscadmin.h"
00014 #include "utils/builtins.h"
00015 #include "utils/xml.h"
00016 
00017 #ifdef USE_LIBXSLT
00018 
00019 /* libxml includes */
00020 
00021 #include <libxml/xpath.h>
00022 #include <libxml/tree.h>
00023 #include <libxml/xmlmemory.h>
00024 
00025 /* libxslt includes */
00026 
00027 #include <libxslt/xslt.h>
00028 #include <libxslt/xsltInternals.h>
00029 #include <libxslt/security.h>
00030 #include <libxslt/transform.h>
00031 #include <libxslt/xsltutils.h>
00032 #endif   /* USE_LIBXSLT */
00033 
00034 
00035 /* externally accessible functions */
00036 
00037 Datum       xslt_process(PG_FUNCTION_ARGS);
00038 
00039 #ifdef USE_LIBXSLT
00040 
00041 /* declarations to come from xpath.c */
00042 extern PgXmlErrorContext *pgxml_parser_init(PgXmlStrictness strictness);
00043 
00044 /* local defs */
00045 static const char **parse_params(text *paramstr);
00046 #endif   /* USE_LIBXSLT */
00047 
00048 
00049 PG_FUNCTION_INFO_V1(xslt_process);
00050 
00051 Datum
00052 xslt_process(PG_FUNCTION_ARGS)
00053 {
00054 #ifdef USE_LIBXSLT
00055 
00056     text       *doct = PG_GETARG_TEXT_P(0);
00057     text       *ssheet = PG_GETARG_TEXT_P(1);
00058     text       *result;
00059     text       *paramstr;
00060     const char **params;
00061     PgXmlErrorContext *xmlerrcxt;
00062     volatile xsltStylesheetPtr stylesheet = NULL;
00063     volatile xmlDocPtr doctree = NULL;
00064     volatile xmlDocPtr restree = NULL;
00065     volatile xsltSecurityPrefsPtr xslt_sec_prefs = NULL;
00066     volatile xsltTransformContextPtr xslt_ctxt = NULL;
00067     volatile int resstat = -1;
00068     xmlChar    *resstr = NULL;
00069     int         reslen = 0;
00070 
00071     if (fcinfo->nargs == 3)
00072     {
00073         paramstr = PG_GETARG_TEXT_P(2);
00074         params = parse_params(paramstr);
00075     }
00076     else
00077     {
00078         /* No parameters */
00079         params = (const char **) palloc(sizeof(char *));
00080         params[0] = NULL;
00081     }
00082 
00083     /* Setup parser */
00084     xmlerrcxt = pgxml_parser_init(PG_XML_STRICTNESS_LEGACY);
00085 
00086     PG_TRY();
00087     {
00088         xmlDocPtr   ssdoc;
00089         bool        xslt_sec_prefs_error;
00090 
00091         /* Parse document */
00092         doctree = xmlParseMemory((char *) VARDATA(doct),
00093                                  VARSIZE(doct) - VARHDRSZ);
00094 
00095         if (doctree == NULL)
00096             xml_ereport(xmlerrcxt, ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
00097                         "error parsing XML document");
00098 
00099         /* Same for stylesheet */
00100         ssdoc = xmlParseMemory((char *) VARDATA(ssheet),
00101                                VARSIZE(ssheet) - VARHDRSZ);
00102 
00103         if (ssdoc == NULL)
00104             xml_ereport(xmlerrcxt, ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
00105                         "error parsing stylesheet as XML document");
00106 
00107         /* After this call we need not free ssdoc separately */
00108         stylesheet = xsltParseStylesheetDoc(ssdoc);
00109 
00110         if (stylesheet == NULL)
00111             xml_ereport(xmlerrcxt, ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
00112                         "failed to parse stylesheet");
00113 
00114         xslt_ctxt = xsltNewTransformContext(stylesheet, doctree);
00115 
00116         xslt_sec_prefs_error = false;
00117         if ((xslt_sec_prefs = xsltNewSecurityPrefs()) == NULL)
00118             xslt_sec_prefs_error = true;
00119 
00120         if (xsltSetSecurityPrefs(xslt_sec_prefs, XSLT_SECPREF_READ_FILE,
00121                                  xsltSecurityForbid) != 0)
00122             xslt_sec_prefs_error = true;
00123         if (xsltSetSecurityPrefs(xslt_sec_prefs, XSLT_SECPREF_WRITE_FILE,
00124                                  xsltSecurityForbid) != 0)
00125             xslt_sec_prefs_error = true;
00126         if (xsltSetSecurityPrefs(xslt_sec_prefs, XSLT_SECPREF_CREATE_DIRECTORY,
00127                                  xsltSecurityForbid) != 0)
00128             xslt_sec_prefs_error = true;
00129         if (xsltSetSecurityPrefs(xslt_sec_prefs, XSLT_SECPREF_READ_NETWORK,
00130                                  xsltSecurityForbid) != 0)
00131             xslt_sec_prefs_error = true;
00132         if (xsltSetSecurityPrefs(xslt_sec_prefs, XSLT_SECPREF_WRITE_NETWORK,
00133                                  xsltSecurityForbid) != 0)
00134             xslt_sec_prefs_error = true;
00135         if (xsltSetCtxtSecurityPrefs(xslt_sec_prefs, xslt_ctxt) != 0)
00136             xslt_sec_prefs_error = true;
00137 
00138         if (xslt_sec_prefs_error)
00139             ereport(ERROR,
00140                     (errmsg("could not set libxslt security preferences")));
00141 
00142         restree = xsltApplyStylesheetUser(stylesheet, doctree, params,
00143                                           NULL, NULL, xslt_ctxt);
00144 
00145         if (restree == NULL)
00146             xml_ereport(xmlerrcxt, ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
00147                         "failed to apply stylesheet");
00148 
00149         resstat = xsltSaveResultToString(&resstr, &reslen, restree, stylesheet);
00150     }
00151     PG_CATCH();
00152     {
00153         if (stylesheet != NULL)
00154             xsltFreeStylesheet(stylesheet);
00155         if (restree != NULL)
00156             xmlFreeDoc(restree);
00157         if (doctree != NULL)
00158             xmlFreeDoc(doctree);
00159         if (xslt_sec_prefs != NULL)
00160             xsltFreeSecurityPrefs(xslt_sec_prefs);
00161         if (xslt_ctxt != NULL)
00162             xsltFreeTransformContext(xslt_ctxt);
00163         xsltCleanupGlobals();
00164 
00165         pg_xml_done(xmlerrcxt, true);
00166 
00167         PG_RE_THROW();
00168     }
00169     PG_END_TRY();
00170 
00171     xsltFreeStylesheet(stylesheet);
00172     xmlFreeDoc(restree);
00173     xmlFreeDoc(doctree);
00174     xsltFreeSecurityPrefs(xslt_sec_prefs);
00175     xsltFreeTransformContext(xslt_ctxt);
00176     xsltCleanupGlobals();
00177 
00178     pg_xml_done(xmlerrcxt, false);
00179 
00180     /* XXX this is pretty dubious, really ought to throw error instead */
00181     if (resstat < 0)
00182         PG_RETURN_NULL();
00183 
00184     result = cstring_to_text_with_len((char *) resstr, reslen);
00185 
00186     if (resstr)
00187         xmlFree(resstr);
00188 
00189     PG_RETURN_TEXT_P(result);
00190 #else                           /* !USE_LIBXSLT */
00191 
00192     ereport(ERROR,
00193             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00194              errmsg("xslt_process() is not available without libxslt")));
00195     PG_RETURN_NULL();
00196 #endif   /* USE_LIBXSLT */
00197 }
00198 
00199 #ifdef USE_LIBXSLT
00200 
00201 static const char **
00202 parse_params(text *paramstr)
00203 {
00204     char       *pos;
00205     char       *pstr;
00206     char       *nvsep = "=";
00207     char       *itsep = ",";
00208     const char **params;
00209     int         max_params;
00210     int         nparams;
00211 
00212     pstr = text_to_cstring(paramstr);
00213 
00214     max_params = 20;            /* must be even! */
00215     params = (const char **) palloc((max_params + 1) * sizeof(char *));
00216     nparams = 0;
00217 
00218     pos = pstr;
00219 
00220     while (*pos != '\0')
00221     {
00222         if (nparams >= max_params)
00223         {
00224             max_params *= 2;
00225             params = (const char **) repalloc(params,
00226                                           (max_params + 1) * sizeof(char *));
00227         }
00228         params[nparams++] = pos;
00229         pos = strstr(pos, nvsep);
00230         if (pos != NULL)
00231         {
00232             *pos = '\0';
00233             pos++;
00234         }
00235         else
00236         {
00237             /* No equal sign, so ignore this "parameter" */
00238             nparams--;
00239             break;
00240         }
00241 
00242         /* since max_params is even, we still have nparams < max_params */
00243         params[nparams++] = pos;
00244         pos = strstr(pos, itsep);
00245         if (pos != NULL)
00246         {
00247             *pos = '\0';
00248             pos++;
00249         }
00250         else
00251             break;
00252     }
00253 
00254     /* Add the terminator marker; we left room for it in the palloc's */
00255     params[nparams] = NULL;
00256 
00257     return params;
00258 }
00259 
00260 #endif   /* USE_LIBXSLT */