aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/xml.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2024-09-10 16:20:31 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2024-09-10 16:20:31 -0400
commitbccca780eef904002512a1a0b5ce617bcb63507b (patch)
tree65d58a8b2af7dc210bc98927e2a112f0ac7c9372 /src/backend/utils/adt/xml.c
parented055d249df577ab40470f9dc1a30ab18ffdfff4 (diff)
downloadpostgresql-bccca780eef904002512a1a0b5ce617bcb63507b.tar.gz
postgresql-bccca780eef904002512a1a0b5ce617bcb63507b.zip
Fix some whitespace issues in XMLSERIALIZE(... INDENT).
We must drop whitespace while parsing the input, else libxml2 will include "blank" nodes that interfere with the desired indentation behavior. The end result is that we didn't indent nodes separated by whitespace. Also, it seems that libxml2 may add a trailing newline when working in DOCUMENT mode. This is semantically insignificant, so strip it. This is in the gray area between being a bug fix and a definition change. However, the INDENT option is still pretty new (since v16), so I think we can get away with changing this in stable branches. Hence, back-patch to v16. Jim Jones Discussion: https://postgr.es/m/872865a8-548b-48e1-bfcd-4e38e672c1e4@uni-muenster.de
Diffstat (limited to 'src/backend/utils/adt/xml.c')
-rw-r--r--src/backend/utils/adt/xml.c27
1 files changed, 24 insertions, 3 deletions
diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c
index 447e72b21eb..1a07876cd59 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();
{