Hello, Here is the patch for contrib/xml2 (attached), that: - renames xml_valid() to xml_is_well_formed() - adds PG_MODULE_MAGIC; at the beginning of xpath.c - introduces xpath_array() function - adds some words about that function and caution about libraries to README
I understand that it's too late, but xpath_array() is pretty simple function (and, actually, this is a tiny step to XQuery sequences). Besides that, it is mentioned in the current TODO list and I've told about this before. Actually, this is at least some [minor] addition for this module for 8.2. Let me know if I can help somehow else in this direction. -- Best regards, Nikolay
Index: README.xml2 =================================================================== RCS file: /projects/cvsroot/pgsql/contrib/xml2/README.xml2,v retrieving revision 1.6 diff -u -r1.6 README.xml2 --- README.xml2 25 Aug 2006 23:45:02 -0000 1.6 +++ README.xml2 5 Sep 2006 21:51:23 -0000 @@ -21,14 +21,16 @@ Before you begin, just check the Makefile, and then just 'make' and 'make install'. -This code requires libxml to be previously installed. +By default, this module requires both libxml2 and libxslt installed +on your system. If you do not have libxslt or do not want to use XSLT +functions, you should edit Makefile to remove mentioning of XSLT. Description of functions ------------------------ The first set of functions are straightforward XML parsing and XPath queries: -xml_valid(document) RETURNS bool +xml_is_well_formed(document) RETURNS bool This parses the document text in its parameter and returns true if the document is well-formed XML. @@ -67,6 +69,12 @@ This is a wrapper for the above function that uses ',' as the seperator. +xpath_array(document,query) RETURNS text[] + +This function returns array of text values. In common case, XPath +evaluation produces a set of values (a set of strings, a set of integers +or a set of XML chunks). Text array returned by this functions corresponds +to that set of values. xpath_table ----------- Index: pgxml.sql.in =================================================================== RCS file: /projects/cvsroot/pgsql/contrib/xml2/pgxml.sql.in,v retrieving revision 1.8 diff -u -r1.8 pgxml.sql.in --- pgxml.sql.in 27 Feb 2006 16:09:49 -0000 1.8 +++ pgxml.sql.in 5 Sep 2006 21:51:23 -0000 @@ -1,6 +1,6 @@ --SQL for XML parser -CREATE OR REPLACE FUNCTION xml_valid(text) RETURNS bool +CREATE OR REPLACE FUNCTION xml_is_well_formed(text) RETURNS bool AS 'MODULE_PATHNAME' LANGUAGE C STRICT IMMUTABLE; CREATE OR REPLACE FUNCTION xml_encode_special_chars(text) RETURNS text @@ -24,6 +24,10 @@ AS 'MODULE_PATHNAME' LANGUAGE C STRICT IMMUTABLE; +-- Array returning XPath function +CREATE OR REPLACE FUNCTION xpath_array(text,text) RETURNS _text + AS 'MODULE_PATHNAME' LANGUAGE C STRICT IMMUTABLE; + CREATE OR REPLACE FUNCTION xpath_list(text,text) RETURNS text AS 'SELECT xpath_list($1,$2,'','')' LANGUAGE SQL STRICT IMMUTABLE; @@ -46,15 +50,3 @@ AS 'MODULE_PATHNAME' LANGUAGE C STRICT STABLE; --- XSLT functions --- Delete from here to the end of the file if you are not compiling with --- XSLT support. - - -CREATE OR REPLACE FUNCTION xslt_process(text,text,text) RETURNS text - AS 'MODULE_PATHNAME' LANGUAGE C STRICT VOLATILE; - --- the function checks for the correct argument count - -CREATE OR REPLACE FUNCTION xslt_process(text,text) RETURNS text - AS 'MODULE_PATHNAME' LANGUAGE C STRICT IMMUTABLE; Index: xpath.c =================================================================== RCS file: /projects/cvsroot/pgsql/contrib/xml2/xpath.c,v retrieving revision 1.11 diff -u -r1.11 xpath.c --- xpath.c 23 May 2006 15:21:51 -0000 1.11 +++ xpath.c 5 Sep 2006 21:51:24 -0000 @@ -16,6 +16,8 @@ #include <libxml/xmlerror.h> #include <libxml/parserInternals.h> +PG_MODULE_MAGIC; + /* declarations */ static void *pgxml_palloc(size_t size); @@ -30,6 +32,8 @@ static xmlChar *pgxmlNodeSetToText(xmlNodeSetPtr nodeset, xmlChar * toptagname, xmlChar * septagname, xmlChar * plainsep); + +text *pgxml_node_dump_to_text(xmlNodePtr cur); text *pgxml_result_to_text(xmlXPathObjectPtr res, xmlChar * toptag, xmlChar * septag, xmlChar * plainsep); @@ -38,14 +42,14 @@ static xmlXPathObjectPtr pgxml_xpath(text *document, xmlChar * xpath); - -Datum xml_valid(PG_FUNCTION_ARGS); +Datum xml_is_well_formed(PG_FUNCTION_ARGS); Datum xml_encode_special_chars(PG_FUNCTION_ARGS); Datum xpath_nodeset(PG_FUNCTION_ARGS); Datum xpath_string(PG_FUNCTION_ARGS); Datum xpath_number(PG_FUNCTION_ARGS); Datum xpath_bool(PG_FUNCTION_ARGS); Datum xpath_list(PG_FUNCTION_ARGS); +Datum xpath_array(PG_FUNCTION_ARGS); Datum xpath_table(PG_FUNCTION_ARGS); /* Global variables */ @@ -163,12 +167,12 @@ /* Returns true if document is well-formed */ -PG_FUNCTION_INFO_V1(xml_valid); +PG_FUNCTION_INFO_V1(xml_is_well_formed); Datum -xml_valid(PG_FUNCTION_ARGS) +xml_is_well_formed(PG_FUNCTION_ARGS) { - /* called as xml_valid(document) */ + /* called as xml_is_well_formed(document) */ xmlDocPtr doctree; text *t = PG_GETARG_TEXT_P(0); /* document buffer */ int32 docsize = VARSIZE(t) - VARHDRSZ; @@ -513,7 +517,56 @@ } +/* + * Evaluate XPath expression and return array of XML chunks (array of text values) + */ +PG_FUNCTION_INFO_V1(xpath_array); +Datum +xpath_array(PG_FUNCTION_ARGS) +{ + xmlXPathObjectPtr xpathobj; + ArrayBuildState *astate = NULL; + xmlChar *xpath; + int i; + int32 pathsize; + text *xpathsupp; + + /* PG_GETARG_TEXT_P(0) is document buffer */ + xpathsupp = PG_GETARG_TEXT_P(1); /* XPath expression */ + pathsize = VARSIZE(xpathsupp) - VARHDRSZ; + xpath = pgxml_texttoxmlchar(xpathsupp); + + xpathobj = pgxml_xpath(PG_GETARG_TEXT_P(0), xpath); + if (xpathobj == NULL + || xpathobj->nodesetval == NULL + || xpathobj->nodesetval->nodeNr == 0) + { + /* Note, that throwing ERROR might be more proper solution + here (at least in one of these three cases); + meanwhile, keep silence here, as in other xpath_*() functions */ + xmlCleanupParser(); + PG_RETURN_NULL(); + } + + for (i = 0; i < xpathobj->nodesetval->nodeNr; i++) + { + xmlChar *str; + text *txt; + Datum elem; + bool elemisnull = false; + txt = pgxml_node_dump_to_text(xpathobj->nodesetval->nodeTab[i]); + elem = PointerGetDatum(txt); + astate = accumArrayResult(astate, elem, + elemisnull, TEXTOID, + CurrentMemoryContext); + } + + xmlXPathFreeObject(xpathobj); + xmlCleanupParser(); + + PG_RETURN_ARRAYTYPE_P(makeArrayResult(astate, CurrentMemoryContext)); +} /* Core function to evaluate XPath query */ @@ -623,6 +676,27 @@ return xpres; } +/* dumps XML node to text (serialization) */ +text * +pgxml_node_dump_to_text(xmlNodePtr cur) +{ + xmlBufferPtr buf; + xmlChar *str; + text *result; + size_t len; + + buf = xmlBufferCreate(); + xmlNodeDump(buf, cur->doc, cur, 1, 0); + str = xmlStrdup(buf->content); + xmlBufferFree(buf); + len = strlen(str); + result = (text *) palloc(len + VARHDRSZ); + VARATT_SIZEP(result) = len + VARHDRSZ; + memcpy(VARDATA(result), str, len); + + return result; +} + /* xpath_table is a table function. It needs some tidying (as do the * other functions here! */
---------------------------(end of broadcast)--------------------------- TIP 4: Have you searched our list archives? http://archives.postgresql.org