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:
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user