1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Refactor XML serializer such that passing context is easier

This commit is contained in:
Niels Dossche
2024-07-10 16:19:59 +02:00
parent 4ef7539144
commit 8ad5c64393

View File

@@ -66,9 +66,13 @@ typedef struct {
const xmlChar *prefix, *name;
} dom_qname_pair;
typedef struct dom_xml_serialize_ctx {
xmlSaveCtxtPtr ctxt;
xmlOutputBufferPtr out;
} dom_xml_serialize_ctx;
static int dom_xml_serialization_algorithm(
xmlSaveCtxtPtr ctxt,
xmlOutputBufferPtr out,
dom_xml_serialize_ctx *ctx,
dom_xml_ns_prefix_map *namespace_prefix_map,
xmlNodePtr node,
const xmlChar *namespace,
@@ -895,8 +899,7 @@ static int dom_xml_output_indents(xmlOutputBufferPtr out, int indent)
/* https://w3c.github.io/DOM-Parsing/#dfn-xml-serializing-an-element-node */
static int dom_xml_serialize_element_node(
xmlSaveCtxtPtr ctxt,
xmlOutputBufferPtr out,
dom_xml_serialize_ctx *ctx,
const xmlChar *namespace,
dom_xml_ns_prefix_map *namespace_prefix_map,
xmlNodePtr element,
@@ -916,7 +919,7 @@ static int dom_xml_serialize_element_node(
bool should_format = indent >= 0 && element->children != NULL && dom_xml_should_format_element(element);
/* 2. Let markup be the string "<" (U+003C LESS-THAN SIGN). */
TRY(xmlOutputBufferWriteLit(out, "<"));
TRY(xmlOutputBufferWriteLit(ctx->out, "<"));
/* 3. Let qualified name be an empty string.
* => We're going to do it a bit differently.
@@ -966,7 +969,7 @@ static int dom_xml_serialize_element_node(
}
/* 11.4. Append the value of qualified name to markup. */
TRY_OR_CLEANUP(dom_xml_output_qname(out, &qualified_name));
TRY_OR_CLEANUP(dom_xml_output_qname(ctx->out, &qualified_name));
}
/* 12. Otherwise, inherited ns is not equal to ns */
else {
@@ -1011,7 +1014,7 @@ static int dom_xml_serialize_element_node(
}
/* 12.4.3. Append the value of qualified name to markup. */
TRY_OR_CLEANUP(dom_xml_output_qname(out, &qualified_name));
TRY_OR_CLEANUP(dom_xml_output_qname(ctx->out, &qualified_name));
}
/* 12.5. Otherwise, if prefix is not null, then: */
else if (prefix != NULL) {
@@ -1033,14 +1036,14 @@ static int dom_xml_serialize_element_node(
qualified_name.name = element->name;
/* 12.5.4. Append the value of qualified name to markup. */
TRY_OR_CLEANUP(dom_xml_output_qname(out, &qualified_name));
TRY_OR_CLEANUP(dom_xml_output_qname(ctx->out, &qualified_name));
/* 12.5.5. Append the following to markup, in the order listed: ... */
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(out, " xmlns:")); /* 12.5.5.1 - 12.5.5.2 */
TRY_OR_CLEANUP(xmlOutputBufferWriteString(out, (const char *) prefix));
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(out, "=\""));
TRY_OR_CLEANUP(dom_xml_common_text_serialization(out, (const char *) ns, true));
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(out, "\""));
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out, " xmlns:")); /* 12.5.5.1 - 12.5.5.2 */
TRY_OR_CLEANUP(xmlOutputBufferWriteString(ctx->out, (const char *) prefix));
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out, "=\""));
TRY_OR_CLEANUP(dom_xml_common_text_serialization(ctx->out, (const char *) ns, true));
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out, "\""));
/* 12.5.6. If local default namespace is not null ... (editorial numbering error: https://github.com/w3c/DOM-Parsing/issues/43) */
if (local_default_namespace != NULL) {
@@ -1064,24 +1067,24 @@ static int dom_xml_serialize_element_node(
inherited_ns = ns;
/* 12.6.4. Append the value of qualified name to markup. */
TRY_OR_CLEANUP(dom_xml_output_qname(out, &qualified_name));
TRY_OR_CLEANUP(dom_xml_output_qname(ctx->out, &qualified_name));
/* 12.6.5. Append the following to markup, in the order listed: ... */
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(out, " xmlns=\"")); /* 12.6.5.1 - 12.6.5.2 */
TRY_OR_CLEANUP(dom_xml_common_text_serialization(out, (const char *) ns, true));
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(out, "\""));
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out, " xmlns=\"")); /* 12.6.5.1 - 12.6.5.2 */
TRY_OR_CLEANUP(dom_xml_common_text_serialization(ctx->out, (const char *) ns, true));
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out, "\""));
}
/* 12.7. Otherwise, the node has a local default namespace that matches ns ... */
else {
qualified_name.name = element->name;
inherited_ns = ns;
TRY_OR_CLEANUP(dom_xml_output_qname(out, &qualified_name));
TRY_OR_CLEANUP(dom_xml_output_qname(ctx->out, &qualified_name));
}
}
/* 13. Append to markup the result of the XML serialization of node's attributes given map, prefix index,
* local prefixes map, ignore namespace definition attribute flag, and require well-formed flag. */
TRY_OR_CLEANUP(dom_xml_serialize_attributes(out, element, &map, &local_prefixes_map, prefix_index, ignore_namespace_definition_attribute, require_well_formed));
TRY_OR_CLEANUP(dom_xml_serialize_attributes(ctx->out, element, &map, &local_prefixes_map, prefix_index, ignore_namespace_definition_attribute, require_well_formed));
/* 14. If ns is the HTML namespace, and the node's list of children is empty, and the node's localName matches
* any one of the following void elements: ... */
@@ -1109,19 +1112,19 @@ static int dom_xml_serialize_element_node(
|| dom_local_name_compare_ex(element, "source", strlen("source"), name_length)
|| dom_local_name_compare_ex(element, "track", strlen("track"), name_length)
|| dom_local_name_compare_ex(element, "wbr", strlen("wbr"), name_length)) {
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(out, " /"));
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out, " /"));
skip_end_tag = true;
}
} else {
/* 15. If ns is not the HTML namespace, and the node's list of children is empty,
* then append "/" (U+002F SOLIDUS) to markup and set the skip end tag flag to true. */
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(out, "/"));
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out, "/"));
skip_end_tag = true;
}
}
/* 16. Append ">" (U+003E GREATER-THAN SIGN) to markup. */
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(out, ">"));
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out, ">"));
/* 17. If the value of skip end tag is true, then return the value of markup and skip the remaining steps. */
if (!skip_end_tag) {
@@ -1136,20 +1139,20 @@ static int dom_xml_serialize_element_node(
/* 19. Otherwise, append to markup the result of running the XML serialization algorithm on each of node's children. */
for (xmlNodePtr child = element->children; child != NULL; child = child->next) {
if (should_format) {
TRY_OR_CLEANUP(dom_xml_output_indents(out, indent));
TRY_OR_CLEANUP(dom_xml_output_indents(ctx->out, indent));
}
TRY_OR_CLEANUP(dom_xml_serialization_algorithm(ctxt, out, &map, child, inherited_ns, prefix_index, indent, require_well_formed));
TRY_OR_CLEANUP(dom_xml_serialization_algorithm(ctx, &map, child, inherited_ns, prefix_index, indent, require_well_formed));
}
if (should_format) {
indent--;
TRY_OR_CLEANUP(dom_xml_output_indents(out, indent));
TRY_OR_CLEANUP(dom_xml_output_indents(ctx->out, indent));
}
/* 20. Append the following to markup, in the order listed: */
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(out, "</"));
TRY_OR_CLEANUP(dom_xml_output_qname(out, &qualified_name));
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(out, ">"));
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out, "</"));
TRY_OR_CLEANUP(dom_xml_output_qname(ctx->out, &qualified_name));
TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out, ">"));
}
/* 21. Return the value of markup.
@@ -1166,8 +1169,7 @@ cleanup:
/* https://w3c.github.io/DOM-Parsing/#xml-serializing-a-documentfragment-node */
static int dom_xml_serializing_a_document_fragment_node(
xmlSaveCtxtPtr ctxt,
xmlOutputBufferPtr out,
dom_xml_serialize_ctx *ctx,
dom_xml_ns_prefix_map *namespace_prefix_map,
xmlNodePtr node,
const xmlChar *namespace,
@@ -1182,7 +1184,7 @@ static int dom_xml_serializing_a_document_fragment_node(
/* 2. For each child child of node, in tree order, run the XML serialization algorithm on the child ... */
xmlNodePtr child = node->children;
while (child != NULL) {
TRY(dom_xml_serialization_algorithm(ctxt, out, namespace_prefix_map, child, namespace, prefix_index, indent, require_well_formed));
TRY(dom_xml_serialization_algorithm(ctx, namespace_prefix_map, child, namespace, prefix_index, indent, require_well_formed));
child = child->next;
}
@@ -1193,8 +1195,7 @@ static int dom_xml_serializing_a_document_fragment_node(
/* https://w3c.github.io/DOM-Parsing/#dfn-xml-serializing-a-document-node */
static int dom_xml_serializing_a_document_node(
xmlSaveCtxtPtr ctxt,
xmlOutputBufferPtr out,
dom_xml_serialize_ctx *ctx,
dom_xml_ns_prefix_map *namespace_prefix_map,
xmlNodePtr node,
const xmlChar *namespace,
@@ -1210,16 +1211,16 @@ static int dom_xml_serializing_a_document_node(
node->children = NULL;
/* https://github.com/w3c/DOM-Parsing/issues/50 */
TRY(xmlOutputBufferFlush(out));
TRY(xmlSaveDoc(ctxt, (xmlDocPtr) node));
TRY(xmlSaveFlush(ctxt));
TRY(xmlOutputBufferFlush(ctx->out));
TRY(xmlSaveDoc(ctx->ctxt, (xmlDocPtr) node));
TRY(xmlSaveFlush(ctx->ctxt));
node->children = child;
/* 2. For each child child of node, in tree order, run the XML serialization algorithm on the child passing along the provided arguments,
* and append the result to serialized document. */
while (child != NULL) {
TRY(dom_xml_serialization_algorithm(ctxt, out, namespace_prefix_map, child, namespace, prefix_index, indent, require_well_formed));
TRY(dom_xml_serialization_algorithm(ctx, namespace_prefix_map, child, namespace, prefix_index, indent, require_well_formed));
child = child->next;
}
@@ -1230,8 +1231,7 @@ static int dom_xml_serializing_a_document_node(
/* https://w3c.github.io/DOM-Parsing/#dfn-xml-serialization-algorithm */
static int dom_xml_serialization_algorithm(
xmlSaveCtxtPtr ctxt,
xmlOutputBufferPtr out,
dom_xml_serialize_ctx *ctx,
dom_xml_ns_prefix_map *namespace_prefix_map,
xmlNodePtr node,
const xmlChar *namespace,
@@ -1243,36 +1243,36 @@ static int dom_xml_serialization_algorithm(
/* If node's interface is: */
switch (node->type) {
case XML_ELEMENT_NODE:
return dom_xml_serialize_element_node(ctxt, out, namespace, namespace_prefix_map, node, prefix_index, indent, require_well_formed);
return dom_xml_serialize_element_node(ctx, namespace, namespace_prefix_map, node, prefix_index, indent, require_well_formed);
case XML_DOCUMENT_FRAG_NODE:
return dom_xml_serializing_a_document_fragment_node(ctxt, out, namespace_prefix_map, node, namespace, prefix_index, indent, require_well_formed);
return dom_xml_serializing_a_document_fragment_node(ctx, namespace_prefix_map, node, namespace, prefix_index, indent, require_well_formed);
case XML_HTML_DOCUMENT_NODE:
case XML_DOCUMENT_NODE:
return dom_xml_serializing_a_document_node(ctxt, out, namespace_prefix_map, node, namespace, prefix_index, indent, require_well_formed);
return dom_xml_serializing_a_document_node(ctx, namespace_prefix_map, node, namespace, prefix_index, indent, require_well_formed);
case XML_TEXT_NODE:
return dom_xml_serialize_text_node(out, node, require_well_formed);
return dom_xml_serialize_text_node(ctx->out, node, require_well_formed);
case XML_COMMENT_NODE:
return dom_xml_serialize_comment_node(out, node, require_well_formed);
return dom_xml_serialize_comment_node(ctx->out, node, require_well_formed);
case XML_PI_NODE:
return dom_xml_serialize_processing_instruction(out, node, require_well_formed);
return dom_xml_serialize_processing_instruction(ctx->out, node, require_well_formed);
case XML_CDATA_SECTION_NODE:
return dom_xml_serialize_cdata_section_node(out, node);
return dom_xml_serialize_cdata_section_node(ctx->out, node);
case XML_ATTRIBUTE_NODE:
return dom_xml_serialize_attribute_node(out, node);
return dom_xml_serialize_attribute_node(ctx->out, node);
default:
TRY(xmlOutputBufferFlush(out));
TRY(xmlSaveTree(ctxt, node));
TRY(xmlSaveFlush(ctxt));
TRY(xmlOutputBufferFlush(ctx->out));
TRY(xmlSaveTree(ctx->ctxt, node));
TRY(xmlSaveFlush(ctx->ctxt));
if (node->type == XML_DTD_NODE) {
return xmlOutputBufferWriteLit(out, "\n");
return xmlOutputBufferWriteLit(ctx->out, "\n");
}
return 0;
}
@@ -1297,8 +1297,11 @@ int dom_xml_serialize(xmlSaveCtxtPtr ctxt, xmlOutputBufferPtr out, xmlNodePtr no
unsigned int prefix_index = 1;
/* 5. Return the result of running the XML serialization algorithm ... */
dom_xml_serialize_ctx ctx;
ctx.out = out;
ctx.ctxt = ctxt;
int indent = format ? 0 : -1;
int result = dom_xml_serialization_algorithm(ctxt, out, &namespace_prefix_map, node, namespace, &prefix_index, indent, require_well_formed);
int result = dom_xml_serialization_algorithm(&ctx, &namespace_prefix_map, node, namespace, &prefix_index, indent, require_well_formed);
dom_xml_ns_prefix_map_dtor(&namespace_prefix_map);