diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml index e1fb7d42493469ee325ad205b3a2822f718b9e29..6b72e80e569905de6a8d455989334695c55bc9b3 100644 --- a/doc/src/sgml/datatype.sgml +++ b/doc/src/sgml/datatype.sgml @@ -1,4 +1,4 @@ -<!-- $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> @@ -3213,7 +3213,7 @@ SELECT * FROM test; <sect1 id="datatype-uuid"> <title><acronym>UUID</acronym> Type</title> - <indexterm zone="datatype-xml"> + <indexterm zone="datatype-uuid"> <primary>UUID</primary> </indexterm> @@ -3289,6 +3289,8 @@ a0eebc999c0b4ef8bb6d6bb9bd380a11 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 @@ -3299,7 +3301,7 @@ XMLPARSE ( { DOCUMENT | CONTENT } <replaceable>value</replaceable>) 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 @@ -3351,7 +3353,10 @@ SET xmloption TO { DOCUMENT | CONTENT }; 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. @@ -3398,6 +3403,41 @@ SET xmloption TO { DOCUMENT | CONTENT }; 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; diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 6c901f9cca6864236ee61c9d4a5d21f62861ec1b..9dd25928eb4737fc65cbb21667019c6fd2c64bdc 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -1,4 +1,4 @@ -<!-- $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> @@ -7512,7 +7512,7 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple 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> @@ -7848,6 +7848,51 @@ SELECT xmlroot(xmlparse(document '<?xml version="1.1"?><content>abc</content>'), </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> @@ -8097,75 +8142,6 @@ table2-mapping ]]></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> diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c index e873264e3a1fa896b539820cb6f3f459585dd040..f9fd48db66144128c4a862ab2a871260c51b05aa 100644 --- a/src/backend/utils/adt/xml.c +++ b/src/backend/utils/adt/xml.c @@ -7,7 +7,7 @@ * 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 $ * *------------------------------------------------------------------------- */ @@ -2991,90 +2991,94 @@ xml_xmlnodetoxmltype(xmlNodePtr cur) } #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) { @@ -3087,37 +3091,55 @@ xmlpath(PG_FUNCTION_ARGS) } } } - + 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, @@ -3133,34 +3155,33 @@ xmlpath(PG_FUNCTION_ARGS) 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; @@ -3170,7 +3191,7 @@ xmlpath(PG_FUNCTION_ARGS) elemisnull, XMLOID, CurrentMemoryContext); } - + xmlXPathFreeObject(xpathobj); xmlXPathFreeContext(xpathctx); xmlFreeParserCtxt(ctxt); @@ -3194,15 +3215,11 @@ xmlpath(PG_FUNCTION_ARGS) 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; diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index b0d562f842480b380eda92b005bef69105cf40ca..9ae142387cab1b6a070167cbb98b05805bd556d2 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -37,7 +37,7 @@ * 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 $ * *------------------------------------------------------------------------- */ @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 200705111 +#define CATALOG_VERSION_NO 200705211 #endif diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h index b300f9b92c488d4a76f434743c463126a09d850e..7d297e8a83eacff66b69fc2890e27de03712f5a3 100644 --- a/src/include/catalog/pg_proc.h +++ b/src/include/catalog/pg_proc.h @@ -7,7 +7,7 @@ * 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 @@ -4116,9 +4116,9 @@ DESCR("map database structure to XML Schema"); 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 */ diff --git a/src/include/utils/xml.h b/src/include/utils/xml.h index 15ba500d5078654eb8b66a984ceca67e1083138b..8e750f764f8551ee2fa558ccc080e663ec88fba3 100644 --- a/src/include/utils/xml.h +++ b/src/include/utils/xml.h @@ -7,7 +7,7 @@ * 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 $ * *------------------------------------------------------------------------- */ @@ -36,7 +36,7 @@ extern Datum xmlconcat2(PG_FUNCTION_ARGS); 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); diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out index 20520d97606a2ac789d56d48063a2f81366d056a..cec9ea294420bb1506aedd4e287096246dd47959 100644 --- a/src/test/regress/expected/xml.out +++ b/src/test/regress/expected/xml.out @@ -402,37 +402,37 @@ SELECT table_name, view_definition FROM information_schema.views (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) diff --git a/src/test/regress/expected/xml_1.out b/src/test/regress/expected/xml_1.out index e922107f8d3fd8b9f7f0847d196908d62216e8e9..2bf910577057dc26ff3aaf4556ffeec5694ede9f 100644 --- a/src/test/regress/expected/xml_1.out +++ b/src/test/regress/expected/xml_1.out @@ -326,29 +326,29 @@ SELECT table_name, view_definition FROM information_schema.views (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. diff --git a/src/test/regress/sql/xml.sql b/src/test/regress/sql/xml.sql index 1658a3803650f772bc01c2109c478fe1f66a5592..2c9db299fda33d1df0917e6b199f2fc008b13524 100644 --- a/src/test/regress/sql/xml.sql +++ b/src/test/regress/sql/xml.sql @@ -147,9 +147,9 @@ SELECT table_name, view_definition FROM information_schema.views -- 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>');