- Function renamed to "xpath".
- Function is now strict, per discussion.
- Return empty array in case when XPath expression detects nothing
(previously, NULL was returned in such case), per discussion.
- (bugfix) Work with fragments with prologue: select xpath('/a',
'<?xml version="1.0"?><a /><b />'); // now XML datum is always wrapped
with dummy <x>...</x>, XML prologue simply goes away (if any).
- Some cleanup.
Nikolay Samokhvalov
Some code cleanup and documentation work by myself.
-<!-- $PostgreSQL: pgsql/doc/src/sgml/datatype.sgml,v 1.200 2007/05/08 17:02:59 tgl Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/datatype.sgml,v 1.201 2007/05/21 17:10:28 petere Exp $ -->
<chapter id="datatype">
<title id="datatype-title">Data Types</title>
<sect1 id="datatype-uuid">
<title><acronym>UUID</acronym> Type</title>
- <indexterm zone="datatype-xml">
+ <indexterm zone="datatype-uuid">
<primary>UUID</primary>
</indexterm>
value is a full document or only a content fragment.
</para>
+ <sect2>
+ <title>Creating XML Values</title>
<para>
To produce a value of type <type>xml</type> from character data,
use the function
Examples:
<programlisting><![CDATA[
XMLPARSE (DOCUMENT '<?xml version="1.0"?><book><title>Manual</title><chapter>...</chapter><book>')
-XMLPARSE (CONTENT 'abc<foo>bar</bar><bar>foo</foo>')
+XMLPARSE (CONTENT 'abc<foo>bar</foo><bar>foo</bar>')
]]></programlisting>
While this is the only way to convert character strings into XML
values according to the SQL standard, the PostgreSQL-specific
The default is <literal>CONTENT</literal>, so all forms of XML
data are allowed.
</para>
+ </sect2>
+ <sect2>
+ <title>Encoding Handling</title>
<para>
Care must be taken when dealing with multiple character encodings
on the client, server, and in the XML data passed through them.
processed in UTF-8, computations will be most efficient if the
server encoding is also UTF-8.
</para>
+ </sect2>
+
+ <sect2>
+ <title>Accessing XML Values</title>
+
+ <para>
+ The <type>xml</type> data type is unusual in that it does not
+ provide any comparison operators. This is because there is no
+ well-defined and universally useful comparison algorithm for XML
+ data. One consequence of this is that you cannot retrieve rows by
+ comparing an <type>xml</type> column against a search value. XML
+ values should therefore typically be accompanied by a separate key
+ field such as an ID. An alternative solution for comparing XML
+ values is to convert them to character strings first, but note
+ that character string comparison has little to do with a useful
+ XML comparison method.
+ </para>
+
+ <para>
+ Since there are no comparison operators for the <type>xml</type>
+ data type, it is not possible to create an index directly on a
+ column of this type. If speedy searches in XML data are desired,
+ possible workarounds would be casting the expression to a
+ character string type and indexing that, or indexing an XPath
+ expression. The actual query would of course have to be adjusted
+ to search by the indexed expression.
+ </para>
+
+ <para>
+ The full-text search module Tsearch2 could also be used to speed
+ up full-document searches in XML data. The necessary
+ preprocessing support is, however, not available in the PostgreSQL
+ distribution in this release.
+ </para>
+ </sect2>
</sect1>
&array;
-<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.379 2007/05/07 07:53:26 petere Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.380 2007/05/21 17:10:28 petere Exp $ -->
<chapter id="functions">
<title>Functions and Operators</title>
type. The function-like expressions <function>xmlparse</function>
and <function>xmlserialize</function> for converting to and from
type <type>xml</type> are not repeated here. Use of many of these
- <type>xml</type> functions requires the installation to have been built
+ functions requires the installation to have been built
with <command>configure --with-libxml</>.
</para>
</sect3>
</sect2>
+ <sect2 id="functions-xml-processing">
+ <title>Processing XML</title>
+
+ <indexterm>
+ <primary>XPath</primary>
+ </indexterm>
+
+ <para>
+ To process values of data type <type>xml</type>, PostgreSQL offers
+ the function <function>xpath</function>, which evaluates XPath 1.0
+ expressions.
+ </para>
+
+<synopsis>
+<function>xpath</function>(<replaceable>xpath</replaceable>, <replaceable>xml</replaceable><optional>, <replaceable>nsarray</replaceable></optional>)
+</synopsis>
+
+ <para>
+ The function <function>xpath</function> evaluates the XPath
+ expression <replaceable>xpath</replaceable> against the XML value
+ <replaceable>xml</replaceable>. It returns an array of XML values
+ corresponding to the node set produced by the XPath expression.
+ </para>
+
+ <para>
+ The third argument of the function is an array of namespace
+ mappings. This array should be a two-dimensional array with the
+ length of the second axis being equal to 2 (i.e., it should be an
+ array of arrays, each of which consists of exactly 2 elements).
+ The first element of each array entry is the namespace name, the
+ second the namespace URI.
+ </para>
+
+ <para>
+ Example:
+<screen><![CDATA[
+SELECT xpath('/my:a/text()', '<my:a xmlns:my="http://example.com">test</my:a>', ARRAY[ARRAY['my', 'http://example.com']]);
+ xpath
+--------
+ {test}
+(1 row)
+]]></screen>
+ </para>
+ </sect2>
+
<sect2 id="functions-xml-mapping">
<title>Mapping Tables to XML</title>
]]></programlisting>
</figure>
</sect2>
-
- <sect2>
- <title>Processing XML</title>
-
- <para>
- <acronym>XML</> support is not just the existence of an
- <type>xml</type> data type, but a variety of features supported by
- a database system. These capabilities include import/export,
- indexing, searching, transforming, and <acronym>XML</> to
- <acronym>SQL</> mapping. <productname>PostgreSQL</> supports some
- but not all of these <acronym>XML</> capabilities. For an
- overview of <acronym>XML</> use in databases, see <ulink
- url="http://www.rpbourret.com/xml/XMLAndDatabases.htm"></>.
- </para>
-
- <variablelist>
- <varlistentry>
- <term>Indexing</term>
- <listitem>
-
- <para>
- <filename>contrib/xml2/</> functions can be used in expression
- indexes to index specific <acronym>XML</> fields. To index the
- full contents of <acronym>XML</> documents, the full-text
- indexing tool <filename>contrib/tsearch2/</> can be used. Of
- course, Tsearch2 indexes have no <acronym>XML</> awareness so
- additional <filename>contrib/xml2/</> checks should be added to
- queries.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>Searching</term>
- <listitem>
-
- <para>
- XPath searches are implemented using <filename>contrib/xml2/</>.
- It processes <acronym>XML</> text documents and returns results
- based on the requested query.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>Transforming</term>
- <listitem>
-
- <para>
- <filename>contrib/xml2/</> supports <acronym>XSLT</> (Extensible
- Stylesheet Language Transformation).
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>XML to SQL Mapping</term>
- <listitem>
-
- <para>
- This involves converting <acronym>XML</> data to and from
- relational structures. <productname>PostgreSQL</> has no
- internal support for such mapping, and relies on external tools
- to do such conversions.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
- </sect2>
</sect1>
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.42 2007/04/06 04:21:43 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.43 2007/05/21 17:10:29 petere Exp $
*
*-------------------------------------------------------------------------
*/
}
#endif
+
/*
* Evaluate XPath expression and return array of XML values.
* As we have no support of XQuery sequences yet, this functions seems
* to be the most useful one (array of XML functions plays a role of
* some kind of substritution for XQuery sequences).
-
+ *
* Workaround here: we parse XML data in different way to allow XPath for
* fragments (see "XPath for fragment" TODO comment inside).
*/
Datum
-xmlpath(PG_FUNCTION_ARGS)
+xpath(PG_FUNCTION_ARGS)
{
#ifdef USE_LIBXML
- ArrayBuildState *astate = NULL;
+ text *xpath_expr_text = PG_GETARG_TEXT_P(0);
+ xmltype *data = PG_GETARG_XML_P(1);
+ ArrayType *namespaces = PG_GETARG_ARRAYTYPE_P(2);
+
+ ArrayBuildState *astate = NULL;
xmlParserCtxtPtr ctxt = NULL;
xmlDocPtr doc = NULL;
xmlXPathContextPtr xpathctx = NULL;
xmlXPathCompExprPtr xpathcomp = NULL;
xmlXPathObjectPtr xpathobj = NULL;
- int32 len, xpath_len;
- xmlChar *string, *xpath_expr;
- bool res_is_null = FALSE;
- int i;
- xmltype *data;
- text *xpath_expr_text;
- ArrayType *namespaces;
- int *dims, ndims, ns_count = 0, bitmask = 1;
- char *ptr;
- bits8 *bitmap;
- char **ns_names = NULL, **ns_uris = NULL;
- int16 typlen;
- bool typbyval;
- char typalign;
-
- /* the function is not strict, we must check first two args */
- if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
- PG_RETURN_NULL();
-
- xpath_expr_text = PG_GETARG_TEXT_P(0);
- data = PG_GETARG_XML_P(1);
-
- /* Namespace mappings passed as text[].
- * Assume that 2-dimensional array has been passed,
- * the 1st subarray is array of names, the 2nd -- array of URIs,
- * example: ARRAY[ARRAY['myns', 'myns2'], ARRAY['http://example.com', 'http://example2.com']].
+ int32 len;
+ int32 xpath_len;
+ xmlChar *string;
+ xmlChar *xpath_expr;
+ int i;
+ int res_nitems;
+ int ndim;
+ int ns_count;
+ char **ns_names;
+ char **ns_uris;
+
+ /*
+ * Namespace mappings are passed as text[]. If an empty array is
+ * passed (ndim = 0, "0-dimentional"), then there are no namespace
+ * mappings. Else, a 2-dimentional array with length of the
+ * second axis being equal to 2 should be passed, i.e., every
+ * subarray contains 2 elements, the first element defining the
+ * name, the second one the URI. Example: ARRAY[ARRAY['myns',
+ * 'http://example.com'], ARRAY['myns2', 'http://example2.com']].
*/
- if (!PG_ARGISNULL(2))
+ ndim = ARR_NDIM(namespaces);
+ if (ndim != 0)
{
- namespaces = PG_GETARG_ARRAYTYPE_P(2);
- ndims = ARR_NDIM(namespaces);
+ bits8 *bitmap;
+ int bitmask;
+ int16 typlen;
+ bool typbyval;
+ char typalign;
+ char *ptr;
+ int *dims;
+
dims = ARR_DIMS(namespaces);
-
- /* Sanity check */
- if (ndims != 2)
- ereport(ERROR, (errmsg("invalid array passed for namespace mappings"),
- errdetail("Only 2-dimensional array may be used for namespace mappings.")));
-
+
+ if (ndim != 2 || dims[1] != 2)
+ ereport(ERROR, (errmsg("invalid array for XML namespace mapping"),
+ errdetail("The array must be two-dimensional with length of the second axis equal to 2."),
+ errcode(ERRCODE_DATA_EXCEPTION)));
+
Assert(ARR_ELEMTYPE(namespaces) == TEXTOID);
-
- ns_count = ArrayGetNItems(ndims, dims) / 2;
+
+ ns_count = ArrayGetNItems(ndim, dims) / 2; /* number of NS mappings */
get_typlenbyvalalign(ARR_ELEMTYPE(namespaces),
&typlen, &typbyval, &typalign);
- ns_names = (char **) palloc(ns_count * sizeof(char *));
- ns_uris = (char **) palloc(ns_count * sizeof(char *));
+ ns_names = palloc(ns_count * sizeof(char *));
+ ns_uris = palloc(ns_count * sizeof(char *));
ptr = ARR_DATA_PTR(namespaces);
bitmap = ARR_NULLBITMAP(namespaces);
bitmask = 1;
-
for (i = 0; i < ns_count * 2; i++)
{
if (bitmap && (*bitmap & bitmask) == 0)
- ereport(ERROR, (errmsg("neither namespace nor URI may be NULL"))); /* TODO: better message */
+ ereport(ERROR, (errmsg("neither namespace name nor URI may be null")));
else
{
- if (i < ns_count)
- ns_names[i] = DatumGetCString(DirectFunctionCall1(textout,
- PointerGetDatum(ptr)));
+ if (i % 2 == 0)
+ ns_names[i / 2] = DatumGetCString(DirectFunctionCall1(textout,
+ PointerGetDatum(ptr)));
else
- ns_uris[i - ns_count] = DatumGetCString(DirectFunctionCall1(textout,
- PointerGetDatum(ptr)));
+ ns_uris[i / 2] = DatumGetCString(DirectFunctionCall1(textout,
+ PointerGetDatum(ptr)));
ptr = att_addlength_pointer(ptr, typlen, ptr);
ptr = (char *) att_align_nominal(ptr, typalign);
}
-
+
/* advance bitmap pointer if any */
if (bitmap)
{
}
}
}
-
+ else
+ {
+ ns_count = 0;
+ ns_names = NULL;
+ ns_uris = NULL;
+ }
+
len = VARSIZE(data) - VARHDRSZ;
xpath_len = VARSIZE(xpath_expr_text) - VARHDRSZ;
if (xpath_len == 0)
- ereport(ERROR, (errmsg("empty XPath expression")));
-
- if (xmlStrncmp((xmlChar *) VARDATA(data), (xmlChar *) "<?xml", 5) == 0)
+ ereport(ERROR, (errmsg("empty XPath expression"),
+ errcode(ERRCODE_DATA_EXCEPTION)));
+
+ /*
+ * To handle both documents and fragments, regardless of the fact
+ * whether the XML datum has a single root (XML well-formedness),
+ * we wrap the XML datum in a dummy element (<x>...</x>) and
+ * extend the XPath expression accordingly. To do it, throw away
+ * the XML prolog, if any.
+ */
+ if ((len > 4) && xmlStrncmp((xmlChar *) VARDATA(data), (xmlChar *) "<?xml", 5) == 0)
{
- string = palloc(len + 1);
- memcpy(string, VARDATA(data), len);
- string[len] = '\0';
- xpath_expr = palloc(xpath_len + 1);
- memcpy(xpath_expr, VARDATA(xpath_expr_text), xpath_len);
- xpath_expr[xpath_len] = '\0';
+ i = 5;
+ while ((i < len) && (('?' != (VARDATA(data))[i - 1]) || ('>' != (VARDATA(data))[i])))
+ i++;
+
+ if (i == len)
+ xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
+ "could not parse XML data");
+
+ ++i;
+ string = xmlStrncatNew((xmlChar *) "<x>", (xmlChar *) VARDATA(data) + i, len - i);
}
else
- {
- /* use "<x>...</x>" as dummy root element to enable XPath for fragments */
- /* TODO: (XPath for fragment) find better solution to work with XML fragment! */
string = xmlStrncatNew((xmlChar *) "<x>", (xmlChar *) VARDATA(data), len);
- string = xmlStrncat(string, (xmlChar *) "</x>", 5);
- len += 7;
- xpath_expr = xmlStrncatNew((xmlChar *) "/x", (xmlChar *) VARDATA(xpath_expr_text), xpath_len);
- len += 2;
- }
-
+
+ string = xmlStrncat(string, (xmlChar *) "</x>", 5);
+ len += 7;
+ xpath_expr = xmlStrncatNew((xmlChar *) "/x", (xmlChar *) VARDATA(xpath_expr_text), xpath_len);
+ xpath_len += 2;
+
xml_init();
PG_TRY();
{
- /* redundant XML parsing (two parsings for the same value in the same session are possible) */
+ /*
+ * redundant XML parsing (two parsings for the same value *
+ * during one command execution are possible)
+ */
ctxt = xmlNewParserCtxt();
if (ctxt == NULL)
xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
xpathctx->node = xmlDocGetRootElement(doc);
if (xpathctx->node == NULL)
xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
- "could not find root XML element");
+ "could not find root XML element");
/* register namespaces, if any */
if ((ns_count > 0) && ns_names && ns_uris)
for (i = 0; i < ns_count; i++)
if (0 != xmlXPathRegisterNs(xpathctx, (xmlChar *) ns_names[i], (xmlChar *) ns_uris[i]))
- ereport(ERROR,
- (errmsg("could not register XML namespace with prefix=\"%s\" and href=\"%s\"", ns_names[i], ns_uris[i])));
-
+ ereport(ERROR,
+ (errmsg("could not register XML namespace with name \"%s\" and URI \"%s\"",
+ ns_names[i], ns_uris[i])));
+
xpathcomp = xmlXPathCompile(xpath_expr);
if (xpathcomp == NULL)
xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
"invalid XPath expression"); /* TODO: show proper XPath error details */
-
+
xpathobj = xmlXPathCompiledEval(xpathcomp, xpathctx);
xmlXPathFreeCompExpr(xpathcomp);
if (xpathobj == NULL)
- ereport(ERROR, (errmsg("could not create XPath object")));
-
+ ereport(ERROR, (errmsg("could not create XPath object"))); /* TODO: reason? */
+
+ /* return empty array in cases when nothing is found */
if (xpathobj->nodesetval == NULL)
- res_is_null = TRUE;
-
- if (!res_is_null && xpathobj->nodesetval->nodeNr == 0)
- /* TODO maybe empty array should be here, not NULL? (if so -- fix segfault) */
- /*PG_RETURN_ARRAYTYPE_P(makeArrayResult(astate, CurrentMemoryContext));*/
- res_is_null = TRUE;
-
- if (!res_is_null)
+ res_nitems = 0;
+ else
+ res_nitems = xpathobj->nodesetval->nodeNr;
+
+ if (res_nitems)
for (i = 0; i < xpathobj->nodesetval->nodeNr; i++)
{
Datum elem;
elemisnull, XMLOID,
CurrentMemoryContext);
}
-
+
xmlXPathFreeObject(xpathobj);
xmlXPathFreeContext(xpathctx);
xmlFreeParserCtxt(ctxt);
PG_RE_THROW();
}
PG_END_TRY();
-
- if (res_is_null)
- {
- PG_RETURN_NULL();
- }
+
+ if (res_nitems == 0)
+ PG_RETURN_ARRAYTYPE_P(construct_empty_array(XMLOID));
else
- {
PG_RETURN_ARRAYTYPE_P(makeArrayResult(astate, CurrentMemoryContext));
- }
#else
NO_XML_SUPPORT();
return 0;
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.406 2007/05/11 17:57:13 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.407 2007/05/21 17:10:29 petere Exp $
*
*-------------------------------------------------------------------------
*/
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200705111
+#define CATALOG_VERSION_NO 200705211
#endif
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.455 2007/05/08 18:56:48 neilc Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.456 2007/05/21 17:10:29 petere Exp $
*
* NOTES
* The script catalog/genbki.sh reads this file and generates .bki
DATA(insert OID = 2938 ( database_to_xml_and_xmlschema PGNSP PGUID 12 100 0 f f t f s 3 142 "16 16 25" _null_ _null_ "{nulls,tableforest,targetns}" database_to_xml_and_xmlschema - _null_ ));
DESCR("map database contents and structure to XML and XML Schema");
-DATA(insert OID = 2931 ( xmlpath PGNSP PGUID 12 1 0 f f f f i 3 143 "25 142 1009" _null_ _null_ _null_ xmlpath - _null_ ));
+DATA(insert OID = 2931 ( xpath PGNSP PGUID 12 1 0 f f t f i 3 143 "25 142 1009" _null_ _null_ _null_ xpath - _null_ ));
DESCR("evaluate XPath expression, with namespaces support");
-DATA(insert OID = 2932 ( xmlpath PGNSP PGUID 14 1 0 f f f f i 2 143 "25 142" _null_ _null_ _null_ "select pg_catalog.xmlpath($1, $2, NULL)" - _null_ ));
+DATA(insert OID = 2932 ( xpath PGNSP PGUID 14 1 0 f f t f i 2 143 "25 142" _null_ _null_ _null_ "select pg_catalog.xpath($1, $2, ''{}''::_text)" - _null_ ));
DESCR("evaluate XPath expression");
/* uuid */
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/utils/xml.h,v 1.18 2007/04/01 09:00:26 petere Exp $
+ * $PostgreSQL: pgsql/src/include/utils/xml.h,v 1.19 2007/05/21 17:10:29 petere Exp $
*
*-------------------------------------------------------------------------
*/
extern Datum texttoxml(PG_FUNCTION_ARGS);
extern Datum xmltotext(PG_FUNCTION_ARGS);
extern Datum xmlvalidate(PG_FUNCTION_ARGS);
-extern Datum xmlpath(PG_FUNCTION_ARGS);
+extern Datum xpath(PG_FUNCTION_ARGS);
extern Datum table_to_xml(PG_FUNCTION_ARGS);
extern Datum query_to_xml(PG_FUNCTION_ARGS);
(9 rows)
-- Text XPath expressions evaluation
-SELECT xmlpath('/value', data) FROM xmltest;
- xmlpath
+SELECT xpath('/value', data) FROM xmltest;
+ xpath
----------------------
{<value>one</value>}
{<value>two</value>}
(2 rows)
-SELECT xmlpath(NULL, NULL) IS NULL FROM xmltest;
+SELECT xpath(NULL, NULL) IS NULL FROM xmltest;
?column?
----------
t
t
(2 rows)
-SELECT xmlpath('', '<!-- error -->');
+SELECT xpath('', '<!-- error -->');
ERROR: empty XPath expression
-CONTEXT: SQL function "xmlpath" statement 1
-SELECT xmlpath('//text()', '<local:data xmlns:local="http://127.0.0.1"><local:piece id="1">number one</local:piece><local:piece id="2" /></local:data>');
- xmlpath
+CONTEXT: SQL function "xpath" statement 1
+SELECT xpath('//text()', '<local:data xmlns:local="http://127.0.0.1"><local:piece id="1">number one</local:piece><local:piece id="2" /></local:data>');
+ xpath
----------------
{"number one"}
(1 row)
-SELECT xmlpath('//loc:piece/@id', '<local:data xmlns:local="http://127.0.0.1"><local:piece id="1">number one</local:piece><local:piece id="2" /></local:data>', ARRAY[ARRAY['loc'], ARRAY['http://127.0.0.1']]);
- xmlpath
----------
+SELECT xpath('//loc:piece/@id', '<local:data xmlns:local="http://127.0.0.1"><local:piece id="1">number one</local:piece><local:piece id="2" /></local:data>', ARRAY[ARRAY['loc', 'http://127.0.0.1']]);
+ xpath
+-------
{1,2}
(1 row)
-SELECT xmlpath('//b', '<a>one <b>two</b> three <b>etc</b></a>');
- xmlpath
+SELECT xpath('//b', '<a>one <b>two</b> three <b>etc</b></a>');
+ xpath
-------------------------
{<b>two</b>,<b>etc</b>}
(1 row)
(2 rows)
-- Text XPath expressions evaluation
-SELECT xmlpath('/value', data) FROM xmltest;
- xmlpath
----------
+SELECT xpath('/value', data) FROM xmltest;
+ xpath
+-------
(0 rows)
-SELECT xmlpath(NULL, NULL) IS NULL FROM xmltest;
-ERROR: unsupported XML feature
-DETAIL: This functionality requires libxml support.
-HINT: You need to re-compile PostgreSQL using --with-libxml.
-CONTEXT: SQL function "xmlpath" statement 1
-SELECT xmlpath('', '<!-- error -->');
+SELECT xpath(NULL, NULL) IS NULL FROM xmltest;
+ ?column?
+----------
+(0 rows)
+
+SELECT xpath('', '<!-- error -->');
ERROR: unsupported XML feature
DETAIL: This functionality requires libxml support.
HINT: You need to re-compile PostgreSQL using --with-libxml.
-SELECT xmlpath('//text()', '<local:data xmlns:local="http://127.0.0.1"><local:piece id="1">number one</local:piece><local:piece id="2" /></local:data>');
+SELECT xpath('//text()', '<local:data xmlns:local="http://127.0.0.1"><local:piece id="1">number one</local:piece><local:piece id="2" /></local:data>');
ERROR: unsupported XML feature
DETAIL: This functionality requires libxml support.
HINT: You need to re-compile PostgreSQL using --with-libxml.
-SELECT xmlpath('//loc:piece/@id', '<local:data xmlns:local="http://127.0.0.1"><local:piece id="1">number one</local:piece><local:piece id="2" /></local:data>', ARRAY[ARRAY['loc'], ARRAY['http://127.0.0.1']]);
+SELECT xpath('//loc:piece/@id', '<local:data xmlns:local="http://127.0.0.1"><local:piece id="1">number one</local:piece><local:piece id="2" /></local:data>', ARRAY[ARRAY['loc', 'http://127.0.0.1']]);
ERROR: unsupported XML feature
DETAIL: This functionality requires libxml support.
HINT: You need to re-compile PostgreSQL using --with-libxml.
-SELECT xmlpath('//b', '<a>one <b>two</b> three <b>etc</b></a>');
+SELECT xpath('//b', '<a>one <b>two</b> three <b>etc</b></a>');
ERROR: unsupported XML feature
DETAIL: This functionality requires libxml support.
HINT: You need to re-compile PostgreSQL using --with-libxml.
-- Text XPath expressions evaluation
-SELECT xmlpath('/value', data) FROM xmltest;
-SELECT xmlpath(NULL, NULL) IS NULL FROM xmltest;
-SELECT xmlpath('', '<!-- error -->');
-SELECT xmlpath('//text()', '<local:data xmlns:local="http://127.0.0.1"><local:piece id="1">number one</local:piece><local:piece id="2" /></local:data>');
-SELECT xmlpath('//loc:piece/@id', '<local:data xmlns:local="http://127.0.0.1"><local:piece id="1">number one</local:piece><local:piece id="2" /></local:data>', ARRAY[ARRAY['loc'], ARRAY['http://127.0.0.1']]);
-SELECT xmlpath('//b', '<a>one <b>two</b> three <b>etc</b></a>');
+SELECT xpath('/value', data) FROM xmltest;
+SELECT xpath(NULL, NULL) IS NULL FROM xmltest;
+SELECT xpath('', '<!-- error -->');
+SELECT xpath('//text()', '<local:data xmlns:local="http://127.0.0.1"><local:piece id="1">number one</local:piece><local:piece id="2" /></local:data>');
+SELECT xpath('//loc:piece/@id', '<local:data xmlns:local="http://127.0.0.1"><local:piece id="1">number one</local:piece><local:piece id="2" /></local:data>', ARRAY[ARRAY['loc', 'http://127.0.0.1']]);
+SELECT xpath('//b', '<a>one <b>two</b> three <b>etc</b></a>');