Skip to content

Commit a0b7b71

Browse files
committed
Add xml_is_well_formed, xml_is_well_formed_document, xml_is_well_formed_content
functions to the core XML code. Per discussion, the former depends on XMLOPTION while the others do not. These supersede a version previously offered by contrib/xml2. Mike Fowler, reviewed by Pavel Stehule
1 parent 2a7349f commit a0b7b71

File tree

11 files changed

+343
-18
lines changed

11 files changed

+343
-18
lines changed

contrib/xml2/pgxml.sql.in

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
1-
/* $PostgreSQL: pgsql/contrib/xml2/pgxml.sql.in,v 1.12 2010/03/01 18:07:59 tgl Exp $ */
1+
/* $PostgreSQL: pgsql/contrib/xml2/pgxml.sql.in,v 1.13 2010/08/13 18:36:23 tgl Exp $ */
22

33
-- Adjust this setting to control where the objects get created.
44
SET search_path = public;
55

66
--SQL for XML parser
77

8-
CREATE OR REPLACE FUNCTION xml_is_well_formed(text) RETURNS bool
9-
AS 'MODULE_PATHNAME'
10-
LANGUAGE C STRICT IMMUTABLE;
11-
128
-- deprecated old name for xml_is_well_formed
139
CREATE OR REPLACE FUNCTION xml_valid(text) RETURNS bool
14-
AS 'MODULE_PATHNAME', 'xml_is_well_formed'
15-
LANGUAGE C STRICT IMMUTABLE;
10+
AS 'xml_is_well_formed'
11+
LANGUAGE INTERNAL STRICT STABLE;
1612

1713
CREATE OR REPLACE FUNCTION xml_encode_special_chars(text) RETURNS text
1814
AS 'MODULE_PATHNAME'

contrib/xml2/uninstall_pgxml.sql

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* $PostgreSQL: pgsql/contrib/xml2/uninstall_pgxml.sql,v 1.4 2007/11/13 04:24:29 momjian Exp $ */
1+
/* $PostgreSQL: pgsql/contrib/xml2/uninstall_pgxml.sql,v 1.5 2010/08/13 18:36:23 tgl Exp $ */
22

33
-- Adjust this setting to control where the objects get dropped.
44
SET search_path = public;
@@ -29,5 +29,3 @@ DROP FUNCTION xml_encode_special_chars(text);
2929

3030
-- deprecated old name for xml_is_well_formed
3131
DROP FUNCTION xml_valid(text);
32-
33-
DROP FUNCTION xml_is_well_formed(text);

contrib/xml2/xpath.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* $PostgreSQL: pgsql/contrib/xml2/xpath.c,v 1.30 2010/07/06 19:18:55 momjian Exp $
2+
* $PostgreSQL: pgsql/contrib/xml2/xpath.c,v 1.31 2010/08/13 18:36:23 tgl Exp $
33
*
44
* Parser interface for DOM-based parser (libxml) rather than
55
* stream-based SAX-type parser
@@ -71,7 +71,14 @@ pgxml_parser_init(void)
7171
}
7272

7373

74-
/* Returns true if document is well-formed */
74+
/*
75+
* Returns true if document is well-formed
76+
*
77+
* Note: this has been superseded by a core function. We still have to
78+
* have it in the contrib module so that existing SQL-level references
79+
* to the function won't fail; but in normal usage with up-to-date SQL
80+
* definitions for the contrib module, this won't be called.
81+
*/
7582

7683
PG_FUNCTION_INFO_V1(xml_is_well_formed);
7784

doc/src/sgml/func.sgml

Lines changed: 79 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.526 2010/08/10 21:51:00 tgl Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.527 2010/08/13 18:36:23 tgl Exp $ -->
22

33
<chapter id="functions">
44
<title>Functions and Operators</title>
@@ -8625,6 +8625,84 @@ SELECT xmlexists('//town[text() = ''Toronto'']' PASSING BY REF '<towns><town>Tor
86258625
supports XPath, which is a subset of XQuery.
86268626
</para>
86278627
</sect3>
8628+
8629+
<sect3>
8630+
<title>xml_is_well_formed</title>
8631+
8632+
<indexterm>
8633+
<primary>xml_is_well_formed</primary>
8634+
</indexterm>
8635+
8636+
<indexterm>
8637+
<primary>xml_is_well_formed_document</primary>
8638+
</indexterm>
8639+
8640+
<indexterm>
8641+
<primary>xml_is_well_formed_content</primary>
8642+
</indexterm>
8643+
8644+
<synopsis>
8645+
<function>xml_is_well_formed</function>(<replaceable>text</replaceable>)
8646+
<function>xml_is_well_formed_document</function>(<replaceable>text</replaceable>)
8647+
<function>xml_is_well_formed_content</function>(<replaceable>text</replaceable>)
8648+
</synopsis>
8649+
8650+
<para>
8651+
These functions check whether a <type>text</> string is well-formed XML,
8652+
returning a boolean result.
8653+
<function>xml_is_well_formed_document</function> checks for a well-formed
8654+
document, while <function>xml_is_well_formed_content</function> checks
8655+
for well-formed content. <function>xml_is_well_formed</function> does
8656+
the former if the <xref linkend="guc-xmloption"> configuration
8657+
parameter is set to <literal>DOCUMENT</>, or the latter if it is set to
8658+
<literal>CONTENT</>. This means that
8659+
<function>xml_is_well_formed</function> is useful for seeing whether
8660+
a simple cast to type <type>xml</> will succeed, whereas the other two
8661+
functions are useful for seeing whether the corresponding variants of
8662+
<function>XMLPARSE</> will succeed.
8663+
</para>
8664+
8665+
<para>
8666+
Examples:
8667+
8668+
<screen><![CDATA[
8669+
SET xmloption TO DOCUMENT;
8670+
SELECT xml_is_well_formed('<>');
8671+
xml_is_well_formed
8672+
--------------------
8673+
f
8674+
(1 row)
8675+
8676+
SELECT xml_is_well_formed('<abc/>');
8677+
xml_is_well_formed
8678+
--------------------
8679+
t
8680+
(1 row)
8681+
8682+
SET xmloption TO CONTENT;
8683+
SELECT xml_is_well_formed('abc');
8684+
xml_is_well_formed
8685+
--------------------
8686+
t
8687+
(1 row)
8688+
8689+
SELECT xml_is_well_formed_document('<pg:foo xmlns:pg="http://postgresql.org/stuff">bar</pg:foo>');
8690+
xml_is_well_formed_document
8691+
-----------------------------
8692+
t
8693+
(1 row)
8694+
8695+
SELECT xml_is_well_formed_document('<pg:foo xmlns:pg="http://postgresql.org/stuff">bar</my:foo>');
8696+
xml_is_well_formed_document
8697+
-----------------------------
8698+
f
8699+
(1 row)
8700+
]]></screen>
8701+
8702+
The last example shows that the checks include whether
8703+
namespaces are correctly matched.
8704+
</para>
8705+
</sect3>
86288706
</sect2>
86298707

86308708
<sect2 id="functions-xml-processing">

src/backend/utils/adt/xml.c

Lines changed: 71 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.100 2010/08/08 19:15:27 tgl Exp $
10+
* $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.101 2010/08/13 18:36:24 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -3565,3 +3565,73 @@ xpath_exists(PG_FUNCTION_ARGS)
35653565
return 0;
35663566
#endif
35673567
}
3568+
3569+
/*
3570+
* Functions for checking well-formed-ness
3571+
*/
3572+
3573+
#ifdef USE_LIBXML
3574+
static bool
3575+
wellformed_xml(text *data, XmlOptionType xmloption_arg)
3576+
{
3577+
bool result;
3578+
xmlDocPtr doc = NULL;
3579+
3580+
/* We want to catch any exceptions and return false */
3581+
PG_TRY();
3582+
{
3583+
doc = xml_parse(data, xmloption_arg, true, GetDatabaseEncoding());
3584+
result = true;
3585+
}
3586+
PG_CATCH();
3587+
{
3588+
FlushErrorState();
3589+
result = false;
3590+
}
3591+
PG_END_TRY();
3592+
3593+
if (doc)
3594+
xmlFreeDoc(doc);
3595+
3596+
return result;
3597+
}
3598+
#endif
3599+
3600+
Datum
3601+
xml_is_well_formed(PG_FUNCTION_ARGS)
3602+
{
3603+
#ifdef USE_LIBXML
3604+
text *data = PG_GETARG_TEXT_P(0);
3605+
3606+
PG_RETURN_BOOL(wellformed_xml(data, xmloption));
3607+
#else
3608+
NO_XML_SUPPORT();
3609+
return 0;
3610+
#endif /* not USE_LIBXML */
3611+
}
3612+
3613+
Datum
3614+
xml_is_well_formed_document(PG_FUNCTION_ARGS)
3615+
{
3616+
#ifdef USE_LIBXML
3617+
text *data = PG_GETARG_TEXT_P(0);
3618+
3619+
PG_RETURN_BOOL(wellformed_xml(data, XMLOPTION_DOCUMENT));
3620+
#else
3621+
NO_XML_SUPPORT();
3622+
return 0;
3623+
#endif /* not USE_LIBXML */
3624+
}
3625+
3626+
Datum
3627+
xml_is_well_formed_content(PG_FUNCTION_ARGS)
3628+
{
3629+
#ifdef USE_LIBXML
3630+
text *data = PG_GETARG_TEXT_P(0);
3631+
3632+
PG_RETURN_BOOL(wellformed_xml(data, XMLOPTION_CONTENT));
3633+
#else
3634+
NO_XML_SUPPORT();
3635+
return 0;
3636+
#endif /* not USE_LIBXML */
3637+
}

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.594 2010/08/10 21:51:00 tgl Exp $
40+
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.595 2010/08/13 18:36:24 tgl Exp $
4141
*
4242
*-------------------------------------------------------------------------
4343
*/
@@ -53,6 +53,6 @@
5353
*/
5454

5555
/* yyyymmddN */
56-
#define CATALOG_VERSION_NO 201008101
56+
#define CATALOG_VERSION_NO 201008131
5757

5858
#endif

src/include/catalog/pg_proc.h

Lines changed: 7 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.578 2010/08/10 21:51:00 tgl Exp $
10+
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.579 2010/08/13 18:36:25 tgl Exp $
1111
*
1212
* NOTES
1313
* The script catalog/genbki.pl reads this file and generates .bki
@@ -4423,6 +4423,12 @@ DATA(insert OID = 3049 ( xpath_exists PGNSP PGUID 12 1 0 0 f f f t f i 3 0 16
44234423
DESCR("test XML value against XPath expression, with namespace support");
44244424
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_ ));
44254425
DESCR("test XML value against XPath expression");
4426+
DATA(insert OID = 3051 ( xml_is_well_formed PGNSP PGUID 12 1 0 0 f f f t f s 1 0 16 "25" _null_ _null_ _null_ _null_ xml_is_well_formed _null_ _null_ _null_ ));
4427+
DESCR("determine if a string is well formed XML");
4428+
DATA(insert OID = 3052 ( xml_is_well_formed_document PGNSP PGUID 12 1 0 0 f f f t f i 1 0 16 "25" _null_ _null_ _null_ _null_ xml_is_well_formed_document _null_ _null_ _null_ ));
4429+
DESCR("determine if a string is well formed XML document");
4430+
DATA(insert OID = 3053 ( xml_is_well_formed_content PGNSP PGUID 12 1 0 0 f f f t f i 1 0 16 "25" _null_ _null_ _null_ _null_ xml_is_well_formed_content _null_ _null_ _null_ ));
4431+
DESCR("determine if a string is well formed XML content");
44264432

44274433
/* uuid */
44284434
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_ ));

src/include/utils/xml.h

Lines changed: 4 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.33 2010/08/08 19:15:27 tgl Exp $
10+
* $PostgreSQL: pgsql/src/include/utils/xml.h,v 1.34 2010/08/13 18:36:26 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -39,6 +39,9 @@ extern Datum xmlvalidate(PG_FUNCTION_ARGS);
3939
extern Datum xpath(PG_FUNCTION_ARGS);
4040
extern Datum xpath_exists(PG_FUNCTION_ARGS);
4141
extern Datum xmlexists(PG_FUNCTION_ARGS);
42+
extern Datum xml_is_well_formed(PG_FUNCTION_ARGS);
43+
extern Datum xml_is_well_formed_document(PG_FUNCTION_ARGS);
44+
extern Datum xml_is_well_formed_content(PG_FUNCTION_ARGS);
4245

4346
extern Datum table_to_xml(PG_FUNCTION_ARGS);
4447
extern Datum query_to_xml(PG_FUNCTION_ARGS);

src/test/regress/expected/xml.out

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,3 +599,90 @@ SELECT COUNT(id) FROM xmltest, query WHERE xmlexists(expr PASSING BY REF data);
599599
2
600600
(1 row)
601601

602+
-- Test xml_is_well_formed and variants
603+
SELECT xml_is_well_formed_document('<foo>bar</foo>');
604+
xml_is_well_formed_document
605+
-----------------------------
606+
t
607+
(1 row)
608+
609+
SELECT xml_is_well_formed_document('abc');
610+
xml_is_well_formed_document
611+
-----------------------------
612+
f
613+
(1 row)
614+
615+
SELECT xml_is_well_formed_content('<foo>bar</foo>');
616+
xml_is_well_formed_content
617+
----------------------------
618+
t
619+
(1 row)
620+
621+
SELECT xml_is_well_formed_content('abc');
622+
xml_is_well_formed_content
623+
----------------------------
624+
t
625+
(1 row)
626+
627+
SET xmloption TO DOCUMENT;
628+
SELECT xml_is_well_formed('abc');
629+
xml_is_well_formed
630+
--------------------
631+
f
632+
(1 row)
633+
634+
SELECT xml_is_well_formed('<>');
635+
xml_is_well_formed
636+
--------------------
637+
f
638+
(1 row)
639+
640+
SELECT xml_is_well_formed('<abc/>');
641+
xml_is_well_formed
642+
--------------------
643+
t
644+
(1 row)
645+
646+
SELECT xml_is_well_formed('<foo>bar</foo>');
647+
xml_is_well_formed
648+
--------------------
649+
t
650+
(1 row)
651+
652+
SELECT xml_is_well_formed('<foo>bar</foo');
653+
xml_is_well_formed
654+
--------------------
655+
f
656+
(1 row)
657+
658+
SELECT xml_is_well_formed('<foo><bar>baz</foo>');
659+
xml_is_well_formed
660+
--------------------
661+
f
662+
(1 row)
663+
664+
SELECT xml_is_well_formed('<local:data xmlns:local="http://127.0.0.1"><local:piece id="1">number one</local:piece><local:piece id="2" /></local:data>');
665+
xml_is_well_formed
666+
--------------------
667+
t
668+
(1 row)
669+
670+
SELECT xml_is_well_formed('<pg:foo xmlns:pg="http://postgresql.org/stuff">bar</my:foo>');
671+
xml_is_well_formed
672+
--------------------
673+
f
674+
(1 row)
675+
676+
SELECT xml_is_well_formed('<pg:foo xmlns:pg="http://postgresql.org/stuff">bar</pg:foo>');
677+
xml_is_well_formed
678+
--------------------
679+
t
680+
(1 row)
681+
682+
SET xmloption TO CONTENT;
683+
SELECT xml_is_well_formed('abc');
684+
xml_is_well_formed
685+
--------------------
686+
t
687+
(1 row)
688+

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy