diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c
index 447e72b21e..1a07876cd5 100644
--- a/src/backend/utils/adt/xml.c
+++ b/src/backend/utils/adt/xml.c
@@ -677,8 +677,14 @@ xmltotext_with_options(xmltype *data, XmlOptionType xmloption_arg, bool indent)
}
#ifdef USE_LIBXML
- /* Parse the input according to the xmloption */
- doc = xml_parse(data, xmloption_arg, true, GetDatabaseEncoding(),
+
+ /*
+ * Parse the input according to the xmloption.
+ *
+ * preserve_whitespace is set to false in case we are indenting, otherwise
+ * libxml2 will fail to indent elements that have whitespace between them.
+ */
+ doc = xml_parse(data, xmloption_arg, !indent, GetDatabaseEncoding(),
&parsed_xmloptiontype, &content_nodes,
(Node *) &escontext);
if (doc == NULL || escontext.error_occurred)
@@ -802,7 +808,22 @@ xmltotext_with_options(xmltype *data, XmlOptionType xmloption_arg, bool indent)
"could not close xmlSaveCtxtPtr");
}
- result = (text *) xmlBuffer_to_xmltype(buf);
+ /*
+ * xmlDocContentDumpOutput may add a trailing newline, so remove that.
+ */
+ if (xmloption_arg == XMLOPTION_DOCUMENT)
+ {
+ const char *str = (const char *) xmlBufferContent(buf);
+ int len = xmlBufferLength(buf);
+
+ while (len > 0 && (str[len - 1] == '\n' ||
+ str[len - 1] == '\r'))
+ len--;
+
+ result = cstring_to_text_with_len(str, len);
+ }
+ else
+ result = (text *) xmlBuffer_to_xmltype(buf);
}
PG_CATCH();
{
diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out
index 93a79cda8f..361a6f9b27 100644
--- a/src/test/regress/expected/xml.out
+++ b/src/test/regress/expected/xml.out
@@ -485,8 +485,7 @@ SELECT xmlserialize(DOCUMENT '42' AS text
+
42+
+
- +
-
+
(1 row)
SELECT xmlserialize(CONTENT '42' AS text INDENT);
@@ -546,8 +545,7 @@ SELECT xmlserialize(DOCUMENT '42text node<
42 +
text node73+
+
- +
-
+
(1 row)
SELECT xmlserialize(CONTENT '42text node73' AS text INDENT);
@@ -601,8 +599,7 @@ SELECT xmlserialize(DOCUMENT ' +
73 +
+
- +
-
+
(1 row)
SELECT xmlserialize(CONTENT '73' AS text INDENT);
@@ -620,8 +617,7 @@ SELECT xmlserialize(DOCUMENT '' AS text INDENT);
xmlserialize
--------------
+
- +
-
+
(1 row)
SELECT xmlserialize(CONTENT '' AS text INDENT);
@@ -638,8 +634,7 @@ SELECT xmlserialize(DOCUMENT '' AS text INDENT);
--------------
+
+
- +
-
+
(1 row)
SELECT xmlserialize(CONTENT '' AS text INDENT);
@@ -663,6 +658,24 @@ SELECT xmlserialize(CONTENT '42' AS text
t
(1 row)
+-- indent xml strings containing blank nodes
+SELECT xmlserialize(DOCUMENT ' ' AS text INDENT);
+ xmlserialize
+--------------
+ +
+ +
+
+(1 row)
+
+SELECT xmlserialize(CONTENT 'text node ' AS text INDENT);
+ xmlserialize
+--------------
+ text node +
+ +
+ +
+
+(1 row)
+
SELECT xml 'bar' IS DOCUMENT;
?column?
----------
diff --git a/src/test/regress/expected/xml_1.out b/src/test/regress/expected/xml_1.out
index 9323b84ae2..d26e10441e 100644
--- a/src/test/regress/expected/xml_1.out
+++ b/src/test/regress/expected/xml_1.out
@@ -443,6 +443,17 @@ ERROR: unsupported XML feature
LINE 1: SELECT xmlserialize(CONTENT '42<...
^
DETAIL: This functionality requires the server to be built with libxml support.
+-- indent xml strings containing blank nodes
+SELECT xmlserialize(DOCUMENT ' ' AS text INDENT);
+ERROR: unsupported XML feature
+LINE 1: SELECT xmlserialize(DOCUMENT ' '...
+ ^
+DETAIL: This functionality requires the server to be built with libxml support.
+SELECT xmlserialize(CONTENT 'text node ' AS text INDENT);
+ERROR: unsupported XML feature
+LINE 1: SELECT xmlserialize(CONTENT 'text node ...
+ ^
+DETAIL: This functionality requires the server to be built with libxml support.
SELECT xml 'bar' IS DOCUMENT;
ERROR: unsupported XML feature
LINE 1: SELECT xml 'bar' IS DOCUMENT;
diff --git a/src/test/regress/expected/xml_2.out b/src/test/regress/expected/xml_2.out
index f956322c69..73c2851d3f 100644
--- a/src/test/regress/expected/xml_2.out
+++ b/src/test/regress/expected/xml_2.out
@@ -471,8 +471,7 @@ SELECT xmlserialize(DOCUMENT '42' AS text
+
42+
+
- +
-
+
(1 row)
SELECT xmlserialize(CONTENT '42' AS text INDENT);
@@ -532,8 +531,7 @@ SELECT xmlserialize(DOCUMENT '42text node<
42 +
text node73+
+
- +
-
+
(1 row)
SELECT xmlserialize(CONTENT '42text node73' AS text INDENT);
@@ -587,8 +585,7 @@ SELECT xmlserialize(DOCUMENT ' +
73 +
+
- +
-
+
(1 row)
SELECT xmlserialize(CONTENT '73' AS text INDENT);
@@ -606,8 +603,7 @@ SELECT xmlserialize(DOCUMENT '' AS text INDENT);
xmlserialize
--------------
+
- +
-
+
(1 row)
SELECT xmlserialize(CONTENT '' AS text INDENT);
@@ -624,8 +620,7 @@ SELECT xmlserialize(DOCUMENT '' AS text INDENT);
--------------
+
+
- +
-
+
(1 row)
SELECT xmlserialize(CONTENT '' AS text INDENT);
@@ -649,6 +644,24 @@ SELECT xmlserialize(CONTENT '42' AS text
t
(1 row)
+-- indent xml strings containing blank nodes
+SELECT xmlserialize(DOCUMENT ' ' AS text INDENT);
+ xmlserialize
+--------------
+ +
+ +
+
+(1 row)
+
+SELECT xmlserialize(CONTENT 'text node ' AS text INDENT);
+ xmlserialize
+--------------
+ text node +
+ +
+ +
+
+(1 row)
+
SELECT xml 'bar' IS DOCUMENT;
?column?
----------
diff --git a/src/test/regress/sql/xml.sql b/src/test/regress/sql/xml.sql
index 953bac09e4..f752ecb142 100644
--- a/src/test/regress/sql/xml.sql
+++ b/src/test/regress/sql/xml.sql
@@ -168,6 +168,9 @@ SELECT xmlserialize(CONTENT '' AS text INDENT);
-- 'no indent' = not using 'no indent'
SELECT xmlserialize(DOCUMENT '42' AS text) = xmlserialize(DOCUMENT '42' AS text NO INDENT);
SELECT xmlserialize(CONTENT '42' AS text) = xmlserialize(CONTENT '42' AS text NO INDENT);
+-- indent xml strings containing blank nodes
+SELECT xmlserialize(DOCUMENT ' ' AS text INDENT);
+SELECT xmlserialize(CONTENT 'text node ' AS text INDENT);
SELECT xml 'bar' IS DOCUMENT;
SELECT xml 'barfoo' IS DOCUMENT;