Skip to content

Commit 483bdb2

Browse files
committed
Support [NO] INDENT option in XMLSERIALIZE().
This adds the ability to pretty-print XML documents ... according to libxml's somewhat idiosyncratic notions of what's pretty, anyway. One notable divergence from a strict reading of the spec is that libxml is willing to collapse empty nodes "<node></node>" to just "<node/>", whereas SQL and the underlying XML spec say that this option should only result in whitespace tweaks. Nonetheless, it seems close enough to justify using the SQL-standard syntax. Jim Jones, reviewed by Peter Smith and myself Discussion: https://postgr.es/m/2f5df461-dad8-6d7d-4568-08e10608a69b@uni-muenster.de
1 parent 419a8dd commit 483bdb2

File tree

15 files changed

+775
-22
lines changed

15 files changed

+775
-22
lines changed

doc/src/sgml/datatype.sgml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4460,7 +4460,7 @@ xml '<foo>bar</foo>'
44604460
<type>xml</type>, uses the function
44614461
<function>xmlserialize</function>:<indexterm><primary>xmlserialize</primary></indexterm>
44624462
<synopsis>
4463-
XMLSERIALIZE ( { DOCUMENT | CONTENT } <replaceable>value</replaceable> AS <replaceable>type</replaceable> )
4463+
XMLSERIALIZE ( { DOCUMENT | CONTENT } <replaceable>value</replaceable> AS <replaceable>type</replaceable> [ [ NO ] INDENT ] )
44644464
</synopsis>
44654465
<replaceable>type</replaceable> can be
44664466
<type>character</type>, <type>character varying</type>, or
@@ -4470,6 +4470,13 @@ XMLSERIALIZE ( { DOCUMENT | CONTENT } <replaceable>value</replaceable> AS <repla
44704470
you to simply cast the value.
44714471
</para>
44724472

4473+
<para>
4474+
The <literal>INDENT</literal> option causes the result to be
4475+
pretty-printed, while <literal>NO INDENT</literal> (which is the
4476+
default) just emits the original input string. Casting to a character
4477+
type likewise produces the original string.
4478+
</para>
4479+
44734480
<para>
44744481
When a character string value is cast to or from type
44754482
<type>xml</type> without going through <type>XMLPARSE</type> or

src/backend/catalog/sql_features.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -621,7 +621,7 @@ X061 XMLParse: character string input and DOCUMENT option YES
621621
X065 XMLParse: binary string input and CONTENT option NO
622622
X066 XMLParse: binary string input and DOCUMENT option NO
623623
X068 XMLSerialize: BOM NO
624-
X069 XMLSerialize: INDENT NO
624+
X069 XMLSerialize: INDENT YES
625625
X070 XMLSerialize: character string serialization and CONTENT option YES
626626
X071 XMLSerialize: character string serialization and DOCUMENT option YES
627627
X072 XMLSerialize: character string serialization YES

src/backend/executor/execExprInterp.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3837,8 +3837,10 @@ ExecEvalXmlExpr(ExprState *state, ExprEvalStep *op)
38373837
return;
38383838
value = argvalue[0];
38393839

3840-
*op->resvalue = PointerGetDatum(xmltotext_with_xmloption(DatumGetXmlP(value),
3841-
xexpr->xmloption));
3840+
*op->resvalue =
3841+
PointerGetDatum(xmltotext_with_options(DatumGetXmlP(value),
3842+
xexpr->xmloption,
3843+
xexpr->indent));
38423844
*op->resnull = false;
38433845
}
38443846
break;

src/backend/parser/gram.y

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -613,7 +613,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
613613
%type <node> xml_root_version opt_xml_root_standalone
614614
%type <node> xmlexists_argument
615615
%type <ival> document_or_content
616-
%type <boolean> xml_whitespace_option
616+
%type <boolean> xml_indent_option xml_whitespace_option
617617
%type <list> xmltable_column_list xmltable_column_option_list
618618
%type <node> xmltable_column_el
619619
%type <defelt> xmltable_column_option_el
@@ -702,7 +702,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
702702
HANDLER HAVING HEADER_P HOLD HOUR_P
703703

704704
IDENTITY_P IF_P ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IMPORT_P IN_P INCLUDE
705-
INCLUDING INCREMENT INDEX INDEXES INHERIT INHERITS INITIALLY INLINE_P
705+
INCLUDING INCREMENT INDENT INDEX INDEXES INHERIT INHERITS INITIALLY INLINE_P
706706
INNER_P INOUT INPUT_P INSENSITIVE INSERT INSTEAD INT_P INTEGER
707707
INTERSECT INTERVAL INTO INVOKER IS ISNULL ISOLATION
708708

@@ -15532,13 +15532,14 @@ func_expr_common_subexpr:
1553215532
$$ = makeXmlExpr(IS_XMLROOT, NULL, NIL,
1553315533
list_make3($3, $5, $6), @1);
1553415534
}
15535-
| XMLSERIALIZE '(' document_or_content a_expr AS SimpleTypename ')'
15535+
| XMLSERIALIZE '(' document_or_content a_expr AS SimpleTypename xml_indent_option ')'
1553615536
{
1553715537
XmlSerialize *n = makeNode(XmlSerialize);
1553815538

1553915539
n->xmloption = $3;
1554015540
n->expr = $4;
1554115541
n->typeName = $6;
15542+
n->indent = $7;
1554215543
n->location = @1;
1554315544
$$ = (Node *) n;
1554415545
}
@@ -15592,6 +15593,11 @@ document_or_content: DOCUMENT_P { $$ = XMLOPTION_DOCUMENT; }
1559215593
| CONTENT_P { $$ = XMLOPTION_CONTENT; }
1559315594
;
1559415595

15596+
xml_indent_option: INDENT { $$ = true; }
15597+
| NO INDENT { $$ = false; }
15598+
| /*EMPTY*/ { $$ = false; }
15599+
;
15600+
1559515601
xml_whitespace_option: PRESERVE WHITESPACE_P { $$ = true; }
1559615602
| STRIP_P WHITESPACE_P { $$ = false; }
1559715603
| /*EMPTY*/ { $$ = false; }
@@ -16828,6 +16834,7 @@ unreserved_keyword:
1682816834
| INCLUDE
1682916835
| INCLUDING
1683016836
| INCREMENT
16837+
| INDENT
1683116838
| INDEX
1683216839
| INDEXES
1683316840
| INHERIT
@@ -17384,6 +17391,7 @@ bare_label_keyword:
1738417391
| INCLUDE
1738517392
| INCLUDING
1738617393
| INCREMENT
17394+
| INDENT
1738717395
| INDEX
1738817396
| INDEXES
1738917397
| INHERIT

src/backend/parser/parse_expr.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2331,6 +2331,7 @@ transformXmlSerialize(ParseState *pstate, XmlSerialize *xs)
23312331
typenameTypeIdAndMod(pstate, xs->typeName, &targetType, &targetTypmod);
23322332

23332333
xexpr->xmloption = xs->xmloption;
2334+
xexpr->indent = xs->indent;
23342335
xexpr->location = xs->location;
23352336
/* We actually only need these to be able to parse back the expression. */
23362337
xexpr->type = targetType;

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy