~vcs-imports/mammoth-replicator/trunk

« back to all changes in this revision

Viewing changes to contrib/xml/pgxml_dom.c

  • Committer: alvherre
  • Date: 2005-12-16 21:24:52 UTC
  • Revision ID: svn-v4:db760fc0-0f08-0410-9d63-cc6633f64896:trunk:1
Initial import of the REL8_0_3 sources from the Pgsql CVS repository.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Parser interface for DOM-based parser (libxml) rather than
 
2
   stream-based SAX-type parser */
 
3
 
 
4
#include "postgres.h"
 
5
#include "fmgr.h"
 
6
 
 
7
/* libxml includes */
 
8
 
 
9
#include <libxml/xpath.h>
 
10
#include <libxml/tree.h>
 
11
#include <libxml/xmlmemory.h>
 
12
 
 
13
/* declarations */
 
14
 
 
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);
 
19
 
 
20
static void pgxml_parser_init();
 
21
 
 
22
static xmlChar *pgxmlNodeSetToText(xmlNodeSetPtr nodeset, xmlDocPtr doc,
 
23
                                   xmlChar * toptagname, xmlChar * septagname,
 
24
                                   int format);
 
25
 
 
26
static xmlChar *pgxml_texttoxmlchar(text *textstring);
 
27
 
 
28
 
 
29
Datum           pgxml_parse(PG_FUNCTION_ARGS);
 
30
Datum           pgxml_xpath(PG_FUNCTION_ARGS);
 
31
 
 
32
/* memory handling passthrough functions (e.g. palloc, pstrdup are
 
33
   currently macros, and the others might become so...) */
 
34
 
 
35
static void *
 
36
pgxml_palloc(size_t size)
 
37
{
 
38
        return palloc(size);
 
39
}
 
40
 
 
41
static void *
 
42
pgxml_repalloc(void *ptr, size_t size)
 
43
{
 
44
        return repalloc(ptr, size);
 
45
}
 
46
 
 
47
static void
 
48
pgxml_pfree(void *ptr)
 
49
{
 
50
        pfree(ptr);
 
51
}
 
52
 
 
53
static char *
 
54
pgxml_pstrdup(const char *string)
 
55
{
 
56
        return pstrdup(string);
 
57
}
 
58
 
 
59
static void
 
60
pgxml_parser_init()
 
61
{
 
62
        /*
 
63
         * This code should also set parser settings from  user-supplied info.
 
64
         * Quite how these settings are made is another matter :)
 
65
         */
 
66
 
 
67
        xmlMemSetup(pgxml_pfree, pgxml_palloc, pgxml_repalloc, pgxml_pstrdup);
 
68
        xmlInitParser();
 
69
 
 
70
}
 
71
 
 
72
 
 
73
/* Returns true if document is well-formed */
 
74
 
 
75
PG_FUNCTION_INFO_V1(pgxml_parse);
 
76
 
 
77
Datum
 
78
pgxml_parse(PG_FUNCTION_ARGS)
 
79
{
 
80
        /* called as pgxml_parse(document) */
 
81
        xmlDocPtr       doctree;
 
82
        text       *t = PG_GETARG_TEXT_P(0);            /* document buffer */
 
83
        int32           docsize = VARSIZE(t) - VARHDRSZ;
 
84
 
 
85
        pgxml_parser_init();
 
86
 
 
87
        doctree = xmlParseMemory((char *) VARDATA(t), docsize);
 
88
        if (doctree == NULL)
 
89
        {
 
90
                xmlCleanupParser();
 
91
                PG_RETURN_BOOL(false);  /* i.e. not well-formed */
 
92
        }
 
93
        xmlCleanupParser();
 
94
        xmlFreeDoc(doctree);
 
95
        PG_RETURN_BOOL(true);
 
96
}
 
97
 
 
98
static xmlChar
 
99
*
 
100
pgxmlNodeSetToText(xmlNodeSetPtr nodeset,
 
101
                                   xmlDocPtr doc,
 
102
                                   xmlChar * toptagname,
 
103
                                   xmlChar * septagname,
 
104
                                   int format)
 
105
{
 
106
        /* Function translates a nodeset into a text representation */
 
107
 
 
108
        /*
 
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.
 
111
         */
 
112
        /* each representation is surrounded by <tagname> ... </tagname> */
 
113
        /* if format==0, add a newline between nodes?? */
 
114
 
 
115
        xmlBufferPtr buf;
 
116
        xmlChar    *result;
 
117
        int                     i;
 
118
 
 
119
        buf = xmlBufferCreate();
 
120
 
 
121
        if ((toptagname != NULL) && (xmlStrlen(toptagname) > 0))
 
122
        {
 
123
                xmlBufferWriteChar(buf, "<");
 
124
                xmlBufferWriteCHAR(buf, toptagname);
 
125
                xmlBufferWriteChar(buf, ">");
 
126
        }
 
127
        if (nodeset != NULL)
 
128
        {
 
129
                for (i = 0; i < nodeset->nodeNr; i++)
 
130
                {
 
131
                        if ((septagname != NULL) && (xmlStrlen(septagname) > 0))
 
132
                        {
 
133
                                xmlBufferWriteChar(buf, "<");
 
134
                                xmlBufferWriteCHAR(buf, septagname);
 
135
                                xmlBufferWriteChar(buf, ">");
 
136
                        }
 
137
                        xmlNodeDump(buf, doc, nodeset->nodeTab[i], 1, (format == 2));
 
138
 
 
139
                        if ((septagname != NULL) && (xmlStrlen(septagname) > 0))
 
140
                        {
 
141
                                xmlBufferWriteChar(buf, "</");
 
142
                                xmlBufferWriteCHAR(buf, septagname);
 
143
                                xmlBufferWriteChar(buf, ">");
 
144
                        }
 
145
                        if (format)
 
146
                                xmlBufferWriteChar(buf, "\n");
 
147
                }
 
148
        }
 
149
 
 
150
        if ((toptagname != NULL) && (xmlStrlen(toptagname) > 0))
 
151
        {
 
152
                xmlBufferWriteChar(buf, "</");
 
153
                xmlBufferWriteCHAR(buf, toptagname);
 
154
                xmlBufferWriteChar(buf, ">");
 
155
        }
 
156
        result = xmlStrdup(buf->content);
 
157
        xmlBufferFree(buf);
 
158
        return result;
 
159
}
 
160
 
 
161
static xmlChar *
 
162
pgxml_texttoxmlchar(text *textstring)
 
163
{
 
164
        xmlChar    *res;
 
165
        int32           txsize;
 
166
 
 
167
        txsize = VARSIZE(textstring) - VARHDRSZ;
 
168
        res = (xmlChar *) palloc(txsize + 1);
 
169
        memcpy((char *) res, VARDATA(textstring), txsize);
 
170
        res[txsize] = '\0';
 
171
        return res;
 
172
}
 
173
 
 
174
 
 
175
PG_FUNCTION_INFO_V1(pgxml_xpath);
 
176
 
 
177
Datum
 
178
pgxml_xpath(PG_FUNCTION_ARGS)
 
179
{
 
180
        xmlDocPtr       doctree;
 
181
        xmlXPathContextPtr ctxt;
 
182
        xmlXPathObjectPtr res;
 
183
        xmlChar    *xpath,
 
184
                           *xpresstr,
 
185
                           *toptag,
 
186
                           *septag;
 
187
        xmlXPathCompExprPtr comppath;
 
188
 
 
189
        int32           docsize,
 
190
                                ressize;
 
191
        text       *t,
 
192
                           *xpres;
 
193
 
 
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));
 
198
 
 
199
        docsize = VARSIZE(t) - VARHDRSZ;
 
200
 
 
201
        pgxml_parser_init();
 
202
 
 
203
        doctree = xmlParseMemory((char *) VARDATA(t), docsize);
 
204
        if (doctree == NULL)
 
205
        {                                                       /* not well-formed */
 
206
                xmlCleanupParser();
 
207
                PG_RETURN_NULL();
 
208
        }
 
209
 
 
210
        ctxt = xmlXPathNewContext(doctree);
 
211
        ctxt->node = xmlDocGetRootElement(doctree);
 
212
 
 
213
        /* compile the path */
 
214
        comppath = xmlXPathCompile(xpath);
 
215
        if (comppath == NULL)
 
216
        {
 
217
                elog(WARNING, "XPath syntax error");
 
218
                xmlFreeDoc(doctree);
 
219
                pfree(xpath);
 
220
                xmlCleanupParser();
 
221
                PG_RETURN_NULL();
 
222
        }
 
223
 
 
224
        /* Now evaluate the path expression. */
 
225
        res = xmlXPathCompiledEval(comppath, ctxt);
 
226
        xmlXPathFreeCompExpr(comppath);
 
227
 
 
228
        if (res == NULL)
 
229
        {
 
230
                xmlFreeDoc(doctree);
 
231
                pfree(xpath);
 
232
                xmlCleanupParser();
 
233
                PG_RETURN_NULL();               /* seems appropriate */
 
234
        }
 
235
        /* now we dump this node, ?surrounding by tags? */
 
236
        /* To do this, we look first at the type */
 
237
        switch (res->type)
 
238
        {
 
239
                case XPATH_NODESET:
 
240
                        xpresstr = pgxmlNodeSetToText(res->nodesetval,
 
241
                                                                                  doctree,
 
242
                                                                                  toptag, septag, 0);
 
243
                        break;
 
244
                case XPATH_STRING:
 
245
                        xpresstr = xmlStrdup(res->stringval);
 
246
                        break;
 
247
                default:
 
248
                        elog(WARNING, "Unsupported XQuery result: %d", res->type);
 
249
                        xpresstr = xmlStrdup("<unsupported/>");
 
250
        }
 
251
 
 
252
 
 
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;
 
258
 
 
259
        /* Free various storage */
 
260
        xmlFreeDoc(doctree);
 
261
        pfree(xpath);
 
262
        xmlFree(xpresstr);
 
263
        xmlCleanupParser();
 
264
        PG_RETURN_TEXT_P(xpres);
 
265
}