Hi all,
Well I had to burn some midnight oil trying to figure out why a
construct like
SELECT xpath('name()','<a/>');
doesn't give the expected result. Kept getting an empty array:
xpath
-------------
{}
instead of the expected "{a}"
BugID 4294 and the TODO item "better handling of XPath data types"
pointed in the right direction.
whithin src/backend/utils/adt/xml.c in the function xpath the result of
the call to xmlXPathCompiledEval is not handled optimally. In fact, the
result is assumed to be a nodeset without consulting the ->type member
of the result. I've made some minor changes to xml.c to handle some
non-nodeset results of xmlXPathCompiledEval.
Essentially, the revised code makes an array of all the nodes in the
xpathobj result in case this is a nodeset, or an array with a single
element in case the reult is a number/string/boolean. The problem cases
mentioned in
http://archives.postgresql.org/pgsql-hackers/2008-06/msg00616.php now
work as expected.
Revision of the code involves:
- A switch statement to handle the result type of xmlXPathCompiledEval.
- an additional function xmlpathobjtoxmltype.
diff of the revisioned code with respect to original is in attached file.
kind regards, Arie Bikker
114d113
< static text *xml_xmlpathobjtoxmltype(xmlXPathObjectPtr cur);
3269,3309d3267
<
< /*
< * Convert XML pathobject to text for non-nodeset objects
< */
< static text *
< xml_xmlpathobjtoxmltype(xmlXPathObjectPtr cur)
< {
< xmltype *result;
<
< if (cur->type == XPATH_BOOLEAN)
< {
< PG_TRY();
< {
< result = cstring_to_text((char *)(xmlXPathCastToBoolean(cur)?"t":"f"));
< }
< PG_CATCH();
< {
< PG_RE_THROW();
< }
< PG_END_TRY();
< }
< else
< {
< xmlChar *str;
<
< str = xmlXPathCastToString(cur);
< PG_TRY();
< {
< result = (xmltype *) cstring_to_text((char *) str);
< }
< PG_CATCH();
< {
< xmlFree(str);
< PG_RE_THROW();
< }
< PG_END_TRY();
< xmlFree(str);
< }
<
< return result;
< }
3463,3471c3421,3429
< switch (xpathobj->type) {
< case XPATH_NODESET: {
< /* return empty array in cases when nothing is found */
< if (xpathobj->nodesetval == NULL)
< res_nitems = 0;
< else
< res_nitems = xpathobj->nodesetval->nodeNr;
<
< if (res_nitems)
---
> /* return empty array in cases when nothing is found */
> if (xpathobj->nodesetval == NULL)
> res_nitems = 0;
> else
> res_nitems = xpathobj->nodesetval->nodeNr;
>
> if (res_nitems)
> {
> for (i = 0; i < xpathobj->nodesetval->nodeNr; i++)
3473,3482c3431,3437
< for (i = 0; i < xpathobj->nodesetval->nodeNr; i++)
< {
< Datum elem;
< bool elemisnull = false;
<
< elem = PointerGetDatum(xml_xmlnodetoxmltype(xpathobj->nodesetval->nodeTab[i]));
< astate = accumArrayResult(astate, elem,
< elemisnull, XMLOID,
< CurrentMemoryContext);
< }
---
> Datum elem;
> bool elemisnull = false;
>
> elem = PointerGetDatum(xml_xmlnodetoxmltype(xpathobj->nodesetval->nodeTab[i]));
> astate = accumArrayResult(astate, elem,
> elemisnull, XMLOID,
> CurrentMemoryContext);
3484d3438
< break;
3486,3500d3439
< case XPATH_BOOLEAN:
< case XPATH_NUMBER:
< case XPATH_STRING: {
< Datum elem;
< bool elemisnull = false;
<
< elem = PointerGetDatum(xml_xmlpathobjtoxmltype(xpathobj));
< astate = accumArrayResult(astate, elem,
< elemisnull, XMLOID,
< CurrentMemoryContext);
< break;
< }
< default: {
< }
< }
3524c3463
< if (astate== NULL)
---
> if (res_nitems == 0)
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers