Accidentally left the VERBOSE settings out -- sorry!
Now it matches the approach used in a xpath test in xml.sql, xml.out,
xml_1.out and xml_2.out
-- Since different libxml versions emit slightly different
-- error messages, we suppress the DETAIL in this test.
\set VERBOSITY terse
SELECT xpath('/*', '<invalidns xmlns=''<''/>');
ERROR: could not parse XML document
\set VERBOSITY default
v11 now correctly sets xml_2.out.
Best, Jim
From 473aab0a0028cd4de515c6a3698a1cda1c987067 Mon Sep 17 00:00:00 2001
From: Jim Jones <jim.jo...@uni-muenster.de>
Date: Thu, 2 Feb 2023 21:27:16 +0100
Subject: [PATCH v11] Add pretty-printed XML output option
This small patch introduces a XML pretty print function.
It basically takes advantage of the indentation feature
of xmlDocDumpFormatMemory from libxml2 to format XML strings.
---
doc/src/sgml/func.sgml | 34 ++++++++++
src/backend/utils/adt/xml.c | 45 +++++++++++++
src/include/catalog/pg_proc.dat | 3 +
src/test/regress/expected/xml.out | 101 ++++++++++++++++++++++++++++
src/test/regress/expected/xml_1.out | 53 +++++++++++++++
src/test/regress/expected/xml_2.out | 101 ++++++++++++++++++++++++++++
src/test/regress/sql/xml.sql | 33 +++++++++
7 files changed, 370 insertions(+)
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index e09e289a43..a621192425 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -14861,6 +14861,40 @@ SELECT xmltable.*
]]></screen>
</para>
</sect3>
+
+ <sect3 id="functions-xml-xmlformat">
+ <title><literal>xmlformat</literal></title>
+
+ <indexterm>
+ <primary>xmlformat</primary>
+ </indexterm>
+
+<synopsis>
+<function>xmlformat</function> ( <type>xml</type> ) <returnvalue>xml</returnvalue>
+</synopsis>
+
+ <para>
+ Converts the given XML value to pretty-printed, indented text.
+ </para>
+
+ <para>
+ Example:
+ <screen><![CDATA[
+SELECT xmlformat('<foo id="x"><bar id="y"><var id="z">42</var></bar></foo>');
+ xmlformat
+--------------------------
+ <foo id="x">
+ <bar id="y">
+ <var id="z">42</var>
+ </bar>
+ </foo>
+
+(1 row)
+
+]]></screen>
+ </para>
+ </sect3>
+
</sect2>
<sect2 id="functions-xml-mapping">
diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c
index 079bcb1208..ec12707b5c 100644
--- a/src/backend/utils/adt/xml.c
+++ b/src/backend/utils/adt/xml.c
@@ -473,6 +473,51 @@ xmlBuffer_to_xmltype(xmlBufferPtr buf)
}
#endif
+Datum
+xmlformat(PG_FUNCTION_ARGS)
+{
+#ifdef USE_LIBXML
+
+ xmlDocPtr doc;
+ xmlChar *xmlbuf = NULL;
+ text *arg = PG_GETARG_TEXT_PP(0);
+ StringInfoData buf;
+ int nbytes;
+
+ doc = xml_parse(arg, XMLOPTION_DOCUMENT, false, GetDatabaseEncoding(), NULL);
+
+ if(!doc)
+ elog(ERROR, "could not parse the given XML document");
+
+ /**
+ * xmlDocDumpFormatMemory (
+ * xmlDocPtr doc, # the XML document
+ * xmlChar **xmlbuf, # the memory pointer
+ * int *nbytes, # the memory length
+ * int format # 1 = node indenting
+ *)
+ */
+
+ xmlDocDumpFormatMemory(doc, &xmlbuf, &nbytes, 1);
+
+ xmlFreeDoc(doc);
+
+ if(!nbytes)
+ elog(ERROR, "could not indent the given XML document");
+
+ initStringInfo(&buf);
+ appendStringInfoString(&buf, (const char *)xmlbuf);
+
+ xmlFree(xmlbuf);
+
+ PG_RETURN_XML_P(stringinfo_to_xmltype(&buf));
+
+#else
+ NO_XML_SUPPORT();
+return 0;
+#endif
+}
+
Datum
xmlcomment(PG_FUNCTION_ARGS)
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index c0f2a8a77c..54e8a6262a 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -8842,6 +8842,9 @@
{ oid => '3053', descr => 'determine if a string is well formed XML content',
proname => 'xml_is_well_formed_content', prorettype => 'bool',
proargtypes => 'text', prosrc => 'xml_is_well_formed_content' },
+{ oid => '4642', descr => 'Indented text from xml',
+ proname => 'xmlformat', prorettype => 'xml',
+ proargtypes => 'xml', prosrc => 'xmlformat' },
# json
{ oid => '321', descr => 'I/O',
diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out
index 3c357a9c7e..e45116aaa7 100644
--- a/src/test/regress/expected/xml.out
+++ b/src/test/regress/expected/xml.out
@@ -1599,3 +1599,104 @@ SELECT * FROM XMLTABLE('.' PASSING XMLELEMENT(NAME a) columns a varchar(20) PATH
<foo/> | <foo/>
(1 row)
+-- XML format: single line XML string
+SELECT xmlformat('<breakfast_menu id="42"><food type="discounter"><name>Belgian Waffles</name><price>$5.95</price><description>Two of our famous Belgian Waffles with plenty of real maple syrup</description><calories>650</calories></food></breakfast_menu>');
+ xmlformat
+--------------------------------------------------------------------------------------------------
+ <breakfast_menu id="42"> +
+ <food type="discounter"> +
+ <name>Belgian Waffles</name> +
+ <price>$5.95</price> +
+ <description>Two of our famous Belgian Waffles with plenty of real maple syrup</description>+
+ <calories>650</calories> +
+ </food> +
+ </breakfast_menu> +
+
+(1 row)
+
+-- XML format: XML string with space, tabs and newline between nodes
+SELECT xmlformat('<breakfast_menu id="73"> <food type="organic" class="fancy"> <name>Belgian Waffles</name> <price>$15.95</price>
+ <description>Two of our famous Belgian Waffles with plenty of real maple syrup</description>
+<calories>650</calories> </food> </breakfast_menu> ');
+ xmlformat
+--------------------------------------------------------------------------------------------------
+ <breakfast_menu id="73"> +
+ <food type="organic" class="fancy"> +
+ <name>Belgian Waffles</name> +
+ <price>$15.95</price> +
+ <description>Two of our famous Belgian Waffles with plenty of real maple syrup</description>+
+ <calories>650</calories> +
+ </food> +
+ </breakfast_menu> +
+
+(1 row)
+
+-- XML format: XML string with space, tabs and newline between nodes, using a namespace
+SELECT xmlformat('<meal:breakfast_menu xmlns:meal="http://fancycafe.im/meal/" id="73"> <meal:food type="organic" class="fancy"> <meal:name>Belgian Waffles</meal:name> <meal:price>$15.95</meal:price>
+ <meal:description>Two of our famous Belgian Waffles with plenty of real maple syrup</meal:description>
+<meal:calories>650</meal:calories> </meal:food></meal:breakfast_menu>');
+ xmlformat
+------------------------------------------------------------------------------------------------------------
+ <meal:breakfast_menu xmlns:meal="http://fancycafe.im/meal/" id="73"> +
+ <meal:food type="organic" class="fancy"> +
+ <meal:name>Belgian Waffles</meal:name> +
+ <meal:price>$15.95</meal:price> +
+ <meal:description>Two of our famous Belgian Waffles with plenty of real maple syrup</meal:description>+
+ <meal:calories>650</meal:calories> +
+ </meal:food> +
+ </meal:breakfast_menu> +
+
+(1 row)
+
+-- XML format: XML string with space, tabs and newline between nodes, using multiple namespaces and a comment
+SELECT xmlformat('<meal:breakfast_menu xmlns:meal="http://fancycafe.im/meal/" xmlns:desc="http://fancycafe.mn/meal/" id="73"> <meal:food type="organic" class="fancy"> <meal:name>Belgian Waffles</meal:name> <!-- eat this --> <meal:price>$15.95</meal:price>
+ <desc:description>Two of our famous Belgian Waffles with plenty of real maple syrup</desc:description>
+<meal:calories>650</meal:calories> </meal:food></meal:breakfast_menu>');
+ xmlformat
+-------------------------------------------------------------------------------------------------------------
+ <meal:breakfast_menu xmlns:meal="http://fancycafe.im/meal/" xmlns:desc="http://fancycafe.mn/meal/" id="73">+
+ <meal:food type="organic" class="fancy"> +
+ <meal:name>Belgian Waffles</meal:name> +
+ <!-- eat this --> +
+ <meal:price>$15.95</meal:price> +
+ <desc:description>Two of our famous Belgian Waffles with plenty of real maple syrup</desc:description> +
+ <meal:calories>650</meal:calories> +
+ </meal:food> +
+ </meal:breakfast_menu> +
+
+(1 row)
+
+-- XML format: XML string with space, tabs and newline between nodes, using multiple namespaces and CDATA
+SELECT xmlformat('<meal:breakfast_menu xmlns:meal="http://fancycafe.im/meal/" xmlns:desc="http://fancycafe.mn/meal/" id="73"> <meal:food type="organic" class="fancy"> <meal:name>Belgian Waffles</meal:name> <meal:price>$15.95</meal:price>
+ <desc:description>Two of our famous Belgian Waffles with plenty of real maple syrup</desc:description>
+<meal:calories><c><![CDATA[<unknown> &"<>!<a>foo</a>]]></c></meal:calories> </meal:food></meal:breakfast_menu>');
+ xmlformat
+-------------------------------------------------------------------------------------------------------------
+ <meal:breakfast_menu xmlns:meal="http://fancycafe.im/meal/" xmlns:desc="http://fancycafe.mn/meal/" id="73">+
+ <meal:food type="organic" class="fancy"> +
+ <meal:name>Belgian Waffles</meal:name> +
+ <meal:price>$15.95</meal:price> +
+ <desc:description>Two of our famous Belgian Waffles with plenty of real maple syrup</desc:description> +
+ <meal:calories> +
+ <c><![CDATA[<unknown> &"<>!<a>foo</a>]]></c> +
+ </meal:calories> +
+ </meal:food> +
+ </meal:breakfast_menu> +
+
+(1 row)
+
+-- XML format: NULL parameter
+SELECT xmlformat(NULL);
+ xmlformat
+-----------
+
+(1 row)
+
+\set VERBOSITY terse
+-- XML format: invalid string (whitespaces)
+SELECT xmlformat(' ');
+ERROR: invalid XML document
+-- XML format: empty string
+SELECT xmlformat('');
+ERROR: invalid XML document
+\set VERBOSITY default
diff --git a/src/test/regress/expected/xml_1.out b/src/test/regress/expected/xml_1.out
index 378b412db0..dc3c241a3a 100644
--- a/src/test/regress/expected/xml_1.out
+++ b/src/test/regress/expected/xml_1.out
@@ -1268,3 +1268,56 @@ DETAIL: This functionality requires the server to be built with libxml support.
SELECT * FROM XMLTABLE('.' PASSING XMLELEMENT(NAME a) columns a varchar(20) PATH '"<foo/>"', b xml PATH '"<foo/>"');
ERROR: unsupported XML feature
DETAIL: This functionality requires the server to be built with libxml support.
+-- XML format: single line XML string
+SELECT xmlformat('<breakfast_menu id="42"><food type="discounter"><name>Belgian Waffles</name><price>$5.95</price><description>Two of our famous Belgian Waffles with plenty of real maple syrup</description><calories>650</calories></food></breakfast_menu>');
+ERROR: unsupported XML feature
+LINE 1: SELECT xmlformat('<breakfast_menu id="42"><food type="discou...
+ ^
+DETAIL: This functionality requires the server to be built with libxml support.
+-- XML format: XML string with space, tabs and newline between nodes
+SELECT xmlformat('<breakfast_menu id="73"> <food type="organic" class="fancy"> <name>Belgian Waffles</name> <price>$15.95</price>
+ <description>Two of our famous Belgian Waffles with plenty of real maple syrup</description>
+<calories>650</calories> </food> </breakfast_menu> ');
+ERROR: unsupported XML feature
+LINE 1: SELECT xmlformat('<breakfast_menu id="73"> <food type="organ...
+ ^
+DETAIL: This functionality requires the server to be built with libxml support.
+-- XML format: XML string with space, tabs and newline between nodes, using a namespace
+SELECT xmlformat('<meal:breakfast_menu xmlns:meal="http://fancycafe.im/meal/" id="73"> <meal:food type="organic" class="fancy"> <meal:name>Belgian Waffles</meal:name> <meal:price>$15.95</meal:price>
+ <meal:description>Two of our famous Belgian Waffles with plenty of real maple syrup</meal:description>
+<meal:calories>650</meal:calories> </meal:food></meal:breakfast_menu>');
+ERROR: unsupported XML feature
+LINE 1: SELECT xmlformat('<meal:breakfast_menu xmlns:meal="http://fa...
+ ^
+DETAIL: This functionality requires the server to be built with libxml support.
+-- XML format: XML string with space, tabs and newline between nodes, using multiple namespaces and a comment
+SELECT xmlformat('<meal:breakfast_menu xmlns:meal="http://fancycafe.im/meal/" xmlns:desc="http://fancycafe.mn/meal/" id="73"> <meal:food type="organic" class="fancy"> <meal:name>Belgian Waffles</meal:name> <!-- eat this --> <meal:price>$15.95</meal:price>
+ <desc:description>Two of our famous Belgian Waffles with plenty of real maple syrup</desc:description>
+<meal:calories>650</meal:calories> </meal:food></meal:breakfast_menu>');
+ERROR: unsupported XML feature
+LINE 1: SELECT xmlformat('<meal:breakfast_menu xmlns:meal="http://fa...
+ ^
+DETAIL: This functionality requires the server to be built with libxml support.
+-- XML format: XML string with space, tabs and newline between nodes, using multiple namespaces and CDATA
+SELECT xmlformat('<meal:breakfast_menu xmlns:meal="http://fancycafe.im/meal/" xmlns:desc="http://fancycafe.mn/meal/" id="73"> <meal:food type="organic" class="fancy"> <meal:name>Belgian Waffles</meal:name> <meal:price>$15.95</meal:price>
+ <desc:description>Two of our famous Belgian Waffles with plenty of real maple syrup</desc:description>
+<meal:calories><c><![CDATA[<unknown> &"<>!<a>foo</a>]]></c></meal:calories> </meal:food></meal:breakfast_menu>');
+ERROR: unsupported XML feature
+LINE 1: SELECT xmlformat('<meal:breakfast_menu xmlns:meal="http://fa...
+ ^
+DETAIL: This functionality requires the server to be built with libxml support.
+-- XML format: NULL parameter
+SELECT xmlformat(NULL);
+ xmlformat
+-----------
+
+(1 row)
+
+\set VERBOSITY terse
+-- XML format: invalid string (whitespaces)
+SELECT xmlformat(' ');
+ERROR: unsupported XML feature at character 18
+-- XML format: empty string
+SELECT xmlformat('');
+ERROR: unsupported XML feature at character 18
+\set VERBOSITY default
diff --git a/src/test/regress/expected/xml_2.out b/src/test/regress/expected/xml_2.out
index 42055c5003..c04a57fe6d 100644
--- a/src/test/regress/expected/xml_2.out
+++ b/src/test/regress/expected/xml_2.out
@@ -1579,3 +1579,104 @@ SELECT * FROM XMLTABLE('.' PASSING XMLELEMENT(NAME a) columns a varchar(20) PATH
<foo/> | <foo/>
(1 row)
+-- XML format: single line XML string
+SELECT xmlformat('<breakfast_menu id="42"><food type="discounter"><name>Belgian Waffles</name><price>$5.95</price><description>Two of our famous Belgian Waffles with plenty of real maple syrup</description><calories>650</calories></food></breakfast_menu>');
+ xmlformat
+--------------------------------------------------------------------------------------------------
+ <breakfast_menu id="42"> +
+ <food type="discounter"> +
+ <name>Belgian Waffles</name> +
+ <price>$5.95</price> +
+ <description>Two of our famous Belgian Waffles with plenty of real maple syrup</description>+
+ <calories>650</calories> +
+ </food> +
+ </breakfast_menu> +
+
+(1 row)
+
+-- XML format: XML string with space, tabs and newline between nodes
+SELECT xmlformat('<breakfast_menu id="73"> <food type="organic" class="fancy"> <name>Belgian Waffles</name> <price>$15.95</price>
+ <description>Two of our famous Belgian Waffles with plenty of real maple syrup</description>
+<calories>650</calories> </food> </breakfast_menu> ');
+ xmlformat
+--------------------------------------------------------------------------------------------------
+ <breakfast_menu id="73"> +
+ <food type="organic" class="fancy"> +
+ <name>Belgian Waffles</name> +
+ <price>$15.95</price> +
+ <description>Two of our famous Belgian Waffles with plenty of real maple syrup</description>+
+ <calories>650</calories> +
+ </food> +
+ </breakfast_menu> +
+
+(1 row)
+
+-- XML format: XML string with space, tabs and newline between nodes, using a namespace
+SELECT xmlformat('<meal:breakfast_menu xmlns:meal="http://fancycafe.im/meal/" id="73"> <meal:food type="organic" class="fancy"> <meal:name>Belgian Waffles</meal:name> <meal:price>$15.95</meal:price>
+ <meal:description>Two of our famous Belgian Waffles with plenty of real maple syrup</meal:description>
+<meal:calories>650</meal:calories> </meal:food></meal:breakfast_menu>');
+ xmlformat
+------------------------------------------------------------------------------------------------------------
+ <meal:breakfast_menu xmlns:meal="http://fancycafe.im/meal/" id="73"> +
+ <meal:food type="organic" class="fancy"> +
+ <meal:name>Belgian Waffles</meal:name> +
+ <meal:price>$15.95</meal:price> +
+ <meal:description>Two of our famous Belgian Waffles with plenty of real maple syrup</meal:description>+
+ <meal:calories>650</meal:calories> +
+ </meal:food> +
+ </meal:breakfast_menu> +
+
+(1 row)
+
+-- XML format: XML string with space, tabs and newline between nodes, using multiple namespaces and a comment
+SELECT xmlformat('<meal:breakfast_menu xmlns:meal="http://fancycafe.im/meal/" xmlns:desc="http://fancycafe.mn/meal/" id="73"> <meal:food type="organic" class="fancy"> <meal:name>Belgian Waffles</meal:name> <!-- eat this --> <meal:price>$15.95</meal:price>
+ <desc:description>Two of our famous Belgian Waffles with plenty of real maple syrup</desc:description>
+<meal:calories>650</meal:calories> </meal:food></meal:breakfast_menu>');
+ xmlformat
+-------------------------------------------------------------------------------------------------------------
+ <meal:breakfast_menu xmlns:meal="http://fancycafe.im/meal/" xmlns:desc="http://fancycafe.mn/meal/" id="73">+
+ <meal:food type="organic" class="fancy"> +
+ <meal:name>Belgian Waffles</meal:name> +
+ <!-- eat this --> +
+ <meal:price>$15.95</meal:price> +
+ <desc:description>Two of our famous Belgian Waffles with plenty of real maple syrup</desc:description> +
+ <meal:calories>650</meal:calories> +
+ </meal:food> +
+ </meal:breakfast_menu> +
+
+(1 row)
+
+-- XML format: XML string with space, tabs and newline between nodes, using multiple namespaces and CDATA
+SELECT xmlformat('<meal:breakfast_menu xmlns:meal="http://fancycafe.im/meal/" xmlns:desc="http://fancycafe.mn/meal/" id="73"> <meal:food type="organic" class="fancy"> <meal:name>Belgian Waffles</meal:name> <meal:price>$15.95</meal:price>
+ <desc:description>Two of our famous Belgian Waffles with plenty of real maple syrup</desc:description>
+<meal:calories><c><![CDATA[<unknown> &"<>!<a>foo</a>]]></c></meal:calories> </meal:food></meal:breakfast_menu>');
+ xmlformat
+-------------------------------------------------------------------------------------------------------------
+ <meal:breakfast_menu xmlns:meal="http://fancycafe.im/meal/" xmlns:desc="http://fancycafe.mn/meal/" id="73">+
+ <meal:food type="organic" class="fancy"> +
+ <meal:name>Belgian Waffles</meal:name> +
+ <meal:price>$15.95</meal:price> +
+ <desc:description>Two of our famous Belgian Waffles with plenty of real maple syrup</desc:description> +
+ <meal:calories> +
+ <c><![CDATA[<unknown> &"<>!<a>foo</a>]]></c> +
+ </meal:calories> +
+ </meal:food> +
+ </meal:breakfast_menu> +
+
+(1 row)
+
+-- XML format: NULL parameter
+SELECT xmlformat(NULL);
+ xmlformat
+-----------
+
+(1 row)
+
+\set VERBOSITY terse
+-- XML format: invalid string (whitespaces)
+SELECT xmlformat(' ');
+ERROR: invalid XML document
+-- XML format: empty string
+SELECT xmlformat('');
+ERROR: invalid XML document
+\set VERBOSITY default
\ No newline at end of file
diff --git a/src/test/regress/sql/xml.sql b/src/test/regress/sql/xml.sql
index ddff459297..68ac613475 100644
--- a/src/test/regress/sql/xml.sql
+++ b/src/test/regress/sql/xml.sql
@@ -624,3 +624,36 @@ SELECT * FROM XMLTABLE('*' PASSING '<e>pre<!--c1--><?pi arg?><![CDATA[&ent1]]><n
\x
SELECT * FROM XMLTABLE('.' PASSING XMLELEMENT(NAME a) columns a varchar(20) PATH '"<foo/>"', b xml PATH '"<foo/>"');
+
+-- XML format: single line XML string
+SELECT xmlformat('<breakfast_menu id="42"><food type="discounter"><name>Belgian Waffles</name><price>$5.95</price><description>Two of our famous Belgian Waffles with plenty of real maple syrup</description><calories>650</calories></food></breakfast_menu>');
+
+-- XML format: XML string with space, tabs and newline between nodes
+SELECT xmlformat('<breakfast_menu id="73"> <food type="organic" class="fancy"> <name>Belgian Waffles</name> <price>$15.95</price>
+ <description>Two of our famous Belgian Waffles with plenty of real maple syrup</description>
+<calories>650</calories> </food> </breakfast_menu> ');
+
+-- XML format: XML string with space, tabs and newline between nodes, using a namespace
+SELECT xmlformat('<meal:breakfast_menu xmlns:meal="http://fancycafe.im/meal/" id="73"> <meal:food type="organic" class="fancy"> <meal:name>Belgian Waffles</meal:name> <meal:price>$15.95</meal:price>
+ <meal:description>Two of our famous Belgian Waffles with plenty of real maple syrup</meal:description>
+<meal:calories>650</meal:calories> </meal:food></meal:breakfast_menu>');
+
+-- XML format: XML string with space, tabs and newline between nodes, using multiple namespaces and a comment
+SELECT xmlformat('<meal:breakfast_menu xmlns:meal="http://fancycafe.im/meal/" xmlns:desc="http://fancycafe.mn/meal/" id="73"> <meal:food type="organic" class="fancy"> <meal:name>Belgian Waffles</meal:name> <!-- eat this --> <meal:price>$15.95</meal:price>
+ <desc:description>Two of our famous Belgian Waffles with plenty of real maple syrup</desc:description>
+<meal:calories>650</meal:calories> </meal:food></meal:breakfast_menu>');
+
+-- XML format: XML string with space, tabs and newline between nodes, using multiple namespaces and CDATA
+SELECT xmlformat('<meal:breakfast_menu xmlns:meal="http://fancycafe.im/meal/" xmlns:desc="http://fancycafe.mn/meal/" id="73"> <meal:food type="organic" class="fancy"> <meal:name>Belgian Waffles</meal:name> <meal:price>$15.95</meal:price>
+ <desc:description>Two of our famous Belgian Waffles with plenty of real maple syrup</desc:description>
+<meal:calories><c><![CDATA[<unknown> &"<>!<a>foo</a>]]></c></meal:calories> </meal:food></meal:breakfast_menu>');
+
+-- XML format: NULL parameter
+SELECT xmlformat(NULL);
+\set VERBOSITY terse
+-- XML format: invalid string (whitespaces)
+SELECT xmlformat(' ');
+
+-- XML format: empty string
+SELECT xmlformat('');
+\set VERBOSITY default
\ No newline at end of file
--
2.25.1