Fix xslt_process() to ensure that it inserts a NULL terminator after the
[PostgreSQL.git] / contrib / xml2 / xslt_proc.c
blob798e688983cd13bb85b51a678ad9b61e43cb229f
1 /*
2 * $PostgreSQL$
4 * XSLT processing functions (requiring libxslt)
6 * John Gray, for Torchbox 2003-04-01
7 */
8 #include "postgres.h"
10 #include "executor/spi.h"
11 #include "fmgr.h"
12 #include "funcapi.h"
13 #include "miscadmin.h"
14 #include "utils/builtins.h"
16 /* libxml includes */
18 #include <libxml/xpath.h>
19 #include <libxml/tree.h>
20 #include <libxml/xmlmemory.h>
22 /* libxslt includes */
24 #include <libxslt/xslt.h>
25 #include <libxslt/xsltInternals.h>
26 #include <libxslt/transform.h>
27 #include <libxslt/xsltutils.h>
30 /* declarations to come from xpath.c */
31 extern void elog_error(int level, char *explain, int force);
32 extern void pgxml_parser_init();
33 extern xmlChar *pgxml_texttoxmlchar(text *textstring);
35 /* local defs */
36 static void parse_params(const char **params, text *paramstr);
38 Datum xslt_process(PG_FUNCTION_ARGS);
41 #define MAXPARAMS 20 /* must be even, see parse_params() */
44 PG_FUNCTION_INFO_V1(xslt_process);
46 Datum
47 xslt_process(PG_FUNCTION_ARGS)
49 text *doct = PG_GETARG_TEXT_P(0);
50 text *ssheet = PG_GETARG_TEXT_P(1);
51 text *paramstr;
52 const char *params[MAXPARAMS + 1]; /* +1 for the terminator */
53 xsltStylesheetPtr stylesheet = NULL;
54 xmlDocPtr doctree;
55 xmlDocPtr restree;
56 xmlDocPtr ssdoc = NULL;
57 xmlChar *resstr;
58 int resstat;
59 int reslen;
61 if (fcinfo->nargs == 3)
63 paramstr = PG_GETARG_TEXT_P(2);
64 parse_params(params, paramstr);
66 else
67 /* No parameters */
68 params[0] = NULL;
70 /* Setup parser */
71 pgxml_parser_init();
73 /* Check to see if document is a file or a literal */
75 if (VARDATA(doct)[0] == '<')
76 doctree = xmlParseMemory((char *) VARDATA(doct), VARSIZE(doct) - VARHDRSZ);
77 else
78 doctree = xmlParseFile(text_to_cstring(doct));
80 if (doctree == NULL)
82 xmlCleanupParser();
83 elog_error(ERROR, "error parsing XML document", 0);
85 PG_RETURN_NULL();
88 /* Same for stylesheet */
89 if (VARDATA(ssheet)[0] == '<')
91 ssdoc = xmlParseMemory((char *) VARDATA(ssheet),
92 VARSIZE(ssheet) - VARHDRSZ);
93 if (ssdoc == NULL)
95 xmlFreeDoc(doctree);
96 xmlCleanupParser();
97 elog_error(ERROR, "error parsing stylesheet as XML document", 0);
98 PG_RETURN_NULL();
101 stylesheet = xsltParseStylesheetDoc(ssdoc);
103 else
104 stylesheet = xsltParseStylesheetFile((xmlChar *) text_to_cstring(ssheet));
107 if (stylesheet == NULL)
109 xmlFreeDoc(doctree);
110 xsltCleanupGlobals();
111 xmlCleanupParser();
112 elog_error(ERROR, "failed to parse stylesheet", 0);
113 PG_RETURN_NULL();
116 restree = xsltApplyStylesheet(stylesheet, doctree, params);
117 resstat = xsltSaveResultToString(&resstr, &reslen, restree, stylesheet);
119 xsltFreeStylesheet(stylesheet);
120 xmlFreeDoc(restree);
121 xmlFreeDoc(doctree);
123 xsltCleanupGlobals();
124 xmlCleanupParser();
126 if (resstat < 0)
127 PG_RETURN_NULL();
129 PG_RETURN_TEXT_P(cstring_to_text_with_len((char *) resstr, reslen));
133 static void
134 parse_params(const char **params, text *paramstr)
136 char *pos;
137 char *pstr;
138 int i;
139 char *nvsep = "=";
140 char *itsep = ",";
142 pstr = text_to_cstring(paramstr);
144 pos = pstr;
146 for (i = 0; i < MAXPARAMS; i++)
148 params[i] = pos;
149 pos = strstr(pos, nvsep);
150 if (pos != NULL)
152 *pos = '\0';
153 pos++;
155 else
157 /* No equal sign, so ignore this "parameter" */
158 /* We'll reset params[i] to NULL below the loop */
159 break;
161 /* Value */
162 i++;
163 /* since MAXPARAMS is even, we still have i < MAXPARAMS */
164 params[i] = pos;
165 pos = strstr(pos, itsep);
166 if (pos != NULL)
168 *pos = '\0';
169 pos++;
171 else
173 i++;
174 break;
178 params[i] = NULL;