Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit4dfc457

Browse files
committed
Add an xpath_exists() function. This is equivalent to XMLEXISTS except that
it offers support for namespace mapping.Mike Fowler, reviewed by David Fetter
1 parent46aa77c commit4dfc457

File tree

8 files changed

+205
-39
lines changed

8 files changed

+205
-39
lines changed

‎doc/src/sgml/func.sgml

Lines changed: 62 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.524 2010/08/05 18:21:17 tgl Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.525 2010/08/08 19:15:27 tgl Exp $ -->
22

33
<chapter id="functions">
44
<title>Functions and Operators</title>
@@ -8175,7 +8175,7 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
81758175
linkend="datatype-xml"> for information about the <type>xml</type>
81768176
type. The function-like expressions <function>xmlparse</function>
81778177
and <function>xmlserialize</function> for converting to and from
8178-
type <type>xml</type> are not repeated here. Use ofmany of these
8178+
type <type>xml</type> are not repeated here. Use ofmost of these
81798179
functions requires the installation to have been built
81808180
with <command>configure --with-libxml</>.
81818181
</para>
@@ -8231,7 +8231,7 @@ SELECT xmlcomment('hello');
82318231
<synopsis>
82328232
<function>xmlconcat</function>(<replaceable>xml</replaceable><optional>, ...</optional>)
82338233
</synopsis>
8234-
8234+
82358235
<para>
82368236
The function <function>xmlconcat</function> concatenates a list
82378237
of individual XML values to create a single value containing an
@@ -8277,18 +8277,18 @@ SELECT xmlconcat('<?xml version="1.1"?><foo/>', '<?xml version="1.1" standalone=
82778277
]]></screen>
82788278
</para>
82798279
</sect3>
8280-
8280+
82818281
<sect3>
82828282
<title><literal>xmlelement</literal></title>
8283-
8283+
82848284
<indexterm>
82858285
<primary>xmlelement</primary>
82868286
</indexterm>
8287-
8287+
82888288
<synopsis>
82898289
<function>xmlelement</function>(name <replaceable>name</replaceable> <optional>, xmlattributes(<replaceable>value</replaceable> <optional>AS <replaceable>attname</replaceable></optional> <optional>, ... </optional>)</optional> <optional><replaceable>, content, ...</replaceable></optional>)
82908290
</synopsis>
8291-
8291+
82928292
<para>
82938293
The <function>xmlelement</function> expression produces an XML
82948294
element with the given name, attributes, and content.
@@ -8375,18 +8375,18 @@ SELECT xmlelement(name foo, xmlattributes('xyz' as bar),
83758375
at which point a more precise description will appear.
83768376
</para>
83778377
</sect3>
8378-
8378+
83798379
<sect3>
83808380
<title><literal>xmlforest</literal></title>
8381-
8381+
83828382
<indexterm>
83838383
<primary>xmlforest</primary>
83848384
</indexterm>
8385-
8385+
83868386
<synopsis>
83878387
<function>xmlforest</function>(<replaceable>content</replaceable> <optional>AS <replaceable>name</replaceable></optional> <optional>, ...</optional>)
83888388
</synopsis>
8389-
8389+
83908390
<para>
83918391
The <function>xmlforest</function> expression produces an XML
83928392
forest (sequence) of elements using the given names and content.
@@ -8432,18 +8432,18 @@ WHERE table_schema = 'pg_catalog';
84328432
<function>xmlelement</function>.
84338433
</para>
84348434
</sect3>
8435-
8435+
84368436
<sect3>
84378437
<title><literal>xmlpi</literal></title>
8438-
8438+
84398439
<indexterm>
84408440
<primary>xmlpi</primary>
84418441
</indexterm>
8442-
8442+
84438443
<synopsis>
84448444
<function>xmlpi</function>(name <replaceable>target</replaceable> <optional>, <replaceable>content</replaceable></optional>)
84458445
</synopsis>
8446-
8446+
84478447
<para>
84488448
The <function>xmlpi</function> expression creates an XML
84498449
processing instruction. The content, if present, must not
@@ -8461,18 +8461,18 @@ SELECT xmlpi(name php, 'echo "hello world";');
84618461
]]></screen>
84628462
</para>
84638463
</sect3>
8464-
8464+
84658465
<sect3>
84668466
<title><literal>xmlroot</literal></title>
8467-
8467+
84688468
<indexterm>
84698469
<primary>xmlroot</primary>
84708470
</indexterm>
8471-
8471+
84728472
<synopsis>
84738473
<function>xmlroot</function>(<replaceable>xml</replaceable>, version <replaceable>text</replaceable> | no value <optional>, standalone yes|no|no value</optional>)
84748474
</synopsis>
8475-
8475+
84768476
<para>
84778477
The <function>xmlroot</function> expression alters the properties
84788478
of the root node of an XML value. If a version is specified,
@@ -8483,7 +8483,7 @@ SELECT xmlpi(name php, 'echo "hello world";');
84838483

84848484
<para>
84858485
<screen><![CDATA[
8486-
SELECT xmlroot(xmlparse(document '<?xml version="1.1"?><content>abc</content>'),
8486+
SELECT xmlroot(xmlparse(document '<?xml version="1.1"?><content>abc</content>'),
84878487
version '1.0', standalone yes);
84888488

84898489
xmlroot
@@ -8636,17 +8636,19 @@ SELECT xmlexists('//town[text() = ''Toronto'']' PASSING BY REF '<towns><town>Tor
86368636

86378637
<para>
86388638
To process values of data type <type>xml</type>, PostgreSQL offers
8639-
the function <function>xpath</function>, which evaluates XPath 1.0
8639+
the functions <function>xpath</function> and
8640+
<function>xpath_exists</function>, which evaluate XPath 1.0
86408641
expressions.
86418642
</para>
86428643

86438644
<synopsis>
8644-
<function>xpath</function>(<replaceable>xpath</replaceable>, <replaceable>xml</replaceable><optional>, <replaceable>nsarray</replaceable></optional>)
8645+
<function>xpath</function>(<replaceable>xpath</replaceable>, <replaceable>xml</replaceable><optional>, <replaceable>nsarray</replaceable></optional>)
86458646
</synopsis>
86468647

86478648
<para>
86488649
The function <function>xpath</function> evaluates the XPath
8649-
expression <replaceable>xpath</replaceable> against the XML value
8650+
expression <replaceable>xpath</replaceable> (a <type>text</> value)
8651+
against the XML value
86508652
<replaceable>xml</replaceable>. It returns an array of XML values
86518653
corresponding to the node set produced by the XPath expression.
86528654
</para>
@@ -8657,21 +8659,21 @@ SELECT xmlexists('//town[text() = ''Toronto'']' PASSING BY REF '<towns><town>Tor
86578659
</para>
86588660

86598661
<para>
8660-
The third argument of the function is an array of namespace
8661-
mappings. This array should be a two-dimensional array with the
8662-
length of the second axis being equal to 2 (i.e., it should be an
8662+
Theoptionalthird argument of the function is an array of namespace
8663+
mappings. This array should be a two-dimensional<type>text</>array with
8664+
thelength of the second axis being equal to 2 (i.e., it should be an
86638665
array of arrays, each of which consists of exactly 2 elements).
86648666
The first element of each array entry is the namespace name (alias), the
86658667
second the namespace URI. It is not required that aliases provided in
8666-
this arrayare the samethat those being used in the XML document itself (in
8668+
this arraybe the sameas those being used in the XML document itself (in
86678669
other words, both in the XML document and in the <function>xpath</function>
86688670
function context, aliases are <emphasis>local</>).
86698671
</para>
86708672

86718673
<para>
86728674
Example:
86738675
<screen><![CDATA[
8674-
SELECT xpath('/my:a/text()', '<my:a xmlns:my="http://example.com">test</my:a>',
8676+
SELECT xpath('/my:a/text()', '<my:a xmlns:my="http://example.com">test</my:a>',
86758677
ARRAY[ARRAY['my', 'http://example.com']]);
86768678

86778679
xpath
@@ -8682,7 +8684,7 @@ SELECT xpath('/my:a/text()', '<my:a xmlns:my="http://example.com">test</my:a>',
86828684
</para>
86838685

86848686
<para>
8685-
How todeal with default (anonymous) namespaces:
8687+
Todeal with default (anonymous) namespaces, do something like this:
86868688
<screen><![CDATA[
86878689
SELECT xpath('//mydefns:b/text()', '<a xmlns="http://example.com"><b>test</b></a>',
86888690
ARRAY[ARRAY['mydefns', 'http://example.com']]);
@@ -8691,14 +8693,44 @@ SELECT xpath('//mydefns:b/text()', '<a xmlns="http://example.com"><b>test</b></a
86918693
--------
86928694
{test}
86938695
(1 row)
8696+
]]></screen>
8697+
</para>
8698+
8699+
<indexterm>
8700+
<primary>xpath_exists</primary>
8701+
</indexterm>
8702+
8703+
<synopsis>
8704+
<function>xpath_exists</function>(<replaceable>xpath</replaceable>, <replaceable>xml</replaceable> <optional>, <replaceable>nsarray</replaceable></optional>)
8705+
</synopsis>
8706+
8707+
<para>
8708+
The function <function>xpath_exists</function> is a specialized form
8709+
of the <function>xpath</function> function. Instead of returning the
8710+
individual XML values that satisfy the XPath, this function returns a
8711+
boolean indicating whether the query was satisfied or not. This
8712+
function is equivalent to the standard <literal>XMLEXISTS</> predicate,
8713+
except that it also offers support for a namespace mapping argument.
8714+
</para>
8715+
8716+
<para>
8717+
Example:
8718+
<screen><![CDATA[
8719+
SELECT xpath_exists('/my:a/text()', '<my:a xmlns:my="http://example.com">test</my:a>',
8720+
ARRAY[ARRAY['my', 'http://example.com']]);
8721+
8722+
xpath_exists
8723+
--------------
8724+
t
8725+
(1 row)
86948726
]]></screen>
86958727
</para>
86968728
</sect2>
86978729

86988730
<sect2 id="functions-xml-mapping">
86998731
<title>Mapping Tables to XML</title>
87008732

8701-
<indexterm zone="functions-xml-mapping">
8733+
<indexterm zone="functions-xml-mapping">
87028734
<primary>XML export</primary>
87038735
</indexterm>
87048736

‎src/backend/utils/adt/xml.c

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.99 2010/08/05 04:21:54 petere Exp $
10+
* $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.100 2010/08/08 19:15:27 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -3541,3 +3541,27 @@ Datum xmlexists(PG_FUNCTION_ARGS)
35413541
return0;
35423542
#endif
35433543
}
3544+
3545+
/*
3546+
* Determines if the node specified by the supplied XPath exists
3547+
* in a given XML document, returning a boolean. Differs from
3548+
* xmlexists as it supports namespaces and is not defined in SQL/XML.
3549+
*/
3550+
Datum
3551+
xpath_exists(PG_FUNCTION_ARGS)
3552+
{
3553+
#ifdefUSE_LIBXML
3554+
text*xpath_expr_text=PG_GETARG_TEXT_P(0);
3555+
xmltype*data=PG_GETARG_XML_P(1);
3556+
ArrayType*namespaces=PG_GETARG_ARRAYTYPE_P(2);
3557+
intres_nitems;
3558+
3559+
xpath_internal(xpath_expr_text,data,namespaces,
3560+
&res_nitems,NULL);
3561+
3562+
PG_RETURN_BOOL(res_nitems>0);
3563+
#else
3564+
NO_XML_SUPPORT();
3565+
return0;
3566+
#endif
3567+
}

‎src/include/catalog/catversion.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
3838
* Portions Copyright (c) 1994, Regents of the University of California
3939
*
40-
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.592 2010/08/0816:27:04 tgl Exp $
40+
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.593 2010/08/0819:15:27 tgl Exp $
4141
*
4242
*-------------------------------------------------------------------------
4343
*/
@@ -53,6 +53,6 @@
5353
*/
5454

5555
/*yyyymmddN */
56-
#defineCATALOG_VERSION_NO201008071
56+
#defineCATALOG_VERSION_NO201008081
5757

5858
#endif

‎src/include/catalog/pg_proc.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.576 2010/08/0816:27:04 tgl Exp $
10+
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.577 2010/08/0819:15:27 tgl Exp $
1111
*
1212
* NOTES
1313
* The script catalog/genbki.pl reads this file and generates .bki
@@ -4415,6 +4415,11 @@ DESCR("evaluate XPath expression");
44154415
DATA(insertOID=2614 (xmlexistsPGNSPPGUID12100ffftfi2016"25 142"_null__null__null__null_xmlexists_null__null__null_ ));
44164416
DESCR("test XML value against XPath expression");
44174417

4418+
DATA(insertOID=3049 (xpath_existsPGNSPPGUID12100ffftfi3016"25 142 1009"_null__null__null__null_xpath_exists_null__null__null_ ));
4419+
DESCR("test XML value against XPath expression, with namespace support");
4420+
DATA(insertOID=3050 (xpath_existsPGNSPPGUID14100ffftfi2016"25 142"_null__null__null__null_"select pg_catalog.xpath_exists($1, $2, ''{}''::pg_catalog.text[])"_null__null__null_ ));
4421+
DESCR("test XML value against XPath expression");
4422+
44184423
/* uuid */
44194424
DATA(insertOID=2952 (uuid_inPGNSPPGUID12100ffftfi102950"2275"_null__null__null__null_uuid_in_null__null__null_ ));
44204425
DESCR("I/O");

‎src/include/utils/xml.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/utils/xml.h,v 1.32 2010/08/05 04:21:54 petere Exp $
10+
* $PostgreSQL: pgsql/src/include/utils/xml.h,v 1.33 2010/08/08 19:15:27 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -37,6 +37,7 @@ extern Datum texttoxml(PG_FUNCTION_ARGS);
3737
externDatumxmltotext(PG_FUNCTION_ARGS);
3838
externDatumxmlvalidate(PG_FUNCTION_ARGS);
3939
externDatumxpath(PG_FUNCTION_ARGS);
40+
externDatumxpath_exists(PG_FUNCTION_ARGS);
4041
externDatumxmlexists(PG_FUNCTION_ARGS);
4142

4243
externDatumtable_to_xml(PG_FUNCTION_ARGS);

‎src/test/regress/expected/xml.out

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,7 @@ SELECT xpath('//b', '<a>one <b>two</b> three <b>etc</b></a>');
502502
{<b>two</b>,<b>etc</b>}
503503
(1 row)
504504

505-
-- Test xmlexistsevaluation
505+
-- Test xmlexistsand xpath_exists
506506
SELECT xmlexists('//town[text() = ''Toronto'']' PASSING BY REF '<towns><town>Bidford-on-Avon</town><town>Cwmbran</town><town>Bristol</town></towns>');
507507
xmlexists
508508
-----------
@@ -515,6 +515,18 @@ SELECT xmlexists('//town[text() = ''Cwmbran'']' PASSING BY REF '<towns><town>Bid
515515
t
516516
(1 row)
517517

518+
SELECT xpath_exists('//town[text() = ''Toronto'']','<towns><town>Bidford-on-Avon</town><town>Cwmbran</town><town>Bristol</town></towns>'::xml);
519+
xpath_exists
520+
--------------
521+
f
522+
(1 row)
523+
524+
SELECT xpath_exists('//town[text() = ''Cwmbran'']','<towns><town>Bidford-on-Avon</town><town>Cwmbran</town><town>Bristol</town></towns>'::xml);
525+
xpath_exists
526+
--------------
527+
t
528+
(1 row)
529+
518530
INSERT INTO xmltest VALUES (4, '<menu><beers><name>Budvar</name><cost>free</cost><name>Carling</name><cost>lots</cost></beers></menu>'::xml);
519531
INSERT INTO xmltest VALUES (5, '<menu><beers><name>Molson</name><cost>free</cost><name>Carling</name><cost>lots</cost></beers></menu>'::xml);
520532
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
543555
1
544556
(1 row)
545557

558+
SELECT COUNT(id) FROM xmltest WHERE xpath_exists('/menu/beer',data);
559+
count
560+
-------
561+
0
562+
(1 row)
563+
564+
SELECT COUNT(id) FROM xmltest WHERE xpath_exists('/menu/beers',data);
565+
count
566+
-------
567+
2
568+
(1 row)
569+
570+
SELECT COUNT(id) FROM xmltest WHERE xpath_exists('/menu/beers/name[text() = ''Molson'']',data);
571+
count
572+
-------
573+
1
574+
(1 row)
575+
576+
SELECT COUNT(id) FROM xmltest WHERE xpath_exists('/myns:menu/myns:beer',data,ARRAY[ARRAY['myns','http://myns.com']]);
577+
count
578+
-------
579+
0
580+
(1 row)
581+
582+
SELECT COUNT(id) FROM xmltest WHERE xpath_exists('/myns:menu/myns:beers',data,ARRAY[ARRAY['myns','http://myns.com']]);
583+
count
584+
-------
585+
2
586+
(1 row)
587+
588+
SELECT COUNT(id) FROM xmltest WHERE xpath_exists('/myns:menu/myns:beers/myns:name[text() = ''Molson'']',data,ARRAY[ARRAY['myns','http://myns.com']]);
589+
count
590+
-------
591+
1
592+
(1 row)
593+
546594
CREATE TABLE query ( expr TEXT );
547595
INSERT INTO query VALUES ('/menu/beers/cost[text() = ''lots'']');
548596
SELECT COUNT(id) FROM xmltest, query WHERE xmlexists(expr PASSING BY REF data);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp