Skip to content

Commit 8ad5c64

Browse files
committed
Refactor XML serializer such that passing context is easier
1 parent 4ef7539 commit 8ad5c64

File tree

1 file changed

+55
-52
lines changed

1 file changed

+55
-52
lines changed

ext/dom/xml_serializer.c

Lines changed: 55 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,13 @@ typedef struct {
6666
const xmlChar *prefix, *name;
6767
} dom_qname_pair;
6868

69+
typedef struct dom_xml_serialize_ctx {
70+
xmlSaveCtxtPtr ctxt;
71+
xmlOutputBufferPtr out;
72+
} dom_xml_serialize_ctx;
73+
6974
static int dom_xml_serialization_algorithm(
70-
xmlSaveCtxtPtr ctxt,
71-
xmlOutputBufferPtr out,
75+
dom_xml_serialize_ctx *ctx,
7276
dom_xml_ns_prefix_map *namespace_prefix_map,
7377
xmlNodePtr node,
7478
const xmlChar *namespace,
@@ -895,8 +899,7 @@ static int dom_xml_output_indents(xmlOutputBufferPtr out, int indent)
895899

896900
/* https://w3c.github.io/DOM-Parsing/#dfn-xml-serializing-an-element-node */
897901
static int dom_xml_serialize_element_node(
898-
xmlSaveCtxtPtr ctxt,
899-
xmlOutputBufferPtr out,
902+
dom_xml_serialize_ctx *ctx,
900903
const xmlChar *namespace,
901904
dom_xml_ns_prefix_map *namespace_prefix_map,
902905
xmlNodePtr element,
@@ -916,7 +919,7 @@ static int dom_xml_serialize_element_node(
916919
bool should_format = indent >= 0 && element->children != NULL && dom_xml_should_format_element(element);
917920

918921
/* 2. Let markup be the string "<" (U+003C LESS-THAN SIGN). */
919-
TRY(xmlOutputBufferWriteLit(out, "<"));
922+
TRY(xmlOutputBufferWriteLit(ctx->out, "<"));
920923

921924
/* 3. Let qualified name be an empty string.
922925
* => We're going to do it a bit differently.
@@ -966,7 +969,7 @@ static int dom_xml_serialize_element_node(
966969
}
967970

968971
/* 11.4. Append the value of qualified name to markup. */
969-
TRY_OR_CLEANUP(dom_xml_output_qname(out, &qualified_name));
972+
TRY_OR_CLEANUP(dom_xml_output_qname(ctx->out, &qualified_name));
970973
}
971974
/* 12. Otherwise, inherited ns is not equal to ns */
972975
else {
@@ -1011,7 +1014,7 @@ static int dom_xml_serialize_element_node(
10111014
}
10121015

10131016
/* 12.4.3. Append the value of qualified name to markup. */
1014-
TRY_OR_CLEANUP(dom_xml_output_qname(out, &qualified_name));
1017+
TRY_OR_CLEANUP(dom_xml_output_qname(ctx->out, &qualified_name));
10151018
}
10161019
/* 12.5. Otherwise, if prefix is not null, then: */
10171020
else if (prefix != NULL) {
@@ -1033,14 +1036,14 @@ static int dom_xml_serialize_element_node(
10331036
qualified_name.name = element->name;
10341037

10351038
/* 12.5.4. Append the value of qualified name to markup. */
1036-
TRY_OR_CLEANUP(dom_xml_output_qname(out, &qualified_name));
1039+
TRY_OR_CLEANUP(dom_xml_output_qname(ctx->out, &qualified_name));
10371040

10381041
/* 12.5.5. Append the following to markup, in the order listed: ... */
1039-
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(out, " xmlns:")); /* 12.5.5.1 - 12.5.5.2 */
1040-
TRY_OR_CLEANUP(xmlOutputBufferWriteString(out, (const char *) prefix));
1041-
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(out, "=\""));
1042-
TRY_OR_CLEANUP(dom_xml_common_text_serialization(out, (const char *) ns, true));
1043-
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(out, "\""));
1042+
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out, " xmlns:")); /* 12.5.5.1 - 12.5.5.2 */
1043+
TRY_OR_CLEANUP(xmlOutputBufferWriteString(ctx->out, (const char *) prefix));
1044+
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out, "=\""));
1045+
TRY_OR_CLEANUP(dom_xml_common_text_serialization(ctx->out, (const char *) ns, true));
1046+
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out, "\""));
10441047

10451048
/* 12.5.6. If local default namespace is not null ... (editorial numbering error: https://github.com/w3c/DOM-Parsing/issues/43) */
10461049
if (local_default_namespace != NULL) {
@@ -1064,24 +1067,24 @@ static int dom_xml_serialize_element_node(
10641067
inherited_ns = ns;
10651068

10661069
/* 12.6.4. Append the value of qualified name to markup. */
1067-
TRY_OR_CLEANUP(dom_xml_output_qname(out, &qualified_name));
1070+
TRY_OR_CLEANUP(dom_xml_output_qname(ctx->out, &qualified_name));
10681071

10691072
/* 12.6.5. Append the following to markup, in the order listed: ... */
1070-
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(out, " xmlns=\"")); /* 12.6.5.1 - 12.6.5.2 */
1071-
TRY_OR_CLEANUP(dom_xml_common_text_serialization(out, (const char *) ns, true));
1072-
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(out, "\""));
1073+
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out, " xmlns=\"")); /* 12.6.5.1 - 12.6.5.2 */
1074+
TRY_OR_CLEANUP(dom_xml_common_text_serialization(ctx->out, (const char *) ns, true));
1075+
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out, "\""));
10731076
}
10741077
/* 12.7. Otherwise, the node has a local default namespace that matches ns ... */
10751078
else {
10761079
qualified_name.name = element->name;
10771080
inherited_ns = ns;
1078-
TRY_OR_CLEANUP(dom_xml_output_qname(out, &qualified_name));
1081+
TRY_OR_CLEANUP(dom_xml_output_qname(ctx->out, &qualified_name));
10791082
}
10801083
}
10811084

10821085
/* 13. Append to markup the result of the XML serialization of node's attributes given map, prefix index,
10831086
* local prefixes map, ignore namespace definition attribute flag, and require well-formed flag. */
1084-
TRY_OR_CLEANUP(dom_xml_serialize_attributes(out, element, &map, &local_prefixes_map, prefix_index, ignore_namespace_definition_attribute, require_well_formed));
1087+
TRY_OR_CLEANUP(dom_xml_serialize_attributes(ctx->out, element, &map, &local_prefixes_map, prefix_index, ignore_namespace_definition_attribute, require_well_formed));
10851088

10861089
/* 14. If ns is the HTML namespace, and the node's list of children is empty, and the node's localName matches
10871090
* any one of the following void elements: ... */
@@ -1109,19 +1112,19 @@ static int dom_xml_serialize_element_node(
11091112
|| dom_local_name_compare_ex(element, "source", strlen("source"), name_length)
11101113
|| dom_local_name_compare_ex(element, "track", strlen("track"), name_length)
11111114
|| dom_local_name_compare_ex(element, "wbr", strlen("wbr"), name_length)) {
1112-
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(out, " /"));
1115+
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out, " /"));
11131116
skip_end_tag = true;
11141117
}
11151118
} else {
11161119
/* 15. If ns is not the HTML namespace, and the node's list of children is empty,
11171120
* then append "/" (U+002F SOLIDUS) to markup and set the skip end tag flag to true. */
1118-
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(out, "/"));
1121+
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out, "/"));
11191122
skip_end_tag = true;
11201123
}
11211124
}
11221125

11231126
/* 16. Append ">" (U+003E GREATER-THAN SIGN) to markup. */
1124-
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(out, ">"));
1127+
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out, ">"));
11251128

11261129
/* 17. If the value of skip end tag is true, then return the value of markup and skip the remaining steps. */
11271130
if (!skip_end_tag) {
@@ -1136,20 +1139,20 @@ static int dom_xml_serialize_element_node(
11361139
/* 19. Otherwise, append to markup the result of running the XML serialization algorithm on each of node's children. */
11371140
for (xmlNodePtr child = element->children; child != NULL; child = child->next) {
11381141
if (should_format) {
1139-
TRY_OR_CLEANUP(dom_xml_output_indents(out, indent));
1142+
TRY_OR_CLEANUP(dom_xml_output_indents(ctx->out, indent));
11401143
}
1141-
TRY_OR_CLEANUP(dom_xml_serialization_algorithm(ctxt, out, &map, child, inherited_ns, prefix_index, indent, require_well_formed));
1144+
TRY_OR_CLEANUP(dom_xml_serialization_algorithm(ctx, &map, child, inherited_ns, prefix_index, indent, require_well_formed));
11421145
}
11431146

11441147
if (should_format) {
11451148
indent--;
1146-
TRY_OR_CLEANUP(dom_xml_output_indents(out, indent));
1149+
TRY_OR_CLEANUP(dom_xml_output_indents(ctx->out, indent));
11471150
}
11481151

11491152
/* 20. Append the following to markup, in the order listed: */
1150-
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(out, "</"));
1151-
TRY_OR_CLEANUP(dom_xml_output_qname(out, &qualified_name));
1152-
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(out, ">"));
1153+
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out, "</"));
1154+
TRY_OR_CLEANUP(dom_xml_output_qname(ctx->out, &qualified_name));
1155+
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out, ">"));
11531156
}
11541157

11551158
/* 21. Return the value of markup.
@@ -1166,8 +1169,7 @@ static int dom_xml_serialize_element_node(
11661169

11671170
/* https://w3c.github.io/DOM-Parsing/#xml-serializing-a-documentfragment-node */
11681171
static int dom_xml_serializing_a_document_fragment_node(
1169-
xmlSaveCtxtPtr ctxt,
1170-
xmlOutputBufferPtr out,
1172+
dom_xml_serialize_ctx *ctx,
11711173
dom_xml_ns_prefix_map *namespace_prefix_map,
11721174
xmlNodePtr node,
11731175
const xmlChar *namespace,
@@ -1182,7 +1184,7 @@ static int dom_xml_serializing_a_document_fragment_node(
11821184
/* 2. For each child child of node, in tree order, run the XML serialization algorithm on the child ... */
11831185
xmlNodePtr child = node->children;
11841186
while (child != NULL) {
1185-
TRY(dom_xml_serialization_algorithm(ctxt, out, namespace_prefix_map, child, namespace, prefix_index, indent, require_well_formed));
1187+
TRY(dom_xml_serialization_algorithm(ctx, namespace_prefix_map, child, namespace, prefix_index, indent, require_well_formed));
11861188
child = child->next;
11871189
}
11881190

@@ -1193,8 +1195,7 @@ static int dom_xml_serializing_a_document_fragment_node(
11931195

11941196
/* https://w3c.github.io/DOM-Parsing/#dfn-xml-serializing-a-document-node */
11951197
static int dom_xml_serializing_a_document_node(
1196-
xmlSaveCtxtPtr ctxt,
1197-
xmlOutputBufferPtr out,
1198+
dom_xml_serialize_ctx *ctx,
11981199
dom_xml_ns_prefix_map *namespace_prefix_map,
11991200
xmlNodePtr node,
12001201
const xmlChar *namespace,
@@ -1210,16 +1211,16 @@ static int dom_xml_serializing_a_document_node(
12101211
node->children = NULL;
12111212

12121213
/* https://github.com/w3c/DOM-Parsing/issues/50 */
1213-
TRY(xmlOutputBufferFlush(out));
1214-
TRY(xmlSaveDoc(ctxt, (xmlDocPtr) node));
1215-
TRY(xmlSaveFlush(ctxt));
1214+
TRY(xmlOutputBufferFlush(ctx->out));
1215+
TRY(xmlSaveDoc(ctx->ctxt, (xmlDocPtr) node));
1216+
TRY(xmlSaveFlush(ctx->ctxt));
12161217

12171218
node->children = child;
12181219

12191220
/* 2. For each child child of node, in tree order, run the XML serialization algorithm on the child passing along the provided arguments,
12201221
* and append the result to serialized document. */
12211222
while (child != NULL) {
1222-
TRY(dom_xml_serialization_algorithm(ctxt, out, namespace_prefix_map, child, namespace, prefix_index, indent, require_well_formed));
1223+
TRY(dom_xml_serialization_algorithm(ctx, namespace_prefix_map, child, namespace, prefix_index, indent, require_well_formed));
12231224
child = child->next;
12241225
}
12251226

@@ -1230,8 +1231,7 @@ static int dom_xml_serializing_a_document_node(
12301231

12311232
/* https://w3c.github.io/DOM-Parsing/#dfn-xml-serialization-algorithm */
12321233
static int dom_xml_serialization_algorithm(
1233-
xmlSaveCtxtPtr ctxt,
1234-
xmlOutputBufferPtr out,
1234+
dom_xml_serialize_ctx *ctx,
12351235
dom_xml_ns_prefix_map *namespace_prefix_map,
12361236
xmlNodePtr node,
12371237
const xmlChar *namespace,
@@ -1243,36 +1243,36 @@ static int dom_xml_serialization_algorithm(
12431243
/* If node's interface is: */
12441244
switch (node->type) {
12451245
case XML_ELEMENT_NODE:
1246-
return dom_xml_serialize_element_node(ctxt, out, namespace, namespace_prefix_map, node, prefix_index, indent, require_well_formed);
1246+
return dom_xml_serialize_element_node(ctx, namespace, namespace_prefix_map, node, prefix_index, indent, require_well_formed);
12471247

12481248
case XML_DOCUMENT_FRAG_NODE:
1249-
return dom_xml_serializing_a_document_fragment_node(ctxt, out, namespace_prefix_map, node, namespace, prefix_index, indent, require_well_formed);
1249+
return dom_xml_serializing_a_document_fragment_node(ctx, namespace_prefix_map, node, namespace, prefix_index, indent, require_well_formed);
12501250

12511251
case XML_HTML_DOCUMENT_NODE:
12521252
case XML_DOCUMENT_NODE:
1253-
return dom_xml_serializing_a_document_node(ctxt, out, namespace_prefix_map, node, namespace, prefix_index, indent, require_well_formed);
1253+
return dom_xml_serializing_a_document_node(ctx, namespace_prefix_map, node, namespace, prefix_index, indent, require_well_formed);
12541254

12551255
case XML_TEXT_NODE:
1256-
return dom_xml_serialize_text_node(out, node, require_well_formed);
1256+
return dom_xml_serialize_text_node(ctx->out, node, require_well_formed);
12571257

12581258
case XML_COMMENT_NODE:
1259-
return dom_xml_serialize_comment_node(out, node, require_well_formed);
1259+
return dom_xml_serialize_comment_node(ctx->out, node, require_well_formed);
12601260

12611261
case XML_PI_NODE:
1262-
return dom_xml_serialize_processing_instruction(out, node, require_well_formed);
1262+
return dom_xml_serialize_processing_instruction(ctx->out, node, require_well_formed);
12631263

12641264
case XML_CDATA_SECTION_NODE:
1265-
return dom_xml_serialize_cdata_section_node(out, node);
1265+
return dom_xml_serialize_cdata_section_node(ctx->out, node);
12661266

12671267
case XML_ATTRIBUTE_NODE:
1268-
return dom_xml_serialize_attribute_node(out, node);
1268+
return dom_xml_serialize_attribute_node(ctx->out, node);
12691269

12701270
default:
1271-
TRY(xmlOutputBufferFlush(out));
1272-
TRY(xmlSaveTree(ctxt, node));
1273-
TRY(xmlSaveFlush(ctxt));
1271+
TRY(xmlOutputBufferFlush(ctx->out));
1272+
TRY(xmlSaveTree(ctx->ctxt, node));
1273+
TRY(xmlSaveFlush(ctx->ctxt));
12741274
if (node->type == XML_DTD_NODE) {
1275-
return xmlOutputBufferWriteLit(out, "\n");
1275+
return xmlOutputBufferWriteLit(ctx->out, "\n");
12761276
}
12771277
return 0;
12781278
}
@@ -1297,8 +1297,11 @@ int dom_xml_serialize(xmlSaveCtxtPtr ctxt, xmlOutputBufferPtr out, xmlNodePtr no
12971297
unsigned int prefix_index = 1;
12981298

12991299
/* 5. Return the result of running the XML serialization algorithm ... */
1300+
dom_xml_serialize_ctx ctx;
1301+
ctx.out = out;
1302+
ctx.ctxt = ctxt;
13001303
int indent = format ? 0 : -1;
1301-
int result = dom_xml_serialization_algorithm(ctxt, out, &namespace_prefix_map, node, namespace, &prefix_index, indent, require_well_formed);
1304+
int result = dom_xml_serialization_algorithm(&ctx, &namespace_prefix_map, node, namespace, &prefix_index, indent, require_well_formed);
13021305

13031306
dom_xml_ns_prefix_map_dtor(&namespace_prefix_map);
13041307

0 commit comments

Comments
 (0)