mirror of
https://github.com/postgres/postgres.git
synced 2025-07-30 11:03:19 +03:00
Add an xpath_exists() function. This is equivalent to XMLEXISTS except that
it offers support for namespace mapping. Mike Fowler, reviewed by David Fetter
This commit is contained in:
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.99 2010/08/05 04:21:54 petere Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.100 2010/08/08 19:15:27 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -3541,3 +3541,27 @@ Datum xmlexists(PG_FUNCTION_ARGS)
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Determines if the node specified by the supplied XPath exists
|
||||
* in a given XML document, returning a boolean. Differs from
|
||||
* xmlexists as it supports namespaces and is not defined in SQL/XML.
|
||||
*/
|
||||
Datum
|
||||
xpath_exists(PG_FUNCTION_ARGS)
|
||||
{
|
||||
#ifdef USE_LIBXML
|
||||
text *xpath_expr_text = PG_GETARG_TEXT_P(0);
|
||||
xmltype *data = PG_GETARG_XML_P(1);
|
||||
ArrayType *namespaces = PG_GETARG_ARRAYTYPE_P(2);
|
||||
int res_nitems;
|
||||
|
||||
xpath_internal(xpath_expr_text, data, namespaces,
|
||||
&res_nitems, NULL);
|
||||
|
||||
PG_RETURN_BOOL(res_nitems > 0);
|
||||
#else
|
||||
NO_XML_SUPPORT();
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
@ -37,7 +37,7 @@
|
||||
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.592 2010/08/08 16:27:04 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.593 2010/08/08 19:15:27 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -53,6 +53,6 @@
|
||||
*/
|
||||
|
||||
/* yyyymmddN */
|
||||
#define CATALOG_VERSION_NO 201008071
|
||||
#define CATALOG_VERSION_NO 201008081
|
||||
|
||||
#endif
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.576 2010/08/08 16:27:04 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.577 2010/08/08 19:15:27 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* The script catalog/genbki.pl reads this file and generates .bki
|
||||
@ -4415,6 +4415,11 @@ DESCR("evaluate XPath expression");
|
||||
DATA(insert OID = 2614 ( xmlexists PGNSP PGUID 12 1 0 0 f f f t f i 2 0 16 "25 142" _null_ _null_ _null_ _null_ xmlexists _null_ _null_ _null_ ));
|
||||
DESCR("test XML value against XPath expression");
|
||||
|
||||
DATA(insert OID = 3049 ( xpath_exists PGNSP PGUID 12 1 0 0 f f f t f i 3 0 16 "25 142 1009" _null_ _null_ _null_ _null_ xpath_exists _null_ _null_ _null_ ));
|
||||
DESCR("test XML value against XPath expression, with namespace support");
|
||||
DATA(insert OID = 3050 ( xpath_exists PGNSP PGUID 14 1 0 0 f f f t f i 2 0 16 "25 142" _null_ _null_ _null_ _null_ "select pg_catalog.xpath_exists($1, $2, ''{}''::pg_catalog.text[])" _null_ _null_ _null_ ));
|
||||
DESCR("test XML value against XPath expression");
|
||||
|
||||
/* uuid */
|
||||
DATA(insert OID = 2952 ( uuid_in PGNSP PGUID 12 1 0 0 f f f t f i 1 0 2950 "2275" _null_ _null_ _null_ _null_ uuid_in _null_ _null_ _null_ ));
|
||||
DESCR("I/O");
|
||||
|
@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/utils/xml.h,v 1.32 2010/08/05 04:21:54 petere Exp $
|
||||
* $PostgreSQL: pgsql/src/include/utils/xml.h,v 1.33 2010/08/08 19:15:27 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -37,6 +37,7 @@ extern Datum texttoxml(PG_FUNCTION_ARGS);
|
||||
extern Datum xmltotext(PG_FUNCTION_ARGS);
|
||||
extern Datum xmlvalidate(PG_FUNCTION_ARGS);
|
||||
extern Datum xpath(PG_FUNCTION_ARGS);
|
||||
extern Datum xpath_exists(PG_FUNCTION_ARGS);
|
||||
extern Datum xmlexists(PG_FUNCTION_ARGS);
|
||||
|
||||
extern Datum table_to_xml(PG_FUNCTION_ARGS);
|
||||
|
@ -502,7 +502,7 @@ SELECT xpath('//b', '<a>one <b>two</b> three <b>etc</b></a>');
|
||||
{<b>two</b>,<b>etc</b>}
|
||||
(1 row)
|
||||
|
||||
-- Test xmlexists evaluation
|
||||
-- Test xmlexists and xpath_exists
|
||||
SELECT xmlexists('//town[text() = ''Toronto'']' PASSING BY REF '<towns><town>Bidford-on-Avon</town><town>Cwmbran</town><town>Bristol</town></towns>');
|
||||
xmlexists
|
||||
-----------
|
||||
@ -515,6 +515,18 @@ SELECT xmlexists('//town[text() = ''Cwmbran'']' PASSING BY REF '<towns><town>Bid
|
||||
t
|
||||
(1 row)
|
||||
|
||||
SELECT xpath_exists('//town[text() = ''Toronto'']','<towns><town>Bidford-on-Avon</town><town>Cwmbran</town><town>Bristol</town></towns>'::xml);
|
||||
xpath_exists
|
||||
--------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
SELECT xpath_exists('//town[text() = ''Cwmbran'']','<towns><town>Bidford-on-Avon</town><town>Cwmbran</town><town>Bristol</town></towns>'::xml);
|
||||
xpath_exists
|
||||
--------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
INSERT INTO xmltest VALUES (4, '<menu><beers><name>Budvar</name><cost>free</cost><name>Carling</name><cost>lots</cost></beers></menu>'::xml);
|
||||
INSERT INTO xmltest VALUES (5, '<menu><beers><name>Molson</name><cost>free</cost><name>Carling</name><cost>lots</cost></beers></menu>'::xml);
|
||||
INSERT INTO xmltest VALUES (6, '<myns:menu xmlns:myns="http://myns.com"><myns:beers><myns:name>Budvar</myns:name><myns:cost>free</myns:cost><myns:name>Carling</myns:name><myns:cost>lots</myns:cost></myns:beers></myns:menu>'::xml);
|
||||
@ -543,6 +555,42 @@ SELECT COUNT(id) FROM xmltest WHERE xmlexists('/menu/beers/name[text() = ''Molso
|
||||
1
|
||||
(1 row)
|
||||
|
||||
SELECT COUNT(id) FROM xmltest WHERE xpath_exists('/menu/beer',data);
|
||||
count
|
||||
-------
|
||||
0
|
||||
(1 row)
|
||||
|
||||
SELECT COUNT(id) FROM xmltest WHERE xpath_exists('/menu/beers',data);
|
||||
count
|
||||
-------
|
||||
2
|
||||
(1 row)
|
||||
|
||||
SELECT COUNT(id) FROM xmltest WHERE xpath_exists('/menu/beers/name[text() = ''Molson'']',data);
|
||||
count
|
||||
-------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
SELECT COUNT(id) FROM xmltest WHERE xpath_exists('/myns:menu/myns:beer',data,ARRAY[ARRAY['myns','http://myns.com']]);
|
||||
count
|
||||
-------
|
||||
0
|
||||
(1 row)
|
||||
|
||||
SELECT COUNT(id) FROM xmltest WHERE xpath_exists('/myns:menu/myns:beers',data,ARRAY[ARRAY['myns','http://myns.com']]);
|
||||
count
|
||||
-------
|
||||
2
|
||||
(1 row)
|
||||
|
||||
SELECT COUNT(id) FROM xmltest WHERE xpath_exists('/myns:menu/myns:beers/myns:name[text() = ''Molson'']',data,ARRAY[ARRAY['myns','http://myns.com']]);
|
||||
count
|
||||
-------
|
||||
1
|
||||
(1 row)
|
||||
|
||||
CREATE TABLE query ( expr TEXT );
|
||||
INSERT INTO query VALUES ('/menu/beers/cost[text() = ''lots'']');
|
||||
SELECT COUNT(id) FROM xmltest, query WHERE xmlexists(expr PASSING BY REF data);
|
||||
|
@ -456,7 +456,7 @@ LINE 1: SELECT xpath('//b', '<a>one <b>two</b> three <b>etc</b></a>'...
|
||||
^
|
||||
DETAIL: This functionality requires the server to be built with libxml support.
|
||||
HINT: You need to rebuild PostgreSQL using --with-libxml.
|
||||
-- Test xmlexists evaluation
|
||||
-- Test xmlexists and xpath_exists
|
||||
SELECT xmlexists('//town[text() = ''Toronto'']' PASSING BY REF '<towns><town>Bidford-on-Avon</town><town>Cwmbran</town><town>Bristol</town></towns>');
|
||||
ERROR: unsupported XML feature
|
||||
LINE 1: ...sts('//town[text() = ''Toronto'']' PASSING BY REF '<towns><t...
|
||||
@ -469,6 +469,18 @@ LINE 1: ...sts('//town[text() = ''Cwmbran'']' PASSING BY REF '<towns><t...
|
||||
^
|
||||
DETAIL: This functionality requires the server to be built with libxml support.
|
||||
HINT: You need to rebuild PostgreSQL using --with-libxml.
|
||||
SELECT xpath_exists('//town[text() = ''Toronto'']','<towns><town>Bidford-on-Avon</town><town>Cwmbran</town><town>Bristol</town></towns>'::xml);
|
||||
ERROR: unsupported XML feature
|
||||
LINE 1: ...ELECT xpath_exists('//town[text() = ''Toronto'']','<towns><t...
|
||||
^
|
||||
DETAIL: This functionality requires the server to be built with libxml support.
|
||||
HINT: You need to rebuild PostgreSQL using --with-libxml.
|
||||
SELECT xpath_exists('//town[text() = ''Cwmbran'']','<towns><town>Bidford-on-Avon</town><town>Cwmbran</town><town>Bristol</town></towns>'::xml);
|
||||
ERROR: unsupported XML feature
|
||||
LINE 1: ...ELECT xpath_exists('//town[text() = ''Cwmbran'']','<towns><t...
|
||||
^
|
||||
DETAIL: This functionality requires the server to be built with libxml support.
|
||||
HINT: You need to rebuild PostgreSQL using --with-libxml.
|
||||
INSERT INTO xmltest VALUES (4, '<menu><beers><name>Budvar</name><cost>free</cost><name>Carling</name><cost>lots</cost></beers></menu>'::xml);
|
||||
ERROR: unsupported XML feature
|
||||
LINE 1: INSERT INTO xmltest VALUES (4, '<menu><beers><name>Budvar</n...
|
||||
@ -517,6 +529,42 @@ SELECT COUNT(id) FROM xmltest WHERE xmlexists('/menu/beers/name[text() = ''Molso
|
||||
0
|
||||
(1 row)
|
||||
|
||||
SELECT COUNT(id) FROM xmltest WHERE xpath_exists('/menu/beer',data);
|
||||
count
|
||||
-------
|
||||
0
|
||||
(1 row)
|
||||
|
||||
SELECT COUNT(id) FROM xmltest WHERE xpath_exists('/menu/beers',data);
|
||||
count
|
||||
-------
|
||||
0
|
||||
(1 row)
|
||||
|
||||
SELECT COUNT(id) FROM xmltest WHERE xpath_exists('/menu/beers/name[text() = ''Molson'']',data);
|
||||
count
|
||||
-------
|
||||
0
|
||||
(1 row)
|
||||
|
||||
SELECT COUNT(id) FROM xmltest WHERE xpath_exists('/myns:menu/myns:beer',data,ARRAY[ARRAY['myns','http://myns.com']]);
|
||||
count
|
||||
-------
|
||||
0
|
||||
(1 row)
|
||||
|
||||
SELECT COUNT(id) FROM xmltest WHERE xpath_exists('/myns:menu/myns:beers',data,ARRAY[ARRAY['myns','http://myns.com']]);
|
||||
count
|
||||
-------
|
||||
0
|
||||
(1 row)
|
||||
|
||||
SELECT COUNT(id) FROM xmltest WHERE xpath_exists('/myns:menu/myns:beers/myns:name[text() = ''Molson'']',data,ARRAY[ARRAY['myns','http://myns.com']]);
|
||||
count
|
||||
-------
|
||||
0
|
||||
(1 row)
|
||||
|
||||
CREATE TABLE query ( expr TEXT );
|
||||
INSERT INTO query VALUES ('/menu/beers/cost[text() = ''lots'']');
|
||||
SELECT COUNT(id) FROM xmltest, query WHERE xmlexists(expr PASSING BY REF data);
|
||||
|
@ -164,21 +164,29 @@ SELECT xpath('//text()', '<local:data xmlns:local="http://127.0.0.1"><local:piec
|
||||
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>');
|
||||
|
||||
-- Test xmlexists evaluation
|
||||
-- Test xmlexists and xpath_exists
|
||||
SELECT xmlexists('//town[text() = ''Toronto'']' PASSING BY REF '<towns><town>Bidford-on-Avon</town><town>Cwmbran</town><town>Bristol</town></towns>');
|
||||
SELECT xmlexists('//town[text() = ''Cwmbran'']' PASSING BY REF '<towns><town>Bidford-on-Avon</town><town>Cwmbran</town><town>Bristol</town></towns>');
|
||||
SELECT xpath_exists('//town[text() = ''Toronto'']','<towns><town>Bidford-on-Avon</town><town>Cwmbran</town><town>Bristol</town></towns>'::xml);
|
||||
SELECT xpath_exists('//town[text() = ''Cwmbran'']','<towns><town>Bidford-on-Avon</town><town>Cwmbran</town><town>Bristol</town></towns>'::xml);
|
||||
|
||||
INSERT INTO xmltest VALUES (4, '<menu><beers><name>Budvar</name><cost>free</cost><name>Carling</name><cost>lots</cost></beers></menu>'::xml);
|
||||
INSERT INTO xmltest VALUES (5, '<menu><beers><name>Molson</name><cost>free</cost><name>Carling</name><cost>lots</cost></beers></menu>'::xml);
|
||||
INSERT INTO xmltest VALUES (6, '<myns:menu xmlns:myns="http://myns.com"><myns:beers><myns:name>Budvar</myns:name><myns:cost>free</myns:cost><myns:name>Carling</myns:name><myns:cost>lots</myns:cost></myns:beers></myns:menu>'::xml);
|
||||
INSERT INTO xmltest VALUES (7, '<myns:menu xmlns:myns="http://myns.com"><myns:beers><myns:name>Molson</myns:name><myns:cost>free</myns:cost><myns:name>Carling</myns:name><myns:cost>lots</myns:cost></myns:beers></myns:menu>'::xml);
|
||||
|
||||
|
||||
SELECT COUNT(id) FROM xmltest WHERE xmlexists('/menu/beer' PASSING data);
|
||||
SELECT COUNT(id) FROM xmltest WHERE xmlexists('/menu/beer' PASSING BY REF data BY REF);
|
||||
SELECT COUNT(id) FROM xmltest WHERE xmlexists('/menu/beers' PASSING BY REF data);
|
||||
SELECT COUNT(id) FROM xmltest WHERE xmlexists('/menu/beers/name[text() = ''Molson'']' PASSING BY REF data);
|
||||
|
||||
SELECT COUNT(id) FROM xmltest WHERE xpath_exists('/menu/beer',data);
|
||||
SELECT COUNT(id) FROM xmltest WHERE xpath_exists('/menu/beers',data);
|
||||
SELECT COUNT(id) FROM xmltest WHERE xpath_exists('/menu/beers/name[text() = ''Molson'']',data);
|
||||
SELECT COUNT(id) FROM xmltest WHERE xpath_exists('/myns:menu/myns:beer',data,ARRAY[ARRAY['myns','http://myns.com']]);
|
||||
SELECT COUNT(id) FROM xmltest WHERE xpath_exists('/myns:menu/myns:beers',data,ARRAY[ARRAY['myns','http://myns.com']]);
|
||||
SELECT COUNT(id) FROM xmltest WHERE xpath_exists('/myns:menu/myns:beers/myns:name[text() = ''Molson'']',data,ARRAY[ARRAY['myns','http://myns.com']]);
|
||||
|
||||
CREATE TABLE query ( expr TEXT );
|
||||
INSERT INTO query VALUES ('/menu/beers/cost[text() = ''lots'']');
|
||||
SELECT COUNT(id) FROM xmltest, query WHERE xmlexists(expr PASSING BY REF data);
|
||||
|
Reference in New Issue
Block a user