1
/* Parser interface for DOM-based parser (libxml) rather than
2
stream-based SAX-type parser */
9
#include <libxml/xpath.h>
10
#include <libxml/tree.h>
11
#include <libxml/xmlmemory.h>
15
static void *pgxml_palloc(size_t size);
16
static void *pgxml_repalloc(void *ptr, size_t size);
17
static void pgxml_pfree(void *ptr);
18
static char *pgxml_pstrdup(const char *string);
20
static void pgxml_parser_init();
22
static xmlChar *pgxmlNodeSetToText(xmlNodeSetPtr nodeset, xmlDocPtr doc,
23
xmlChar * toptagname, xmlChar * septagname,
26
static xmlChar *pgxml_texttoxmlchar(text *textstring);
29
Datum pgxml_parse(PG_FUNCTION_ARGS);
30
Datum pgxml_xpath(PG_FUNCTION_ARGS);
32
/* memory handling passthrough functions (e.g. palloc, pstrdup are
33
currently macros, and the others might become so...) */
36
pgxml_palloc(size_t size)
42
pgxml_repalloc(void *ptr, size_t size)
44
return repalloc(ptr, size);
48
pgxml_pfree(void *ptr)
54
pgxml_pstrdup(const char *string)
56
return pstrdup(string);
63
* This code should also set parser settings from user-supplied info.
64
* Quite how these settings are made is another matter :)
67
xmlMemSetup(pgxml_pfree, pgxml_palloc, pgxml_repalloc, pgxml_pstrdup);
73
/* Returns true if document is well-formed */
75
PG_FUNCTION_INFO_V1(pgxml_parse);
78
pgxml_parse(PG_FUNCTION_ARGS)
80
/* called as pgxml_parse(document) */
82
text *t = PG_GETARG_TEXT_P(0); /* document buffer */
83
int32 docsize = VARSIZE(t) - VARHDRSZ;
87
doctree = xmlParseMemory((char *) VARDATA(t), docsize);
91
PG_RETURN_BOOL(false); /* i.e. not well-formed */
100
pgxmlNodeSetToText(xmlNodeSetPtr nodeset,
102
xmlChar * toptagname,
103
xmlChar * septagname,
106
/* Function translates a nodeset into a text representation */
109
* iterates over each node in the set and calls xmlNodeDump to write
110
* it to an xmlBuffer -from which an xmlChar * string is returned.
112
/* each representation is surrounded by <tagname> ... </tagname> */
113
/* if format==0, add a newline between nodes?? */
119
buf = xmlBufferCreate();
121
if ((toptagname != NULL) && (xmlStrlen(toptagname) > 0))
123
xmlBufferWriteChar(buf, "<");
124
xmlBufferWriteCHAR(buf, toptagname);
125
xmlBufferWriteChar(buf, ">");
129
for (i = 0; i < nodeset->nodeNr; i++)
131
if ((septagname != NULL) && (xmlStrlen(septagname) > 0))
133
xmlBufferWriteChar(buf, "<");
134
xmlBufferWriteCHAR(buf, septagname);
135
xmlBufferWriteChar(buf, ">");
137
xmlNodeDump(buf, doc, nodeset->nodeTab[i], 1, (format == 2));
139
if ((septagname != NULL) && (xmlStrlen(septagname) > 0))
141
xmlBufferWriteChar(buf, "</");
142
xmlBufferWriteCHAR(buf, septagname);
143
xmlBufferWriteChar(buf, ">");
146
xmlBufferWriteChar(buf, "\n");
150
if ((toptagname != NULL) && (xmlStrlen(toptagname) > 0))
152
xmlBufferWriteChar(buf, "</");
153
xmlBufferWriteCHAR(buf, toptagname);
154
xmlBufferWriteChar(buf, ">");
156
result = xmlStrdup(buf->content);
162
pgxml_texttoxmlchar(text *textstring)
167
txsize = VARSIZE(textstring) - VARHDRSZ;
168
res = (xmlChar *) palloc(txsize + 1);
169
memcpy((char *) res, VARDATA(textstring), txsize);
175
PG_FUNCTION_INFO_V1(pgxml_xpath);
178
pgxml_xpath(PG_FUNCTION_ARGS)
181
xmlXPathContextPtr ctxt;
182
xmlXPathObjectPtr res;
187
xmlXPathCompExprPtr comppath;
194
t = PG_GETARG_TEXT_P(0); /* document buffer */
195
xpath = pgxml_texttoxmlchar(PG_GETARG_TEXT_P(1)); /* XPath expression */
196
toptag = pgxml_texttoxmlchar(PG_GETARG_TEXT_P(2));
197
septag = pgxml_texttoxmlchar(PG_GETARG_TEXT_P(3));
199
docsize = VARSIZE(t) - VARHDRSZ;
203
doctree = xmlParseMemory((char *) VARDATA(t), docsize);
205
{ /* not well-formed */
210
ctxt = xmlXPathNewContext(doctree);
211
ctxt->node = xmlDocGetRootElement(doctree);
213
/* compile the path */
214
comppath = xmlXPathCompile(xpath);
215
if (comppath == NULL)
217
elog(WARNING, "XPath syntax error");
224
/* Now evaluate the path expression. */
225
res = xmlXPathCompiledEval(comppath, ctxt);
226
xmlXPathFreeCompExpr(comppath);
233
PG_RETURN_NULL(); /* seems appropriate */
235
/* now we dump this node, ?surrounding by tags? */
236
/* To do this, we look first at the type */
240
xpresstr = pgxmlNodeSetToText(res->nodesetval,
245
xpresstr = xmlStrdup(res->stringval);
248
elog(WARNING, "Unsupported XQuery result: %d", res->type);
249
xpresstr = xmlStrdup("<unsupported/>");
253
/* Now convert this result back to text */
254
ressize = strlen(xpresstr);
255
xpres = (text *) palloc(ressize + VARHDRSZ);
256
memcpy(VARDATA(xpres), xpresstr, ressize);
257
VARATT_SIZEP(xpres) = ressize + VARHDRSZ;
259
/* Free various storage */
264
PG_RETURN_TEXT_P(xpres);