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;