Hi Umar, Hi Pavel,

On 26.12.24 14:46, Jim Jones wrote:
> The idea of NO DEFAULT is pretty much to free an element (and its
> children) from a previous DEFAULT in the same scope.
>
> SELECT
>   xmlserialize(DOCUMENT
>     xmlelement(NAME "root",
>       xmlnamespaces(DEFAULT 'http:/x.y/ns1'),
>       xmlelement(NAME "foo",
>         xmlnamespaces(NO DEFAULT))
>   ) AS text INDENT);
>
>          xmlserialize         
> ------------------------------
>  <root xmlns="http:/x.y/ns1">+
>    <foo xmlns=""/>           +
>  </root>
> (1 row)

v3 is attached, now using xmlTextWriterWriteAttributeNS from libxml2 for
managing XML namespaces, instead of using xmlTextWriterWriteAttribute.
Libxml2 is quite lenient, allowing the duplication of default namespaces
within the same scope and even permitting NO DEFAULT namespaces when no
previous DEFAULT declaration has been made - both are semantically valid.

The crux now is finding the appropriate balance between accuracy and
user intent. In the context of PostgreSQL's xmlelement and
xmlnamespaces, I would argue that explicitly declared namespaces,
redundant or not, ought to be preserved. A user who intentionally
repeats a namespace declaration might have sound reasons for doing so,
like ensuring clarity, preserving compatibility with external XML
processors, or sticking to a specific schema. Silently omitting these
declarations could lead to confusion.

Pavel has tidied up the parser modifications - it's looking much neater
now. Many thanks for that!

Best, Jim

From be391fc95c16e2b9197257553310f68415a9f3d3 Mon Sep 17 00:00:00 2001
From: Jim Jones <jim.jo...@uni-muenster.de>
Date: Wed, 15 Jan 2025 20:21:27 +0100
Subject: [PATCH v3] Add XMLNamespaces option to XMLElement

This patch adds the scoped option XMLNamespaces to XMLElement,
as described in ISO/IEC 9075-14:2023, 11.2 XML lexically scoped
options:

xmlnamespaces(uri AS prefix, ...)
xmlnamespaces(DEFAULT uri, ...)
xmlnamespaces(NO DEFAULT, ...)

* prefix:         Namespace's prefix.
* uri:            Namespace's URI.
* DEFAULT prefix: Specifies the DEFAULT namespace to use within
the scope of a namespace declaration.
* NO DEFAULT:     Specifies that NO DEFAULT namespace is to be
used within the scope of a namespace declaration.

== Examples ==

SELECT xmlelement(NAME "foo", xmlnamespaces('http:/x.y' AS bar));
          xmlelement
------------------------------
 <foo xmlns:bar="http:/x.y"/>

SELECT xmlelement(NAME "foo", xmlnamespaces(DEFAULT 'http:/x.y'));
        xmlelement
--------------------------
 <foo xmlns="http:/x.y"/>

 SELECT xmlelement(NAME "foo", xmlnamespaces(NO DEFAULT));
   xmlelement
-----------------
 <foo xmlns=""/>

Tests and documentation were updated accordingly.
---
 doc/src/sgml/func.sgml              |  57 ++++++-
 src/backend/parser/gram.y           | 100 ++++++++++--
 src/backend/parser/parse_expr.c     |  80 ++++++++++
 src/backend/utils/adt/xml.c         |  47 +++++-
 src/include/nodes/primnodes.h       |   4 +-
 src/include/utils/xml.h             |   6 +
 src/test/regress/expected/xml.out   | 236 ++++++++++++++++++++++++++++
 src/test/regress/expected/xml_1.out | 172 ++++++++++++++++++++
 src/test/regress/expected/xml_2.out | 236 ++++++++++++++++++++++++++++
 src/test/regress/sql/xml.sql        | 116 ++++++++++++++
 10 files changed, 1032 insertions(+), 22 deletions(-)

diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 47370e581a..b33663bc09 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -14482,7 +14482,10 @@ SELECT xmlconcat('<?xml version="1.1"?><foo/>', '<?xml version="1.1" standalone=
    </indexterm>
 
 <synopsis>
-<function>xmlelement</function> ( <literal>NAME</literal> <replaceable>name</replaceable> <optional>, <literal>XMLATTRIBUTES</literal> ( <replaceable>attvalue</replaceable> <optional> <literal>AS</literal> <replaceable>attname</replaceable> </optional> <optional>, ...</optional> ) </optional> <optional>, <replaceable>content</replaceable> <optional>, ...</optional></optional> ) <returnvalue>xml</returnvalue>
+<function>xmlelement</function> ( <literal>NAME</literal> <replaceable>name</replaceable>
+    <optional>, <literal>XMLATTRIBUTES</literal> ( <replaceable>attvalue</replaceable> <optional> <literal>AS</literal> <replaceable>attname</replaceable> </optional> <optional>, ...</optional> ) </optional>
+    <optional>, <literal>XMLNAMESPACES</literal> ( {<replaceable>regular-nsuri</replaceable> <literal>AS</literal> <replaceable>nsprefix</replaceable> | DEFAULT <replaceable>default-nsuri</replaceable> | NO DEFAULT} <optional>, ...</optional> ) </optional>
+<optional>, <replaceable>content</replaceable> <optional>, ...</optional></optional> ) <returnvalue>xml</returnvalue>
 </synopsis>
 
     <para>
@@ -14495,7 +14498,39 @@ SELECT xmlconcat('<?xml version="1.1"?><foo/>', '<?xml version="1.1" standalone=
      yield any <productname>PostgreSQL</productname> data type.  The
      argument(s) within <literal>XMLATTRIBUTES</literal> generate attributes
      of the XML element; the <replaceable>content</replaceable> value(s) are
-     concatenated to form its content.
+     concatenated to form its content. The arguments within <literal>XMLNAMESPACES</literal>
+     constuct namespace declarations from values provided in <replaceable>nsuri</replaceable>
+     and <replaceable>nsprefix</replaceable>, which correspond to the URI of a namespace and
+     its prefix, respectively. The option <literal>DEFAULT</literal> can be used to set the
+     default namespace declaration (without a prefix) to the URI provided in <replaceable>default-nsuri</replaceable>.
+     The option <literal>NO DEFAULT</literal> states that a namespace scope has no default namespace. A valid
+     <literal>XMLNAMESPACES</literal> item must fulfill the following conditions:
+
+    <itemizedlist>
+    <listitem>
+     <para>
+      Only a single <literal>DEFAULT</literal> declaration item within the same scope.
+     </para>
+    </listitem>
+    <listitem>
+     <para>
+      No two <replaceable>nsuri</replaceable> can be equal within the same scope.
+     </para>
+    </listitem>
+    <listitem>
+     <para>
+      No <replaceable>nsprefix</replaceable> can be equal to <literal>xml</literal> or <literal>xmlns</literal>,
+      and no <replaceable>nsuri</replaceable> can be equal to <literal>http://www.w3.org/2000/xmlns/</literal>
+      or to <literal>http://www.w3.org/XML/1998/namespace</literal>, as they are already bouned to standard XML declarations.
+     </para>
+    </listitem>
+    <listitem>
+     <para>
+      The value of a <replaceable>regular-nsuri</replaceable> cannot be a zero-length string.
+     </para>
+    </listitem>
+   </itemizedlist>
+
     </para>
 
     <para>
@@ -14518,6 +14553,24 @@ SELECT xmlelement(name foo, xmlattributes(current_date as bar), 'cont', 'ent');
              xmlelement
 -------------------------------------
  <foo bar="2007-01-26">content</foo>
+
+SELECT xmlelement(NAME "foo:root", xmlnamespaces('http:/foo.bar/' AS foo), 'content');
+
+                       xmlelement
+---------------------------------------------------------
+ <foo:root xmlns:foo="http:/foo.bar/">content</foo:root>
+
+ SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http:/foo.bar/'), 'content');
+
+                 xmlelement
+---------------------------------------------
+ <root xmlns="http:/foo.bar/">content</root>
+
+ SELECT xmlelement(NAME "root", xmlnamespaces(NO DEFAULT), 'content');
+
+          xmlelement
+-------------------------------
+ <root xmlns="">content</root>
 ]]></screen>
     </para>
 
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 6079de70e0..9bf3af484c 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -136,6 +136,12 @@ typedef struct KeyActions
 	KeyAction *deleteAction;
 } KeyActions;
 
+typedef struct XmlElementOpts
+{
+	List	   *xml_attributes;
+	List	   *xml_namespaces;
+} XmlElementOpts;
+
 /* ConstraintAttributeSpec yields an integer bitmask of these flags: */
 #define CAS_NOT_DEFERRABLE			0x01
 #define CAS_DEFERRABLE				0x02
@@ -187,7 +193,7 @@ static Node *makeNotExpr(Node *expr, int location);
 static Node *makeAArrayExpr(List *elements, int location);
 static Node *makeSQLValueFunction(SQLValueFunctionOp op, int32 typmod,
 								  int location);
-static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args,
+static Node *makeXmlExpr(XmlExprOp op, char *name, XmlElementOpts *opts,
 						 List *args, int location);
 static List *mergeTableFuncParameters(List *func_args, List *columns, core_yyscan_t yyscanner);
 static TypeName *TableFuncTypeName(List *columns);
@@ -267,6 +273,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 	MergeWhenClause *mergewhen;
 	struct KeyActions *keyactions;
 	struct KeyAction *keyaction;
+	struct XmlElementOpts *xmlelementopts;
 }
 
 %type <node>	stmt toplevel_stmt schema_stmt routine_body_stmt
@@ -612,8 +619,9 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 %type <list>	xmltable_column_list xmltable_column_option_list
 %type <node>	xmltable_column_el
 %type <defelt>	xmltable_column_option_el
-%type <list>	xml_namespace_list
+%type <list>	xml_namespace_list xml_namespaces
 %type <target>	xml_namespace_el
+%type <xmlelementopts> xmlelement_opts
 
 %type <node>	func_application func_expr_common_subexpr
 %type <node>	func_expr func_expr_windowless
@@ -14235,6 +14243,15 @@ xml_namespace_el:
 					$$->val = $2;
 					$$->location = @1;
 				}
+			| NO DEFAULT
+				{
+					$$ = makeNode(ResTarget);
+					$$->name = NULL;
+					$$->indirection = NIL;
+					$$->val = NULL;
+					$$->location = @1;
+				}
+
 		;
 
 json_table:
@@ -15288,12 +15305,12 @@ a_expr:		c_expr									{ $$ = $1; }
 				}
 			| a_expr IS DOCUMENT_P					%prec IS
 				{
-					$$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL,
+					$$ = makeXmlExpr(IS_DOCUMENT, NULL, NULL,
 									 list_make1($1), @2);
 				}
 			| a_expr IS NOT DOCUMENT_P				%prec IS
 				{
-					$$ = makeNotExpr(makeXmlExpr(IS_DOCUMENT, NULL, NIL,
+					$$ = makeNotExpr(makeXmlExpr(IS_DOCUMENT, NULL, NULL,
 												 list_make1($1), @2),
 									 @2);
 				}
@@ -15435,12 +15452,12 @@ b_expr:		c_expr
 				}
 			| b_expr IS DOCUMENT_P					%prec IS
 				{
-					$$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL,
+					$$ = makeXmlExpr(IS_DOCUMENT, NULL, NULL,
 									 list_make1($1), @2);
 				}
 			| b_expr IS NOT DOCUMENT_P				%prec IS
 				{
-					$$ = makeNotExpr(makeXmlExpr(IS_DOCUMENT, NULL, NIL,
+					$$ = makeNotExpr(makeXmlExpr(IS_DOCUMENT, NULL, NULL,
 												 list_make1($1), @2),
 									 @2);
 				}
@@ -15975,21 +15992,21 @@ func_expr_common_subexpr:
 				}
 			| XMLCONCAT '(' expr_list ')'
 				{
-					$$ = makeXmlExpr(IS_XMLCONCAT, NULL, NIL, $3, @1);
+					$$ = makeXmlExpr(IS_XMLCONCAT, NULL, NULL, $3, @1);
 				}
 			| XMLELEMENT '(' NAME_P ColLabel ')'
 				{
-					$$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, NIL, @1);
+					$$ = makeXmlExpr(IS_XMLELEMENT, $4, NULL, NIL, @1);
 				}
-			| XMLELEMENT '(' NAME_P ColLabel ',' xml_attributes ')'
+			| XMLELEMENT '(' NAME_P ColLabel ',' xmlelement_opts ')'
 				{
 					$$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, NIL, @1);
 				}
 			| XMLELEMENT '(' NAME_P ColLabel ',' expr_list ')'
 				{
-					$$ = makeXmlExpr(IS_XMLELEMENT, $4, NIL, $6, @1);
+					$$ = makeXmlExpr(IS_XMLELEMENT, $4, NULL, $6, @1);
 				}
-			| XMLELEMENT '(' NAME_P ColLabel ',' xml_attributes ',' expr_list ')'
+			| XMLELEMENT '(' NAME_P ColLabel ',' xmlelement_opts ',' expr_list ')'
 				{
 					$$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, $8, @1);
 				}
@@ -16004,12 +16021,17 @@ func_expr_common_subexpr:
 				}
 			| XMLFOREST '(' xml_attribute_list ')'
 				{
-					$$ = makeXmlExpr(IS_XMLFOREST, NULL, $3, NIL, @1);
+					XmlElementOpts opts;
+
+					opts.xml_attributes = $3;
+					opts.xml_namespaces = NIL;
+
+					$$ = makeXmlExpr(IS_XMLFOREST, NULL, &opts, NIL, @1);
 				}
 			| XMLPARSE '(' document_or_content a_expr xml_whitespace_option ')'
 				{
 					XmlExpr *x = (XmlExpr *)
-						makeXmlExpr(IS_XMLPARSE, NULL, NIL,
+						makeXmlExpr(IS_XMLPARSE, NULL, NULL,
 									list_make2($4, makeBoolAConst($5, -1)),
 									@1);
 
@@ -16026,7 +16048,7 @@ func_expr_common_subexpr:
 				}
 			| XMLROOT '(' a_expr ',' xml_root_version opt_xml_root_standalone ')'
 				{
-					$$ = makeXmlExpr(IS_XMLROOT, NULL, NIL,
+					$$ = makeXmlExpr(IS_XMLROOT, NULL, NULL,
 									 list_make3($3, $5, $6), @1);
 				}
 			| XMLSERIALIZE '(' document_or_content a_expr AS SimpleTypename xml_indent_option ')'
@@ -16230,6 +16252,9 @@ opt_xml_root_standalone: ',' STANDALONE_P YES_P
 xml_attributes: XMLATTRIBUTES '(' xml_attribute_list ')'	{ $$ = $3; }
 		;
 
+xml_namespaces: XMLNAMESPACES '(' xml_namespace_list ')'	{ $$ = $3; }
+		;
+
 xml_attribute_list:	xml_attribute_el					{ $$ = list_make1($1); }
 			| xml_attribute_list ',' xml_attribute_el	{ $$ = lappend($1, $3); }
 		;
@@ -16266,6 +16291,44 @@ xml_whitespace_option: PRESERVE WHITESPACE_P		{ $$ = true; }
 			| /*EMPTY*/								{ $$ = false; }
 		;
 
+xmlelement_opts: xml_attributes
+				{
+					XmlElementOpts *n = palloc(sizeof(XmlElementOpts));
+
+					n->xml_attributes = $1;
+					n->xml_namespaces = NIL;
+					$$ = n;
+				}
+			| xml_namespaces
+				{
+					XmlElementOpts *n = palloc(sizeof(XmlElementOpts));
+
+					n->xml_attributes = NIL;
+					n->xml_namespaces = $1;
+					$$ = n;
+				}
+			| xmlelement_opts ',' xml_attributes
+				{
+					if ($$->xml_attributes)
+						ereport(ERROR,
+							(errcode(ERRCODE_DUPLICATE_OBJECT),
+							 errmsg("duplicate XMLATTRIBUTES specified"),
+							 parser_errposition(@3)));
+
+					$$->xml_attributes = $3;
+				}
+			| xmlelement_opts ',' xml_namespaces
+				{
+					if ($$->xml_namespaces)
+						ereport(ERROR,
+							(errcode(ERRCODE_DUPLICATE_OBJECT),
+							 errmsg("duplicate XMLNAMESACES specified"),
+							 parser_errposition(@3)));
+
+					$$->xml_namespaces = $3;
+				}
+		;
+
 /* We allow several variants for SQL and other compatibility. */
 xmlexists_argument:
 			PASSING c_expr
@@ -19238,7 +19301,7 @@ makeSQLValueFunction(SQLValueFunctionOp op, int32 typmod, int location)
 }
 
 static Node *
-makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args,
+makeXmlExpr(XmlExprOp op, char *name, XmlElementOpts *opts, List *args,
 			int location)
 {
 	XmlExpr    *x = makeNode(XmlExpr);
@@ -19250,7 +19313,12 @@ makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args,
 	 * named_args is a list of ResTarget; it'll be split apart into separate
 	 * expression and name lists in transformXmlExpr().
 	 */
-	x->named_args = named_args;
+	if (opts)
+	{
+		x->named_args = opts->xml_attributes;
+		x->xmlnamespaces = opts->xml_namespaces;
+	}
+
 	x->arg_names = NIL;
 	x->args = args;
 	/* xmloption, if relevant, must be filled in by caller */
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index d1f64f8f0a..322e07e22c 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -2347,6 +2347,7 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x)
 	XmlExpr    *newx;
 	ListCell   *lc;
 	int			i;
+	bool		has_default_xmlns = false;
 
 	newx = makeNode(XmlExpr);
 	newx->op = x->op;
@@ -2366,6 +2367,80 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x)
 	newx->named_args = NIL;
 	newx->arg_names = NIL;
 
+	/*
+	 * this adds the xmlnamespaces into arg_names and named_args
+	 */
+	foreach (lc, x->xmlnamespaces)
+	{
+		ResTarget *r = lfirst_node(ResTarget, lc);
+		Node *expr;
+		ListCell *lc2;
+		char	   *argname = NULL;
+
+		/*
+		 * SQL/XML:2023 - 11.2 <XML lexically scoped options>
+		 * Syntax Rule 2) <XML namespace declaration> shall contain at most one
+		 * <XML default namespace declaration item>.
+		 */
+		if (!r->name)
+		{
+			if (has_default_xmlns)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("XML elements can have only a single [NO] DEFAULT namespace"),
+						 parser_errposition(pstate, r->location)));
+
+			has_default_xmlns = true;
+		}
+		/*
+		 * SQL/XML:2023 - 11.2 <XML lexically scoped options>
+		 * Syntax Rule 5) No <XML namespace prefix> shall be equivalent to
+		 * "xml" or "xmlns".
+		 */
+		else if (strcmp(r->name, NAMESPACE_XMLNS_DEFAULT_PREFIX) == 0 ||
+				 strcmp(r->name, NAMESPACE_XML_DEFAULT_PREFIX) == 0)
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					 errmsg("invalid XML namespace prefix \"%s\"", r->name),
+					 errdetail("this prefix is already bounded to a standard namespace URI"),
+					 parser_errposition(pstate, r->location)));
+		else if (r->name)
+			argname = map_sql_identifier_to_xml_name(r->name, false, false);
+
+		else if (IsA(r->val, ColumnRef))
+			argname = map_sql_identifier_to_xml_name(FigureColname(r->val),
+													 true, false);
+
+		/*
+		 * SQL/XML:2023 - 11.2 <XML lexically scoped options>
+		 * Syntax Rule 4) No two <XML namespace prefix>es shall be equivalent.
+		 */
+		if (x->op == IS_XMLELEMENT && argname)
+		{
+			foreach(lc2, newx->arg_names)
+			{
+				if (!strVal(lfirst(lc2)))
+					continue;
+
+				if (strVal(lfirst(lc2)) && strcmp(argname, strVal(lfirst(lc2))) == 0)
+					ereport(ERROR,
+							(errcode(ERRCODE_SYNTAX_ERROR),
+							 errmsg("XML namespace name \"%s\" appears more than once",
+									argname),
+							 parser_errposition(pstate, r->location)));
+			}
+		}
+
+		if(r->val)
+			expr = transformExprRecurse(pstate, r->val);
+		else
+			expr = transformExprRecurse(pstate, makeStringConst("", newx->location));
+
+		newx->named_args = lappend(newx->named_args, expr);
+		newx->arg_names = lappend(newx->arg_names, makeString(argname));
+		newx->xmlnamespaces = lappend(newx->xmlnamespaces, makeString(NAMESPACE_XMLNS_DEFAULT_PREFIX));
+	}
+
 	foreach(lc, x->named_args)
 	{
 		ResTarget  *r = lfirst_node(ResTarget, lc);
@@ -2397,6 +2472,10 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x)
 
 			foreach(lc2, newx->arg_names)
 			{
+
+				if (!strVal(lfirst(lc2)))
+					continue;
+
 				if (strcmp(argname, strVal(lfirst(lc2))) == 0)
 					ereport(ERROR,
 							(errcode(ERRCODE_SYNTAX_ERROR),
@@ -2408,6 +2487,7 @@ transformXmlExpr(ParseState *pstate, XmlExpr *x)
 
 		newx->named_args = lappend(newx->named_args, expr);
 		newx->arg_names = lappend(newx->arg_names, makeString(argname));
+		newx->xmlnamespaces = lappend(newx->xmlnamespaces, makeString(""));
 	}
 
 	/* The other arguments are of varying types depending on the function */
diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c
index db8d0d6a7e..ce79d97a5b 100644
--- a/src/backend/utils/adt/xml.c
+++ b/src/backend/utils/adt/xml.c
@@ -244,7 +244,6 @@ const TableFuncRoutine XmlTableRoutine =
 #define NAMESPACE_XSI "http://www.w3.org/2001/XMLSchema-instance";
 #define NAMESPACE_SQLXML "http://standards.iso.org/iso/9075/2003/sqlxml";
 
-
 #ifdef USE_LIBXML
 
 static int
@@ -865,6 +864,7 @@ xmlelement(XmlExpr *xexpr,
 	int			i;
 	ListCell   *arg;
 	ListCell   *narg;
+	ListCell   *nsarg;
 	PgXmlErrorContext *xmlerrcxt;
 	volatile xmlBufferPtr buf = NULL;
 	volatile xmlTextWriterPtr writer = NULL;
@@ -926,12 +926,53 @@ xmlelement(XmlExpr *xexpr,
 
 		xmlTextWriterStartElement(writer, (xmlChar *) xexpr->name);
 
-		forboth(arg, named_arg_strings, narg, xexpr->arg_names)
+		forthree(arg, named_arg_strings, narg, xexpr->arg_names, nsarg, xexpr->xmlnamespaces)
 		{
 			char	   *str = (char *) lfirst(arg);
 			char	   *argname = strVal(lfirst(narg));
+			char	   *prefix = strVal(lfirst(nsarg));
 
-			if (str)
+			if (str && strlen(prefix) != 0)
+			{
+				/*
+				 * SQL/XML:2023 - 11.2 <XML lexically scoped options>
+				 * Syntax Rule 6) No <XML namespace URI> shall be identical, as defined
+				 * in XML Namespaces, to http://www.w3.org/2000/xmlns/ or to
+				 * http://www.w3.org/XML/1998/namespace
+				 */
+				if (strcmp(str, NAMESPACE_XMLNS) == 0 || strcmp(str, NAMESPACE_XML) == 0)
+					ereport(ERROR,
+							(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+							 errmsg("invalid XML namespace URI \"%s\"", str),
+							 errdetail("this URI is already bounded to standard a namespace prefix")));
+
+				/*
+				 * SQL/XML:2023 - 11.2 <XML lexically scoped options>
+				 * Syntax Rule 7) The value of an <XML namespace URI> contained in an
+				 * <XML regular namespace declaration item> shall not be a zero-length string.
+				 */
+				if (argname && strlen(str) == 0)
+					ereport(ERROR,
+							(errcode(ERRCODE_ZERO_LENGTH_CHARACTER_STRING),
+							 errmsg("invalid XML namespace URI for \"%s\"", argname),
+							 errdetail("a regular XML namespace cannot be a zero-length string")));
+
+				/*
+				* xmlTextWriterWriteAttributeNS
+				*   prefix       - Namespace prefix for the attribute. Pass NULL for no prefix,
+				*				   which means DEFAULT namespace.
+				*   name         - Local name of the attribute (without prefix). This is the
+				*				   actual attribute name.
+				*   namespaceURI - Namespace URI associated with the prefix (NULL for none).
+				*   content      - Value of the attribute.
+				*/
+				xmlTextWriterWriteAttributeNS(writer,
+											  !argname ? NULL : (const xmlChar *) prefix,
+											  argname ? (const xmlChar *) argname : (const xmlChar *) prefix,
+											  NULL,
+											  (const xmlChar *) str);
+			}
+			else if (str)
 				xmlTextWriterWriteAttribute(writer,
 											(xmlChar *) argname,
 											(xmlChar *) str);
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index 9c2957eb54..95d3af61db 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -1578,7 +1578,7 @@ typedef struct SQLValueFunction
 typedef enum XmlExprOp
 {
 	IS_XMLCONCAT,				/* XMLCONCAT(args) */
-	IS_XMLELEMENT,				/* XMLELEMENT(name, xml_attributes, args) */
+	IS_XMLELEMENT,				/* XMLELEMENT(name, xml_attributes, xml_namespaces, args) */
 	IS_XMLFOREST,				/* XMLFOREST(xml_attributes) */
 	IS_XMLPARSE,				/* XMLPARSE(text, is_doc, preserve_ws) */
 	IS_XMLPI,					/* XMLPI(name [, args]) */
@@ -1602,6 +1602,8 @@ typedef struct XmlExpr
 	char	   *name pg_node_attr(query_jumble_ignore);
 	/* non-XML expressions for xml_attributes */
 	List	   *named_args;
+	/* non-XML expressions for XMLNAMESPACES */
+	List	   *xmlnamespaces;
 	/* parallel list of String values */
 	List	   *arg_names pg_node_attr(query_jumble_ignore);
 	/* list of expressions */
diff --git a/src/include/utils/xml.h b/src/include/utils/xml.h
index 0d7a816b9f..4a714dbca9 100644
--- a/src/include/utils/xml.h
+++ b/src/include/utils/xml.h
@@ -59,6 +59,12 @@ XmlPGetDatum(const xmltype *X)
 	return PointerGetDatum(X);
 }
 
+/* reserved prefixes and URIs for XMLNamespace() from SQL/XML:2023, 11.2 */
+#define NAMESPACE_XMLNS "http://www.w3.org/2000/xmlns/";
+#define NAMESPACE_XML "http://www.w3.org/XML/1998/namespace";
+#define NAMESPACE_XMLNS_DEFAULT_PREFIX "xmlns"
+#define NAMESPACE_XML_DEFAULT_PREFIX "xml"
+
 #define PG_GETARG_XML_P(n)	DatumGetXmlP(PG_GETARG_DATUM(n))
 #define PG_RETURN_XML_P(x)	PG_RETURN_POINTER(x)
 
diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out
index 2e9616acda..67625c4773 100644
--- a/src/test/regress/expected/xml.out
+++ b/src/test/regress/expected/xml.out
@@ -225,6 +225,242 @@ SELECT xmlelement(name foo, xmlattributes('<>&"''' as funny, xml 'b<a/>r' as fun
  <foo funny="&lt;&gt;&amp;&quot;'" funnier="b&lt;a/&gt;r"/>
 (1 row)
 
+-- DEFAULT NULL xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT NULL));
+ xmlelement 
+------------
+ <root/>
+(1 row)
+
+-- DEFAULT xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http:/x.y/ns1'));
+          xmlelement           
+-------------------------------
+ <root xmlns="http:/x.y/ns1"/>
+(1 row)
+
+-- DEFAULT numeric xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 42.73));
+      xmlelement       
+-----------------------
+ <root xmlns="42.73"/>
+(1 row)
+
+-- DEFAULT empty xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT ''));
+    xmlelement    
+------------------
+ <root xmlns=""/>
+(1 row)
+
+-- DEFAULT empty xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(NO DEFAULT));
+    xmlelement    
+------------------
+ <root xmlns=""/>
+(1 row)
+
+-- Testing xmlnamespace with subqueries
+SELECT
+  xmlelement(NAME root, xmlnamespaces(DEFAULT 'ns'),
+    (SELECT xmlelement(NAME child1, xmlnamespaces(NO DEFAULT))));
+                 xmlelement                 
+--------------------------------------------
+ <root xmlns="ns"><child1 xmlns=""/></root>
+(1 row)
+
+-- Testing xmlnamespace url from ColumnRef
+CREATE TABLE xmlns (url text);
+INSERT INTO xmlns VALUES ('http:/x.y/ns1');
+SELECT
+  xmlserialize(DOCUMENT
+  xmlelement(NAME root, xmlnamespaces(DEFAULT 'foo', url AS ns),
+    xmlelement(NAME root,
+      xmlelement(NAME child2, xmlnamespaces(url AS ns, NO DEFAULT))))
+  AS text INDENT)
+FROM xmlns;
+                  xmlserialize                   
+-------------------------------------------------
+ <root xmlns="foo" xmlns:ns="http:/x.y/ns1">    +
+   <root>                                       +
+     <child2 xmlns:ns="http:/x.y/ns1" xmlns=""/>+
+   </root>                                      +
+ </root>
+(1 row)
+
+-- NULL xmlnamespace uri
+SELECT xmlelement(NAME "root", xmlnamespaces(NULL AS ns));
+ xmlelement 
+------------
+ <root/>
+(1 row)
+
+-- empty xmlelement containing one namespace
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1));
+            xmlelement             
+-----------------------------------
+ <root xmlns:ns1="http:/x.y/ns1"/>
+(1 row)
+
+-- empty xmlelement with DEFAULT and regular xmlnamespaces
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http:/x.y/ns1', 'http:/x.y/ns2' AS ns2));
+                       xmlelement                        
+---------------------------------------------------------
+ <root xmlns="http:/x.y/ns1" xmlns:ns2="http:/x.y/ns2"/>
+(1 row)
+
+-- xmlelement containing a namespace and a text node
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1), 'text node');
+                    xmlelement                    
+--------------------------------------------------
+ <root xmlns:ns1="http:/x.y/ns1">text node</root>
+(1 row)
+
+-- empty xmlelement containing a) xmlnamespace and b) xmlattribute
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1), xmlattributes('val' AS att));
+                 xmlelement                  
+---------------------------------------------
+ <root xmlns:ns1="http:/x.y/ns1" att="val"/>
+(1 row)
+
+-- empty xmlelement containing a) xmlattribute and b) xmlnamespace
+SELECT xmlelement(NAME "root", xmlattributes('val' AS att), xmlnamespaces('http:/x.y/ns1' AS ns1));
+                 xmlelement                  
+---------------------------------------------
+ <root xmlns:ns1="http:/x.y/ns1" att="val"/>
+(1 row)
+
+-- empty xmlelement containing two xmlnamespaces
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1, 'http:/x.y/ns2' AS ns2));
+                         xmlelement                          
+-------------------------------------------------------------
+ <root xmlns:ns1="http:/x.y/ns1" xmlns:ns2="http:/x.y/ns2"/>
+(1 row)
+
+-- empty xmlelement containing two xmlnamespaces and one xmlattribute
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1, 'http:/x.y/ns2' AS ns2), xmlattributes('val' AS att));
+                              xmlelement                               
+-----------------------------------------------------------------------
+ <root xmlns:ns1="http:/x.y/ns1" xmlns:ns2="http:/x.y/ns2" att="val"/>
+(1 row)
+
+-- xmlelement containing two xmlnamespaces, one xmlattribute,
+-- and a text node.
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1, 'http:/x.y/ns2' AS ns2), xmlattributes('val' AS att), 'text node');
+                                      xmlelement                                      
+--------------------------------------------------------------------------------------
+ <root xmlns:ns1="http:/x.y/ns1" xmlns:ns2="http:/x.y/ns2" att="val">text node</root>
+(1 row)
+
+-- empty root xmlelement containing one xmlnamespace, one xmlattribute,
+-- and one xmlelement child (ns1:foo).
+-- empty xmlelement child "ns1:foo" containing one xmlnamespace and one
+-- xmlelement child (ns2:bar).
+-- xmlelement child "ns2:bar" containing a text node.
+SELECT
+  xmlelement(NAME "root",
+    xmlnamespaces('http:/x.y/ns1' AS ns1),
+    xmlattributes('val' AS att),
+    xmlelement(NAME "ns1:foo",
+      xmlnamespaces('http:/x.y/ns2' AS ns2),
+      xmlelement(NAME "ns2:bar", 'text node'))
+  );
+                                                         xmlelement                                                         
+----------------------------------------------------------------------------------------------------------------------------
+ <root xmlns:ns1="http:/x.y/ns1" att="val"><ns1:foo xmlns:ns2="http:/x.y/ns2"><ns2:bar>text node</ns2:bar></ns1:foo></root>
+(1 row)
+
+-- empty root xmlelement containing one xmlnamespace, one xmlattribute,
+-- and one xmlelement child (ns1:foo).
+-- xmlelement child "ns1:foo" containing one xmlnamespace, one xmlelement
+-- child (ns2:bar), and a text node.
+-- xmlelement child "ns2:bar" containing a text node.
+SELECT
+  xmlelement(NAME "root",
+    xmlnamespaces('http:/x.y/ns1' AS ns1),
+    xmlattributes('val' AS att),
+    xmlelement(NAME "ns1:foo",
+      xmlnamespaces('http:/x.y/ns2' AS ns2),
+      xmlelement(NAME "ns2:bar", 'text node'),
+      'mixed content')
+  );
+                                                               xmlelement                                                                
+-----------------------------------------------------------------------------------------------------------------------------------------
+ <root xmlns:ns1="http:/x.y/ns1" att="val"><ns1:foo xmlns:ns2="http:/x.y/ns2"><ns2:bar>text node</ns2:bar>mixed content</ns1:foo></root>
+(1 row)
+
+-- empty root xmlelement containing one DEFAULT xmlnamespace, one xmlattribute,
+-- and one xmlelement child (foo).
+-- xmlelement child "foo" containing one NO DEFAULT xmlnamespace and a text node.
+SELECT
+  xmlelement(NAME "root",
+    xmlnamespaces(DEFAULT 'http:/x.y/ns1'),
+    xmlattributes('val' AS att),
+    xmlelement(NAME "foo",
+      xmlnamespaces(NO DEFAULT),'bar')
+  );
+                              xmlelement                              
+----------------------------------------------------------------------
+ <root xmlns="http:/x.y/ns1" att="val"><foo xmlns="">bar</foo></root>
+(1 row)
+
+-- empty root xmlelement containing one xmlattribute, one xmlnamespace,
+-- three child nodes generated by xmlforest and xmltext, one xmlcomment,
+-- and a text node generated by xmlconcat.
+SELECT
+  xmlelement(NAME "root",
+    xmlattributes(73 AS att),
+    xmlnamespaces('http:/x.y/ns1' AS ns),
+    xmlforest(true AS "ns:x", 42 AS "ns:y", xmltext('<&>') AS "ns:z"),
+    xmlcomment(':)'),
+    xmlconcat('foo', 'bar')
+  );
+                                                        xmlelement                                                        
+--------------------------------------------------------------------------------------------------------------------------
+ <root xmlns:ns="http:/x.y/ns1" att="73"><ns:x>true</ns:x><ns:y>42</ns:y><ns:z>&lt;&amp;&gt;</ns:z><!--:)-->foobar</root>
+(1 row)
+
+\set VERBOSITY terse
+-- duplicate xmlnamespace entry (ns1)
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1, 'http:/x.y/ns1' AS ns1));
+ERROR:  XML namespace name "ns1" appears more than once at character 70
+-- invalid xmlnamespace syntax
+SELECT xmlelement(NAME "root", xmlnamespaces('invalid'));
+ERROR:  syntax error at or near ")" at character 55
+-- multiple DEFAULT xmlnamespaces
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http:/x.y/ns1', DEFAULT 'http:/x.y/ns2'));
+ERROR:  XML elements can have only a single [NO] DEFAULT namespace at character 71
+-- multiple NO DEFAULT xmlnamespaces
+SELECT xmlelement(NAME "root", xmlnamespaces(NO DEFAULT, NO DEFAULT));
+ERROR:  XML elements can have only a single [NO] DEFAULT namespace at character 58
+-- invalid xmlnamespace prefix (xmlns)
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS xmlns));
+ERROR:  invalid XML namespace prefix "xmlns" at character 46
+-- invalid xmlnamespace prefix (xml)
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS xml));
+ERROR:  invalid XML namespace prefix "xml" at character 46
+-- duplicate xmlnamespace calls
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1), xmlnamespaces('http:/x.y/ns2' AS ns2));
+ERROR:  duplicate XMLNAMESACES specified at character 71
+\set VERBOSITY default
+-- invalid xmlnamespaces URIs
+SELECT xmlelement(NAME "root", xmlnamespaces('http://www.w3.org/2000/xmlns/' AS bar));
+ERROR:  invalid XML namespace URI "http://www.w3.org/2000/xmlns/";
+DETAIL:  this URI is already bounded to standard a namespace prefix
+SELECT xmlelement(NAME "root", xmlnamespaces('http://www.w3.org/XML/1998/namespace' AS bar));
+ERROR:  invalid XML namespace URI "http://www.w3.org/XML/1998/namespace";
+DETAIL:  this URI is already bounded to standard a namespace prefix
+-- invalid DEFAULT xmlnamespace URIs
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http://www.w3.org/2000/xmlns/'));
+ERROR:  invalid XML namespace URI "http://www.w3.org/2000/xmlns/";
+DETAIL:  this URI is already bounded to standard a namespace prefix
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http://www.w3.org/XML/1998/namespace'));
+ERROR:  invalid XML namespace URI "http://www.w3.org/XML/1998/namespace";
+DETAIL:  this URI is already bounded to standard a namespace prefix
+-- empty xmlnamespace uri
+SELECT xmlelement(NAME "root", xmlnamespaces('' AS ns));
+ERROR:  invalid XML namespace URI for "ns"
+DETAIL:  a regular XML namespace cannot be a zero-length string
 SELECT xmlparse(content '');
  xmlparse 
 ----------
diff --git a/src/test/regress/expected/xml_1.out b/src/test/regress/expected/xml_1.out
index 7505a14077..d370826b4a 100644
--- a/src/test/regress/expected/xml_1.out
+++ b/src/test/regress/expected/xml_1.out
@@ -150,6 +150,178 @@ DETAIL:  This functionality requires the server to be built with libxml support.
 SELECT xmlelement(name foo, xmlattributes('<>&"''' as funny, xml 'b<a/>r' as funnier));
 ERROR:  unsupported XML feature
 DETAIL:  This functionality requires the server to be built with libxml support.
+-- DEFAULT NULL xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT NULL));
+ERROR:  unsupported XML feature
+DETAIL:  This functionality requires the server to be built with libxml support.
+-- DEFAULT xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http:/x.y/ns1'));
+ERROR:  unsupported XML feature
+DETAIL:  This functionality requires the server to be built with libxml support.
+-- DEFAULT numeric xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 42.73));
+ERROR:  unsupported XML feature
+DETAIL:  This functionality requires the server to be built with libxml support.
+-- DEFAULT empty xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT ''));
+ERROR:  unsupported XML feature
+DETAIL:  This functionality requires the server to be built with libxml support.
+-- DEFAULT empty xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(NO DEFAULT));
+ERROR:  unsupported XML feature
+DETAIL:  This functionality requires the server to be built with libxml support.
+-- Testing xmlnamespace with subqueries
+SELECT
+  xmlelement(NAME root, xmlnamespaces(DEFAULT 'ns'),
+    (SELECT xmlelement(NAME child1, xmlnamespaces(NO DEFAULT))));
+ERROR:  unsupported XML feature
+DETAIL:  This functionality requires the server to be built with libxml support.
+-- Testing xmlnamespace url from ColumnRef
+CREATE TABLE xmlns (url text);
+INSERT INTO xmlns VALUES ('http:/x.y/ns1');
+SELECT
+  xmlserialize(DOCUMENT
+  xmlelement(NAME root, xmlnamespaces(DEFAULT 'foo', url AS ns),
+    xmlelement(NAME root,
+      xmlelement(NAME child2, xmlnamespaces(url AS ns, NO DEFAULT))))
+  AS text INDENT)
+FROM xmlns;
+ERROR:  unsupported XML feature
+DETAIL:  This functionality requires the server to be built with libxml support.
+-- NULL xmlnamespace uri
+SELECT xmlelement(NAME "root", xmlnamespaces(NULL AS ns));
+ERROR:  unsupported XML feature
+DETAIL:  This functionality requires the server to be built with libxml support.
+-- empty xmlelement containing one namespace
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1));
+ERROR:  unsupported XML feature
+DETAIL:  This functionality requires the server to be built with libxml support.
+-- empty xmlelement with DEFAULT and regular xmlnamespaces
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http:/x.y/ns1', 'http:/x.y/ns2' AS ns2));
+ERROR:  unsupported XML feature
+DETAIL:  This functionality requires the server to be built with libxml support.
+-- xmlelement containing a namespace and a text node
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1), 'text node');
+ERROR:  unsupported XML feature
+DETAIL:  This functionality requires the server to be built with libxml support.
+-- empty xmlelement containing a) xmlnamespace and b) xmlattribute
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1), xmlattributes('val' AS att));
+ERROR:  unsupported XML feature
+DETAIL:  This functionality requires the server to be built with libxml support.
+-- empty xmlelement containing a) xmlattribute and b) xmlnamespace
+SELECT xmlelement(NAME "root", xmlattributes('val' AS att), xmlnamespaces('http:/x.y/ns1' AS ns1));
+ERROR:  unsupported XML feature
+DETAIL:  This functionality requires the server to be built with libxml support.
+-- empty xmlelement containing two xmlnamespaces
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1, 'http:/x.y/ns2' AS ns2));
+ERROR:  unsupported XML feature
+DETAIL:  This functionality requires the server to be built with libxml support.
+-- empty xmlelement containing two xmlnamespaces and one xmlattribute
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1, 'http:/x.y/ns2' AS ns2), xmlattributes('val' AS att));
+ERROR:  unsupported XML feature
+DETAIL:  This functionality requires the server to be built with libxml support.
+-- xmlelement containing two xmlnamespaces, one xmlattribute,
+-- and a text node.
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1, 'http:/x.y/ns2' AS ns2), xmlattributes('val' AS att), 'text node');
+ERROR:  unsupported XML feature
+DETAIL:  This functionality requires the server to be built with libxml support.
+-- empty root xmlelement containing one xmlnamespace, one xmlattribute,
+-- and one xmlelement child (ns1:foo).
+-- empty xmlelement child "ns1:foo" containing one xmlnamespace and one
+-- xmlelement child (ns2:bar).
+-- xmlelement child "ns2:bar" containing a text node.
+SELECT
+  xmlelement(NAME "root",
+    xmlnamespaces('http:/x.y/ns1' AS ns1),
+    xmlattributes('val' AS att),
+    xmlelement(NAME "ns1:foo",
+      xmlnamespaces('http:/x.y/ns2' AS ns2),
+      xmlelement(NAME "ns2:bar", 'text node'))
+  );
+ERROR:  unsupported XML feature
+DETAIL:  This functionality requires the server to be built with libxml support.
+-- empty root xmlelement containing one xmlnamespace, one xmlattribute,
+-- and one xmlelement child (ns1:foo).
+-- xmlelement child "ns1:foo" containing one xmlnamespace, one xmlelement
+-- child (ns2:bar), and a text node.
+-- xmlelement child "ns2:bar" containing a text node.
+SELECT
+  xmlelement(NAME "root",
+    xmlnamespaces('http:/x.y/ns1' AS ns1),
+    xmlattributes('val' AS att),
+    xmlelement(NAME "ns1:foo",
+      xmlnamespaces('http:/x.y/ns2' AS ns2),
+      xmlelement(NAME "ns2:bar", 'text node'),
+      'mixed content')
+  );
+ERROR:  unsupported XML feature
+DETAIL:  This functionality requires the server to be built with libxml support.
+-- empty root xmlelement containing one DEFAULT xmlnamespace, one xmlattribute,
+-- and one xmlelement child (foo).
+-- xmlelement child "foo" containing one NO DEFAULT xmlnamespace and a text node.
+SELECT
+  xmlelement(NAME "root",
+    xmlnamespaces(DEFAULT 'http:/x.y/ns1'),
+    xmlattributes('val' AS att),
+    xmlelement(NAME "foo",
+      xmlnamespaces(NO DEFAULT),'bar')
+  );
+ERROR:  unsupported XML feature
+DETAIL:  This functionality requires the server to be built with libxml support.
+-- empty root xmlelement containing one xmlattribute, one xmlnamespace,
+-- three child nodes generated by xmlforest and xmltext, one xmlcomment,
+-- and a text node generated by xmlconcat.
+SELECT
+  xmlelement(NAME "root",
+    xmlattributes(73 AS att),
+    xmlnamespaces('http:/x.y/ns1' AS ns),
+    xmlforest(true AS "ns:x", 42 AS "ns:y", xmltext('<&>') AS "ns:z"),
+    xmlcomment(':)'),
+    xmlconcat('foo', 'bar')
+  );
+ERROR:  unsupported XML feature
+DETAIL:  This functionality requires the server to be built with libxml support.
+\set VERBOSITY terse
+-- duplicate xmlnamespace entry (ns1)
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1, 'http:/x.y/ns1' AS ns1));
+ERROR:  unsupported XML feature
+-- invalid xmlnamespace syntax
+SELECT xmlelement(NAME "root", xmlnamespaces('invalid'));
+ERROR:  syntax error at or near ")" at character 55
+-- multiple DEFAULT xmlnamespaces
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http:/x.y/ns1', DEFAULT 'http:/x.y/ns2'));
+ERROR:  unsupported XML feature
+-- multiple NO DEFAULT xmlnamespaces
+SELECT xmlelement(NAME "root", xmlnamespaces(NO DEFAULT, NO DEFAULT));
+ERROR:  unsupported XML feature
+-- invalid xmlnamespace prefix (xmlns)
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS xmlns));
+ERROR:  unsupported XML feature
+-- invalid xmlnamespace prefix (xml)
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS xml));
+ERROR:  unsupported XML feature
+-- duplicate xmlnamespace calls
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1), xmlnamespaces('http:/x.y/ns2' AS ns2));
+ERROR:  duplicate XMLNAMESACES specified at character 71
+\set VERBOSITY default
+-- invalid xmlnamespaces URIs
+SELECT xmlelement(NAME "root", xmlnamespaces('http://www.w3.org/2000/xmlns/' AS bar));
+ERROR:  unsupported XML feature
+DETAIL:  This functionality requires the server to be built with libxml support.
+SELECT xmlelement(NAME "root", xmlnamespaces('http://www.w3.org/XML/1998/namespace' AS bar));
+ERROR:  unsupported XML feature
+DETAIL:  This functionality requires the server to be built with libxml support.
+-- invalid DEFAULT xmlnamespace URIs
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http://www.w3.org/2000/xmlns/'));
+ERROR:  unsupported XML feature
+DETAIL:  This functionality requires the server to be built with libxml support.
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http://www.w3.org/XML/1998/namespace'));
+ERROR:  unsupported XML feature
+DETAIL:  This functionality requires the server to be built with libxml support.
+-- empty xmlnamespace uri
+SELECT xmlelement(NAME "root", xmlnamespaces('' AS ns));
+ERROR:  unsupported XML feature
+DETAIL:  This functionality requires the server to be built with libxml support.
 SELECT xmlparse(content '');
 ERROR:  unsupported XML feature
 DETAIL:  This functionality requires the server to be built with libxml support.
diff --git a/src/test/regress/expected/xml_2.out b/src/test/regress/expected/xml_2.out
index c07ed2b269..21c3e79120 100644
--- a/src/test/regress/expected/xml_2.out
+++ b/src/test/regress/expected/xml_2.out
@@ -221,6 +221,242 @@ SELECT xmlelement(name foo, xmlattributes('<>&"''' as funny, xml 'b<a/>r' as fun
  <foo funny="&lt;&gt;&amp;&quot;'" funnier="b&lt;a/&gt;r"/>
 (1 row)
 
+-- DEFAULT NULL xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT NULL));
+ xmlelement 
+------------
+ <root/>
+(1 row)
+
+-- DEFAULT xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http:/x.y/ns1'));
+          xmlelement           
+-------------------------------
+ <root xmlns="http:/x.y/ns1"/>
+(1 row)
+
+-- DEFAULT numeric xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 42.73));
+      xmlelement       
+-----------------------
+ <root xmlns="42.73"/>
+(1 row)
+
+-- DEFAULT empty xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT ''));
+    xmlelement    
+------------------
+ <root xmlns=""/>
+(1 row)
+
+-- DEFAULT empty xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(NO DEFAULT));
+    xmlelement    
+------------------
+ <root xmlns=""/>
+(1 row)
+
+-- Testing xmlnamespace with subqueries
+SELECT
+  xmlelement(NAME root, xmlnamespaces(DEFAULT 'ns'),
+    (SELECT xmlelement(NAME child1, xmlnamespaces(NO DEFAULT))));
+                 xmlelement                 
+--------------------------------------------
+ <root xmlns="ns"><child1 xmlns=""/></root>
+(1 row)
+
+-- Testing xmlnamespace url from ColumnRef
+CREATE TABLE xmlns (url text);
+INSERT INTO xmlns VALUES ('http:/x.y/ns1');
+SELECT
+  xmlserialize(DOCUMENT
+  xmlelement(NAME root, xmlnamespaces(DEFAULT 'foo', url AS ns),
+    xmlelement(NAME root,
+      xmlelement(NAME child2, xmlnamespaces(url AS ns, NO DEFAULT))))
+  AS text INDENT)
+FROM xmlns;
+                  xmlserialize                   
+-------------------------------------------------
+ <root xmlns="foo" xmlns:ns="http:/x.y/ns1">    +
+   <root>                                       +
+     <child2 xmlns:ns="http:/x.y/ns1" xmlns=""/>+
+   </root>                                      +
+ </root>
+(1 row)
+
+-- NULL xmlnamespace uri
+SELECT xmlelement(NAME "root", xmlnamespaces(NULL AS ns));
+ xmlelement 
+------------
+ <root/>
+(1 row)
+
+-- empty xmlelement containing one namespace
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1));
+            xmlelement             
+-----------------------------------
+ <root xmlns:ns1="http:/x.y/ns1"/>
+(1 row)
+
+-- empty xmlelement with DEFAULT and regular xmlnamespaces
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http:/x.y/ns1', 'http:/x.y/ns2' AS ns2));
+                       xmlelement                        
+---------------------------------------------------------
+ <root xmlns="http:/x.y/ns1" xmlns:ns2="http:/x.y/ns2"/>
+(1 row)
+
+-- xmlelement containing a namespace and a text node
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1), 'text node');
+                    xmlelement                    
+--------------------------------------------------
+ <root xmlns:ns1="http:/x.y/ns1">text node</root>
+(1 row)
+
+-- empty xmlelement containing a) xmlnamespace and b) xmlattribute
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1), xmlattributes('val' AS att));
+                 xmlelement                  
+---------------------------------------------
+ <root xmlns:ns1="http:/x.y/ns1" att="val"/>
+(1 row)
+
+-- empty xmlelement containing a) xmlattribute and b) xmlnamespace
+SELECT xmlelement(NAME "root", xmlattributes('val' AS att), xmlnamespaces('http:/x.y/ns1' AS ns1));
+                 xmlelement                  
+---------------------------------------------
+ <root xmlns:ns1="http:/x.y/ns1" att="val"/>
+(1 row)
+
+-- empty xmlelement containing two xmlnamespaces
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1, 'http:/x.y/ns2' AS ns2));
+                         xmlelement                          
+-------------------------------------------------------------
+ <root xmlns:ns1="http:/x.y/ns1" xmlns:ns2="http:/x.y/ns2"/>
+(1 row)
+
+-- empty xmlelement containing two xmlnamespaces and one xmlattribute
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1, 'http:/x.y/ns2' AS ns2), xmlattributes('val' AS att));
+                              xmlelement                               
+-----------------------------------------------------------------------
+ <root xmlns:ns1="http:/x.y/ns1" xmlns:ns2="http:/x.y/ns2" att="val"/>
+(1 row)
+
+-- xmlelement containing two xmlnamespaces, one xmlattribute,
+-- and a text node.
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1, 'http:/x.y/ns2' AS ns2), xmlattributes('val' AS att), 'text node');
+                                      xmlelement                                      
+--------------------------------------------------------------------------------------
+ <root xmlns:ns1="http:/x.y/ns1" xmlns:ns2="http:/x.y/ns2" att="val">text node</root>
+(1 row)
+
+-- empty root xmlelement containing one xmlnamespace, one xmlattribute,
+-- and one xmlelement child (ns1:foo).
+-- empty xmlelement child "ns1:foo" containing one xmlnamespace and one
+-- xmlelement child (ns2:bar).
+-- xmlelement child "ns2:bar" containing a text node.
+SELECT
+  xmlelement(NAME "root",
+    xmlnamespaces('http:/x.y/ns1' AS ns1),
+    xmlattributes('val' AS att),
+    xmlelement(NAME "ns1:foo",
+      xmlnamespaces('http:/x.y/ns2' AS ns2),
+      xmlelement(NAME "ns2:bar", 'text node'))
+  );
+                                                         xmlelement                                                         
+----------------------------------------------------------------------------------------------------------------------------
+ <root xmlns:ns1="http:/x.y/ns1" att="val"><ns1:foo xmlns:ns2="http:/x.y/ns2"><ns2:bar>text node</ns2:bar></ns1:foo></root>
+(1 row)
+
+-- empty root xmlelement containing one xmlnamespace, one xmlattribute,
+-- and one xmlelement child (ns1:foo).
+-- xmlelement child "ns1:foo" containing one xmlnamespace, one xmlelement
+-- child (ns2:bar), and a text node.
+-- xmlelement child "ns2:bar" containing a text node.
+SELECT
+  xmlelement(NAME "root",
+    xmlnamespaces('http:/x.y/ns1' AS ns1),
+    xmlattributes('val' AS att),
+    xmlelement(NAME "ns1:foo",
+      xmlnamespaces('http:/x.y/ns2' AS ns2),
+      xmlelement(NAME "ns2:bar", 'text node'),
+      'mixed content')
+  );
+                                                               xmlelement                                                                
+-----------------------------------------------------------------------------------------------------------------------------------------
+ <root xmlns:ns1="http:/x.y/ns1" att="val"><ns1:foo xmlns:ns2="http:/x.y/ns2"><ns2:bar>text node</ns2:bar>mixed content</ns1:foo></root>
+(1 row)
+
+-- empty root xmlelement containing one DEFAULT xmlnamespace, one xmlattribute,
+-- and one xmlelement child (foo).
+-- xmlelement child "foo" containing one NO DEFAULT xmlnamespace and a text node.
+SELECT
+  xmlelement(NAME "root",
+    xmlnamespaces(DEFAULT 'http:/x.y/ns1'),
+    xmlattributes('val' AS att),
+    xmlelement(NAME "foo",
+      xmlnamespaces(NO DEFAULT),'bar')
+  );
+                              xmlelement                              
+----------------------------------------------------------------------
+ <root xmlns="http:/x.y/ns1" att="val"><foo xmlns="">bar</foo></root>
+(1 row)
+
+-- empty root xmlelement containing one xmlattribute, one xmlnamespace,
+-- three child nodes generated by xmlforest and xmltext, one xmlcomment,
+-- and a text node generated by xmlconcat.
+SELECT
+  xmlelement(NAME "root",
+    xmlattributes(73 AS att),
+    xmlnamespaces('http:/x.y/ns1' AS ns),
+    xmlforest(true AS "ns:x", 42 AS "ns:y", xmltext('<&>') AS "ns:z"),
+    xmlcomment(':)'),
+    xmlconcat('foo', 'bar')
+  );
+                                                        xmlelement                                                        
+--------------------------------------------------------------------------------------------------------------------------
+ <root xmlns:ns="http:/x.y/ns1" att="73"><ns:x>true</ns:x><ns:y>42</ns:y><ns:z>&lt;&amp;&gt;</ns:z><!--:)-->foobar</root>
+(1 row)
+
+\set VERBOSITY terse
+-- duplicate xmlnamespace entry (ns1)
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1, 'http:/x.y/ns1' AS ns1));
+ERROR:  XML namespace name "ns1" appears more than once at character 70
+-- invalid xmlnamespace syntax
+SELECT xmlelement(NAME "root", xmlnamespaces('invalid'));
+ERROR:  syntax error at or near ")" at character 55
+-- multiple DEFAULT xmlnamespaces
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http:/x.y/ns1', DEFAULT 'http:/x.y/ns2'));
+ERROR:  XML elements can have only a single [NO] DEFAULT namespace at character 71
+-- multiple NO DEFAULT xmlnamespaces
+SELECT xmlelement(NAME "root", xmlnamespaces(NO DEFAULT, NO DEFAULT));
+ERROR:  XML elements can have only a single [NO] DEFAULT namespace at character 58
+-- invalid xmlnamespace prefix (xmlns)
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS xmlns));
+ERROR:  invalid XML namespace prefix "xmlns" at character 46
+-- invalid xmlnamespace prefix (xml)
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS xml));
+ERROR:  invalid XML namespace prefix "xml" at character 46
+-- duplicate xmlnamespace calls
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1), xmlnamespaces('http:/x.y/ns2' AS ns2));
+ERROR:  duplicate XMLNAMESACES specified at character 71
+\set VERBOSITY default
+-- invalid xmlnamespaces URIs
+SELECT xmlelement(NAME "root", xmlnamespaces('http://www.w3.org/2000/xmlns/' AS bar));
+ERROR:  invalid XML namespace URI "http://www.w3.org/2000/xmlns/";
+DETAIL:  this URI is already bounded to standard a namespace prefix
+SELECT xmlelement(NAME "root", xmlnamespaces('http://www.w3.org/XML/1998/namespace' AS bar));
+ERROR:  invalid XML namespace URI "http://www.w3.org/XML/1998/namespace";
+DETAIL:  this URI is already bounded to standard a namespace prefix
+-- invalid DEFAULT xmlnamespace URIs
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http://www.w3.org/2000/xmlns/'));
+ERROR:  invalid XML namespace URI "http://www.w3.org/2000/xmlns/";
+DETAIL:  this URI is already bounded to standard a namespace prefix
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http://www.w3.org/XML/1998/namespace'));
+ERROR:  invalid XML namespace URI "http://www.w3.org/XML/1998/namespace";
+DETAIL:  this URI is already bounded to standard a namespace prefix
+-- empty xmlnamespace uri
+SELECT xmlelement(NAME "root", xmlnamespaces('' AS ns));
+ERROR:  invalid XML namespace URI for "ns"
+DETAIL:  a regular XML namespace cannot be a zero-length string
 SELECT xmlparse(content '');
  xmlparse 
 ----------
diff --git a/src/test/regress/sql/xml.sql b/src/test/regress/sql/xml.sql
index bac0388ac1..813027ddc2 100644
--- a/src/test/regress/sql/xml.sql
+++ b/src/test/regress/sql/xml.sql
@@ -66,6 +66,122 @@ SELECT xmlelement(name foo, xmlattributes('2009-04-09 00:24:37'::timestamp as ba
 SELECT xmlelement(name foo, xmlattributes('infinity'::timestamp as bar));
 SELECT xmlelement(name foo, xmlattributes('<>&"''' as funny, xml 'b<a/>r' as funnier));
 
+-- DEFAULT NULL xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT NULL));
+-- DEFAULT xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http:/x.y/ns1'));
+-- DEFAULT numeric xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 42.73));
+-- DEFAULT empty xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT ''));
+-- DEFAULT empty xmlnamespace
+SELECT xmlelement(NAME "root", xmlnamespaces(NO DEFAULT));
+-- Testing xmlnamespace with subqueries
+SELECT
+  xmlelement(NAME root, xmlnamespaces(DEFAULT 'ns'),
+    (SELECT xmlelement(NAME child1, xmlnamespaces(NO DEFAULT))));
+-- Testing xmlnamespace url from ColumnRef
+CREATE TABLE xmlns (url text);
+INSERT INTO xmlns VALUES ('http:/x.y/ns1');
+SELECT
+  xmlserialize(DOCUMENT
+  xmlelement(NAME root, xmlnamespaces(DEFAULT 'foo', url AS ns),
+    xmlelement(NAME root,
+      xmlelement(NAME child2, xmlnamespaces(url AS ns, NO DEFAULT))))
+  AS text INDENT)
+FROM xmlns;
+-- NULL xmlnamespace uri
+SELECT xmlelement(NAME "root", xmlnamespaces(NULL AS ns));
+-- empty xmlelement containing one namespace
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1));
+-- empty xmlelement with DEFAULT and regular xmlnamespaces
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http:/x.y/ns1', 'http:/x.y/ns2' AS ns2));
+-- xmlelement containing a namespace and a text node
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1), 'text node');
+-- empty xmlelement containing a) xmlnamespace and b) xmlattribute
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1), xmlattributes('val' AS att));
+-- empty xmlelement containing a) xmlattribute and b) xmlnamespace
+SELECT xmlelement(NAME "root", xmlattributes('val' AS att), xmlnamespaces('http:/x.y/ns1' AS ns1));
+-- empty xmlelement containing two xmlnamespaces
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1, 'http:/x.y/ns2' AS ns2));
+-- empty xmlelement containing two xmlnamespaces and one xmlattribute
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1, 'http:/x.y/ns2' AS ns2), xmlattributes('val' AS att));
+-- xmlelement containing two xmlnamespaces, one xmlattribute,
+-- and a text node.
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1, 'http:/x.y/ns2' AS ns2), xmlattributes('val' AS att), 'text node');
+-- empty root xmlelement containing one xmlnamespace, one xmlattribute,
+-- and one xmlelement child (ns1:foo).
+-- empty xmlelement child "ns1:foo" containing one xmlnamespace and one
+-- xmlelement child (ns2:bar).
+-- xmlelement child "ns2:bar" containing a text node.
+SELECT
+  xmlelement(NAME "root",
+    xmlnamespaces('http:/x.y/ns1' AS ns1),
+    xmlattributes('val' AS att),
+    xmlelement(NAME "ns1:foo",
+      xmlnamespaces('http:/x.y/ns2' AS ns2),
+      xmlelement(NAME "ns2:bar", 'text node'))
+  );
+-- empty root xmlelement containing one xmlnamespace, one xmlattribute,
+-- and one xmlelement child (ns1:foo).
+-- xmlelement child "ns1:foo" containing one xmlnamespace, one xmlelement
+-- child (ns2:bar), and a text node.
+-- xmlelement child "ns2:bar" containing a text node.
+SELECT
+  xmlelement(NAME "root",
+    xmlnamespaces('http:/x.y/ns1' AS ns1),
+    xmlattributes('val' AS att),
+    xmlelement(NAME "ns1:foo",
+      xmlnamespaces('http:/x.y/ns2' AS ns2),
+      xmlelement(NAME "ns2:bar", 'text node'),
+      'mixed content')
+  );
+-- empty root xmlelement containing one DEFAULT xmlnamespace, one xmlattribute,
+-- and one xmlelement child (foo).
+-- xmlelement child "foo" containing one NO DEFAULT xmlnamespace and a text node.
+SELECT
+  xmlelement(NAME "root",
+    xmlnamespaces(DEFAULT 'http:/x.y/ns1'),
+    xmlattributes('val' AS att),
+    xmlelement(NAME "foo",
+      xmlnamespaces(NO DEFAULT),'bar')
+  );
+-- empty root xmlelement containing one xmlattribute, one xmlnamespace,
+-- three child nodes generated by xmlforest and xmltext, one xmlcomment,
+-- and a text node generated by xmlconcat.
+SELECT
+  xmlelement(NAME "root",
+    xmlattributes(73 AS att),
+    xmlnamespaces('http:/x.y/ns1' AS ns),
+    xmlforest(true AS "ns:x", 42 AS "ns:y", xmltext('<&>') AS "ns:z"),
+    xmlcomment(':)'),
+    xmlconcat('foo', 'bar')
+  );
+\set VERBOSITY terse
+-- duplicate xmlnamespace entry (ns1)
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1, 'http:/x.y/ns1' AS ns1));
+-- invalid xmlnamespace syntax
+SELECT xmlelement(NAME "root", xmlnamespaces('invalid'));
+-- multiple DEFAULT xmlnamespaces
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http:/x.y/ns1', DEFAULT 'http:/x.y/ns2'));
+-- multiple NO DEFAULT xmlnamespaces
+SELECT xmlelement(NAME "root", xmlnamespaces(NO DEFAULT, NO DEFAULT));
+-- invalid xmlnamespace prefix (xmlns)
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS xmlns));
+-- invalid xmlnamespace prefix (xml)
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS xml));
+-- duplicate xmlnamespace calls
+SELECT xmlelement(NAME "root", xmlnamespaces('http:/x.y/ns1' AS ns1), xmlnamespaces('http:/x.y/ns2' AS ns2));
+\set VERBOSITY default
+-- invalid xmlnamespaces URIs
+SELECT xmlelement(NAME "root", xmlnamespaces('http://www.w3.org/2000/xmlns/' AS bar));
+SELECT xmlelement(NAME "root", xmlnamespaces('http://www.w3.org/XML/1998/namespace' AS bar));
+-- invalid DEFAULT xmlnamespace URIs
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http://www.w3.org/2000/xmlns/'));
+SELECT xmlelement(NAME "root", xmlnamespaces(DEFAULT 'http://www.w3.org/XML/1998/namespace'));
+-- empty xmlnamespace uri
+SELECT xmlelement(NAME "root", xmlnamespaces('' AS ns));
+
 
 SELECT xmlparse(content '');
 SELECT xmlparse(content '  ');
-- 
2.34.1

Reply via email to