22#if defined(HAVE_LIBXML) && defined(HAVE_DOM)
28#include <libxml/chvalid.h>
50#define TRY(x) do { if (UNEXPECTED((x) < 0)) { return -1; } } while (0)
51#define TRY_OR_CLEANUP(x) do { if (UNEXPECTED((x) < 0)) { goto cleanup; } } while (0)
53#define xmlOutputBufferWriteLit(out, literal) xmlOutputBufferWrite((out), strlen("" literal), "" literal)
59} dom_xml_ns_prefix_map;
64} dom_xml_local_prefix_map;
70typedef struct dom_xml_serialize_ctx {
72 xmlOutputBufferPtr
out;
74} dom_xml_serialize_ctx;
76static int dom_xml_serialization_algorithm(
77 dom_xml_serialize_ctx *ctx,
78 dom_xml_ns_prefix_map *namespace_prefix_map,
80 const xmlChar *
namespace,
81 unsigned int *prefix_index,
83 bool require_well_formed
86static bool dom_xml_str_equals_treat_nulls_as_empty(
const xmlChar *s1,
const xmlChar *s2)
92 return s2 ==
NULL || *s2 ==
'\0';
98 return strcmp((
const char *) s1, (
const char *) s2) == 0;
101static zend_always_inline bool dom_xml_str_equals_treat_nulls_as_nulls(
const xmlChar *s1,
const xmlChar *s2)
109 return strcmp((
const char *) s1, (
const char *) s2) == 0;
118static void dom_xml_ns_prefix_map_destroy(dom_xml_ns_prefix_map *map)
143 dom_xml_ns_prefix_map_destroy(map);
147static zend_always_inline void dom_xml_ns_prefix_map_copy(dom_xml_ns_prefix_map *dst,
const dom_xml_ns_prefix_map *src)
153static zend_always_inline void dom_xml_local_prefix_map_ctor(dom_xml_local_prefix_map *map)
158static zend_always_inline void dom_xml_local_prefix_map_dtor(dom_xml_local_prefix_map *map)
164 dom_xml_local_prefix_map *map,
171 zend_hash_str_add_ptr(&map->ht, (
const char *)
prefix, prefix_len, (
void *) ns);
175 const dom_xml_local_prefix_map *map,
181 return zend_hash_str_find_ptr(&map->ht, (
const char *)
prefix, prefix_len);
185 const dom_xml_local_prefix_map *map,
191 const xmlChar *
result = dom_xml_local_prefix_map_find(map,
prefix, prefix_len);
195 return !dom_xml_str_equals_treat_nulls_as_empty(
result, ns);
199 const dom_xml_local_prefix_map *map,
204 return dom_xml_local_prefix_map_find(map,
prefix, prefix_len) !=
NULL;
208static void dom_xml_ns_prefix_map_add(
209 dom_xml_ns_prefix_map *map,
236 HashTable *list = zend_hash_str_find_ptr(map->ht, (
const char *) ns, ns_length);
243 zend_hash_str_add_new_ptr(map->ht, (
const char *) ns, ns_length, list);
247 zend_hash_str_update_ptr(map->ht, (
const char *) ns, ns_length, list);
268 return zend_hash_str_find_ptr(map->ht, (
const char *) ns, ns_length);
283 if (dom_xml_str_equals_treat_nulls_as_empty(BAD_CAST tmp,
prefix)) {
293 dom_xml_ns_prefix_map *map,
300 HashTable *list = dom_get_candidates_list(map, ns, ns_length);
301 return dom_prefix_in_candidate_list(list,
prefix);
310 return attr->children->content ?
attr->children->content : BAD_CAST
"";
314static const xmlChar *dom_recording_the_namespace_information(
315 dom_xml_ns_prefix_map *namespace_prefix_map,
316 dom_xml_local_prefix_map *local_prefixes_map,
323 const xmlChar *default_namespace_attr_value =
NULL;
335 default_namespace_attr_value = dom_get_attribute_value(
attr);
342 const xmlChar *prefix_definition =
attr->name;
346 const xmlChar *namespace_definition = dom_get_attribute_value(
attr);
359 size_t namespace_definition_length =
strlen((
const char *) namespace_definition);
363 if (dom_prefix_found_in_ns_prefix_map(namespace_prefix_map, prefix_definition, namespace_definition, namespace_definition_length)) {
368 if (*namespace_definition ==
'\0') {
369 namespace_definition =
NULL;
373 dom_xml_ns_prefix_map_add(namespace_prefix_map, prefix_definition,
false, namespace_definition, namespace_definition_length);
377 size_t prefix_definition_length =
strlen((
const char *) prefix_definition);
378 namespace_definition = namespace_definition ==
NULL ? BAD_CAST
"" : namespace_definition;
379 dom_xml_local_prefix_map_add(local_prefixes_map, prefix_definition, prefix_definition_length, namespace_definition);
385 return default_namespace_attr_value;
389static const xmlChar *dom_retrieve_a_preferred_prefix_string(
390 dom_xml_ns_prefix_map *namespace_prefix_map,
391 dom_xml_local_prefix_map *local_prefixes_map,
392 const xmlChar *preferred_prefix,
405 HashTable *list = dom_get_candidates_list(namespace_prefix_map, ns, ns_length);
412 const xmlChar *last_non_conflicting_in_list =
NULL;
420 if (!dom_xml_local_prefix_map_conflicts(local_prefixes_map,
prefix,
strlen((
const char *)
prefix), ns)) {
421 if (dom_xml_str_equals_treat_nulls_as_empty(preferred_prefix,
prefix)) {
425 if (last_non_conflicting_in_list ==
NULL) {
426 last_non_conflicting_in_list =
prefix;
433 return last_non_conflicting_in_list;
437static xmlChar *dom_xml_generate_a_prefix(
438 dom_xml_ns_prefix_map *map,
439 dom_xml_local_prefix_map *local_prefixes_map,
440 const xmlChar *new_namespace,
441 size_t new_namespace_length,
442 unsigned int *prefix_index
457 }
while (dom_xml_local_prefix_map_contains(local_prefixes_map, (
const xmlChar *)
buffer, length));
459 xmlChar *generated_prefix =
emalloc(length + 1);
463 dom_xml_ns_prefix_map_add(map, generated_prefix,
true, new_namespace, new_namespace_length);
465 dom_xml_local_prefix_map_add(local_prefixes_map, generated_prefix, length, new_namespace);
468 return generated_prefix;
471static int dom_xml_output_qname(xmlOutputBufferPtr
out,
const dom_qname_pair *qname)
473 if (qname->prefix !=
NULL) {
474 TRY(xmlOutputBufferWriteString(
out, (
const char *) qname->prefix));
475 TRY(xmlOutputBufferWriteLit(
out,
":"));
477 return xmlOutputBufferWriteString(
out, (
const char *) qname->name);
483static int dom_xml_common_text_serialization(xmlOutputBufferPtr
out,
const char *content,
bool attribute_mode)
485 if (content ==
NULL) {
489 const char *last_output = content;
490 const char *mask = attribute_mode ?
"&<>\"\t\n\r" :
"&<>";
493 size_t chunk_length =
strcspn(content, mask);
495 content += chunk_length;
496 if (*content ==
'\0') {
500 TRY(xmlOutputBufferWrite(
out, content - last_output, last_output));
504 TRY(xmlOutputBufferWriteLit(
out,
"&"));
509 TRY(xmlOutputBufferWriteLit(
out,
"<"));
514 TRY(xmlOutputBufferWriteLit(
out,
">"));
519 TRY(xmlOutputBufferWriteLit(
out,
"""));
526 TRY(xmlOutputBufferWriteLit(
out,
"	"));
531 TRY(xmlOutputBufferWriteLit(
out,
" "));
536 TRY(xmlOutputBufferWriteLit(
out,
" "));
542 last_output = content;
545 return xmlOutputBufferWrite(
out, content - last_output, last_output);
548static int dom_xml_check_char_production(
const xmlChar *content)
552 const xmlChar *
ptr = content;
553 while (*
ptr !=
'\0') {
555 int c = xmlGetUTF8Char(
ptr, &
len);
556 if (c < 0 || !xmlIsCharQ(c)) {
566static zend_always_inline int dom_xml_serialize_text_node(xmlOutputBufferPtr
out, xmlNodePtr
text,
bool require_well_formed)
570 if (require_well_formed &&
text->content !=
NULL) {
571 TRY(dom_xml_check_char_production(
text->content));
574 return dom_xml_common_text_serialization(
out, (
const char *)
text->content,
false);
582static int dom_xml_serialize_attribute_node_value(xmlOutputBufferPtr
out, xmlAttrPtr
attr)
584 TRY(xmlOutputBufferWriteString(
out, (
const char *)
attr->name));
585 TRY(xmlOutputBufferWriteLit(
out,
"=\""));
586 for (xmlNodePtr child =
attr->children; child !=
NULL; child = child->next) {
588 if (child->content !=
NULL) {
589 TRY(dom_xml_common_text_serialization(
out, (
const char *) child->content,
true));
592 TRY(xmlOutputBufferWriteLit(
out,
"&"));
593 TRY(dom_xml_common_text_serialization(
out, (
const char *) child->name,
true));
594 TRY(xmlOutputBufferWriteLit(
out,
";"));
597 return xmlOutputBufferWriteLit(
out,
"\"");
603static zend_always_inline int dom_xml_check_xmlns_attribute_requirements(
const xmlAttr *
attr,
const xmlChar *candidate_prefix)
605 const xmlChar *attr_value = dom_get_attribute_value(
attr);
614 if (*attr_value ==
'\0' && candidate_prefix !=
NULL) {
623static int dom_xml_serialize_attribute_node(xmlOutputBufferPtr
out, xmlNodePtr
attr)
626 TRY(xmlOutputBufferWriteString(
out, (
const char *)
attr->ns->prefix));
627 TRY(xmlOutputBufferWriteLit(
out,
":"));
629 return dom_xml_serialize_attribute_node_value(
out, (xmlAttrPtr)
attr);
633static int dom_xml_serialize_comment_node(xmlOutputBufferPtr
out, xmlNodePtr comment,
bool require_well_formed)
636 if (require_well_formed) {
640 const xmlChar *
ptr = comment->content;
642 TRY(dom_xml_check_char_production(
ptr));
649 TRY(xmlOutputBufferWriteLit(
out,
"<!--"));
651 TRY(xmlOutputBufferWriteString(
out, (
const char *) comment->content));
653 return xmlOutputBufferWriteLit(
out,
"-->");
657static int dom_xml_serialize_processing_instruction(xmlOutputBufferPtr
out, xmlNodePtr
pi,
bool require_well_formed)
660 if (require_well_formed) {
668 if (
pi->content !=
NULL) {
669 TRY(dom_xml_check_char_production(
pi->content));
676 TRY(xmlOutputBufferWriteLit(
out,
"<?"));
677 TRY(xmlOutputBufferWriteString(
out, (
const char *)
pi->name));
678 TRY(xmlOutputBufferWriteLit(
out,
" "));
680 TRY(xmlOutputBufferWriteString(
out, (
const char *)
pi->content));
682 return xmlOutputBufferWriteLit(
out,
"?>");
687static int dom_xml_serialize_cdata_section_node(xmlOutputBufferPtr
out, xmlNodePtr
cdata)
689 TRY(xmlOutputBufferWriteLit(
out,
"<![CDATA["));
691 TRY(xmlOutputBufferWriteString(
out, (
const char *)
cdata->content));
693 return xmlOutputBufferWriteLit(
out,
"]]>");
696static zend_string *dom_xml_create_localname_set_key(
const xmlAttr *
attr)
699 return zend_string_init((
const char *)
attr->name,
strlen((
const char *)
attr->name),
false);
707 (
const char *)
attr->ns->href,
strlen((
const char *)
attr->ns->href),
714static int dom_xml_serialize_attributes(
715 xmlOutputBufferPtr
out,
717 dom_xml_ns_prefix_map *map,
718 dom_xml_local_prefix_map *local_prefixes_map,
719 unsigned int *prefix_index,
720 bool ignore_namespace_definition_attribute,
721 bool require_well_formed
734 if (require_well_formed) {
747 const xmlChar *attribute_namespace = dom_xml_attribute_namespace(
attr);
750 const xmlChar *candidate_prefix =
NULL;
753 if (attribute_namespace !=
NULL) {
756 candidate_prefix = dom_retrieve_a_preferred_prefix_string(
761 strlen((
const char *) attribute_namespace)
766 const xmlChar *attr_value = dom_get_attribute_value(
attr);
774 if (ignore_namespace_definition_attribute &&
attr->ns->prefix ==
NULL) {
776 if (!dom_xml_str_equals_treat_nulls_as_empty(element->ns ==
NULL ?
NULL : element->ns->href, attr_value)) {
786 const xmlChar *
value = dom_xml_local_prefix_map_find(local_prefixes_map,
attr->name,
strlen((
const char *)
attr->name));
788 if (dom_prefix_found_in_ns_prefix_map(map,
attr->name, attr_value,
strlen((
const char *) attr_value))) {
795 if (
attr->ns->prefix !=
NULL &&
strcmp((
const char *)
attr->ns->prefix,
"xmlns") == 0) {
796 candidate_prefix = BAD_CAST
"xmlns";
800 if (require_well_formed) {
802 TRY_OR_CLEANUP(dom_xml_check_xmlns_attribute_requirements(
attr, candidate_prefix));
806 else if (candidate_prefix ==
NULL) {
809 || dom_xml_local_prefix_map_contains(local_prefixes_map,
attr->ns->prefix,
strlen((
const char *)
attr->ns->prefix))) {
812 candidate_prefix = dom_xml_generate_a_prefix(
816 strlen((
const char *) attribute_namespace),
820 candidate_prefix =
attr->ns->prefix;
822 dom_xml_ns_prefix_map_add(
827 strlen((
const char *) attribute_namespace)
829 dom_xml_local_prefix_map_add(
832 strlen((
const char *) candidate_prefix),
838 TRY_OR_CLEANUP(xmlOutputBufferWriteLit(
out,
" xmlns:"));
839 TRY_OR_CLEANUP(xmlOutputBufferWriteString(
out, (
const char *) candidate_prefix));
840 TRY_OR_CLEANUP(xmlOutputBufferWriteLit(
out,
"=\""));
841 TRY_OR_CLEANUP(dom_xml_common_text_serialization(
out, (
const char *) attribute_namespace,
true));
842 TRY_OR_CLEANUP(xmlOutputBufferWriteLit(
out,
"\""));
847 TRY_OR_CLEANUP(xmlOutputBufferWriteLit(
out,
" "));
850 if (candidate_prefix !=
NULL) {
851 TRY_OR_CLEANUP(xmlOutputBufferWriteString(
out, (
const char *) candidate_prefix));
852 TRY_OR_CLEANUP(xmlOutputBufferWriteLit(
out,
":"));
855 if (require_well_formed) {
860 if (xmlValidateNCName(
attr->name, 0) != 0
861 || (
strcmp((
const char *)
attr->name,
"xmlns") == 0 && dom_xml_attribute_namespace(
attr) ==
NULL)) {
867 TRY_OR_CLEANUP(dom_xml_serialize_attribute_node_value(
out,
attr));
882static bool dom_xml_should_format_element(xmlNodePtr element)
884 xmlNodePtr child = element->children;
891 }
while (child !=
NULL);
895static int dom_xml_output_indents(xmlOutputBufferPtr
out,
int indent)
897 TRY(xmlOutputBufferWriteLit(
out,
"\n"));
898 for (
int i = 0; i < indent; i++) {
899 TRY(xmlOutputBufferWriteLit(
out,
" "));
905static int dom_xml_serialize_element_node(
906 dom_xml_serialize_ctx *ctx,
907 const xmlChar *
namespace,
908 dom_xml_ns_prefix_map *namespace_prefix_map,
910 unsigned int *prefix_index,
912 bool require_well_formed
917 if (require_well_formed) {
918 if (xmlValidateNCName(element->name, 0) != 0) {
923 bool should_format = indent >= 0 && element->children !=
NULL && dom_xml_should_format_element(element);
926 TRY(xmlOutputBufferWriteLit(ctx->out,
"<"));
932 dom_qname_pair qualified_name = {
NULL,
NULL };
935 bool skip_end_tag =
false;
938 bool ignore_namespace_definition_attribute =
false;
941 dom_xml_ns_prefix_map map;
942 dom_xml_ns_prefix_map_copy(&map, namespace_prefix_map);
945 dom_xml_local_prefix_map local_prefixes_map;
946 dom_xml_local_prefix_map_ctor(&local_prefixes_map);
949 const xmlChar *local_default_namespace = dom_recording_the_namespace_information(&map, &local_prefixes_map, element);
952 const xmlChar *inherited_ns =
namespace;
955 const xmlChar *
const ns = element->ns ==
NULL ?
NULL : element->ns->href;
958 if (dom_xml_str_equals_treat_nulls_as_nulls(inherited_ns, ns)) {
960 if (local_default_namespace !=
NULL) {
961 ignore_namespace_definition_attribute =
true;
967 qualified_name.prefix = BAD_CAST
"xml";
968 qualified_name.name = element->name;
972 qualified_name.name = element->name;
976 TRY_OR_CLEANUP(dom_xml_output_qname(ctx->out, &qualified_name));
981 const xmlChar *
prefix = element->ns ==
NULL ?
NULL : element->ns->prefix;
985 const xmlChar *candidate_prefix;
986 if (
prefix ==
NULL && dom_xml_str_equals_treat_nulls_as_empty(ns, local_default_namespace)) {
987 candidate_prefix =
NULL;
989 size_t ns_length = ns ==
NULL ? 0 :
strlen((
const char *) ns);
990 candidate_prefix = dom_retrieve_a_preferred_prefix_string(&map, &local_prefixes_map,
prefix, ns, ns_length);
996 if (require_well_formed) {
1001 candidate_prefix =
prefix;
1005 if (candidate_prefix !=
NULL) {
1007 qualified_name.prefix = candidate_prefix;
1008 qualified_name.name = element->name;
1013 if (*local_default_namespace ==
'\0') {
1014 inherited_ns =
NULL;
1016 inherited_ns = local_default_namespace;
1021 TRY_OR_CLEANUP(dom_xml_output_qname(ctx->out, &qualified_name));
1025 size_t ns_length = ns ==
NULL ? 0 :
strlen((
const char *) ns);
1029 if (dom_xml_local_prefix_map_contains(&local_prefixes_map,
prefix, prefix_length)) {
1030 prefix = dom_xml_generate_a_prefix(&map, &local_prefixes_map, ns, ns_length, prefix_index);
1033 dom_xml_ns_prefix_map_add(&map,
prefix,
false, ns, ns_length);
1035 dom_xml_local_prefix_map_add(&local_prefixes_map,
prefix, prefix_length, ns);
1039 qualified_name.prefix =
prefix;
1040 qualified_name.name = element->name;
1043 TRY_OR_CLEANUP(dom_xml_output_qname(ctx->out, &qualified_name));
1046 TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out,
" xmlns:"));
1047 TRY_OR_CLEANUP(xmlOutputBufferWriteString(ctx->out, (
const char *)
prefix));
1048 TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out,
"=\""));
1049 TRY_OR_CLEANUP(dom_xml_common_text_serialization(ctx->out, (
const char *) ns,
true));
1050 TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out,
"\""));
1053 if (local_default_namespace !=
NULL) {
1054 if (*local_default_namespace ==
'\0') {
1055 inherited_ns =
NULL;
1057 inherited_ns = local_default_namespace;
1063 else if (local_default_namespace ==
NULL || !dom_xml_str_equals_treat_nulls_as_empty(local_default_namespace, ns)) {
1065 ignore_namespace_definition_attribute =
true;
1068 qualified_name.name = element->name;
1074 TRY_OR_CLEANUP(dom_xml_output_qname(ctx->out, &qualified_name));
1077 TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out,
" xmlns=\""));
1078 TRY_OR_CLEANUP(dom_xml_common_text_serialization(ctx->out, (
const char *) ns,
true));
1079 TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out,
"\""));
1083 qualified_name.name = element->name;
1085 TRY_OR_CLEANUP(dom_xml_output_qname(ctx->out, &qualified_name));
1091 TRY_OR_CLEANUP(dom_xml_serialize_attributes(ctx->out, element, &map, &local_prefixes_map, prefix_index, ignore_namespace_definition_attribute, require_well_formed));
1095 if (element->children ==
NULL) {
1096 if (xmlSaveNoEmptyTags) {
1099 size_t name_length =
strlen((
const char *) element->name);
1100 if (dom_local_name_compare_ex(element,
"area",
strlen(
"area"), name_length)
1101 || dom_local_name_compare_ex(element,
"base",
strlen(
"base"), name_length)
1102 || dom_local_name_compare_ex(element,
"basefont",
strlen(
"basefont"), name_length)
1103 || dom_local_name_compare_ex(element,
"bgsound",
strlen(
"bgsound"), name_length)
1104 || dom_local_name_compare_ex(element,
"br",
strlen(
"br"), name_length)
1105 || dom_local_name_compare_ex(element,
"col",
strlen(
"col"), name_length)
1106 || dom_local_name_compare_ex(element,
"embed",
strlen(
"embed"), name_length)
1107 || dom_local_name_compare_ex(element,
"frame",
strlen(
"frame"), name_length)
1108 || dom_local_name_compare_ex(element,
"hr",
strlen(
"hr"), name_length)
1109 || dom_local_name_compare_ex(element,
"img",
strlen(
"img"), name_length)
1110 || dom_local_name_compare_ex(element,
"input",
strlen(
"input"), name_length)
1111 || dom_local_name_compare_ex(element,
"keygen",
strlen(
"keygen"), name_length)
1112 || dom_local_name_compare_ex(element,
"link",
strlen(
"link"), name_length)
1113 || dom_local_name_compare_ex(element,
"menuitem",
strlen(
"menuitem"), name_length)
1114 || dom_local_name_compare_ex(element,
"meta",
strlen(
"meta"), name_length)
1115 || dom_local_name_compare_ex(element,
"param",
strlen(
"param"), name_length)
1116 || dom_local_name_compare_ex(element,
"source",
strlen(
"source"), name_length)
1117 || dom_local_name_compare_ex(element,
"track",
strlen(
"track"), name_length)
1118 || dom_local_name_compare_ex(element,
"wbr",
strlen(
"wbr"), name_length)) {
1119 TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out,
" /"));
1120 skip_end_tag =
true;
1125 TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out,
"/"));
1126 skip_end_tag =
true;
1131 TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out,
">"));
1134 if (!skip_end_tag) {
1135 if (should_format) {
1144 xmlNodePtr child =
NULL;
1146 if (ctx->private_data !=
NULL) {
1150 child = element->children;
1154 for (; child !=
NULL; child = child->next) {
1155 if (should_format) {
1156 TRY_OR_CLEANUP(dom_xml_output_indents(ctx->out, indent));
1158 TRY_OR_CLEANUP(dom_xml_serialization_algorithm(ctx, &map, child, inherited_ns, prefix_index, indent, require_well_formed));
1161 if (should_format) {
1163 TRY_OR_CLEANUP(dom_xml_output_indents(ctx->out, indent));
1167 TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out,
"</"));
1168 TRY_OR_CLEANUP(dom_xml_output_qname(ctx->out, &qualified_name));
1169 TRY_OR_CLEANUP(xmlOutputBufferWriteLit(ctx->out,
">"));
1174 dom_xml_ns_prefix_map_dtor(&map);
1175 dom_xml_local_prefix_map_dtor(&local_prefixes_map);
1179 dom_xml_ns_prefix_map_dtor(&map);
1180 dom_xml_local_prefix_map_dtor(&local_prefixes_map);
1185static int dom_xml_serializing_a_document_fragment_node(
1186 dom_xml_serialize_ctx *ctx,
1187 dom_xml_ns_prefix_map *namespace_prefix_map,
1189 const xmlChar *
namespace,
1190 unsigned int *prefix_index,
1192 bool require_well_formed
1199 xmlNodePtr child = node->children;
1200 while (child !=
NULL) {
1201 TRY(dom_xml_serialization_algorithm(ctx, namespace_prefix_map, child,
namespace, prefix_index, indent, require_well_formed));
1202 child = child->next;
1211static int dom_xml_serializing_a_document_node(
1212 dom_xml_serialize_ctx *ctx,
1213 dom_xml_ns_prefix_map *namespace_prefix_map,
1215 const xmlChar *
namespace,
1216 unsigned int *prefix_index,
1218 bool require_well_formed
1224 xmlNodePtr child = node->children;
1225 node->children =
NULL;
1228 TRY(xmlOutputBufferFlush(ctx->out));
1229 TRY(xmlSaveDoc(ctx->ctxt, (xmlDocPtr) node));
1230 TRY(xmlSaveFlush(ctx->ctxt));
1232 node->children = child;
1236 while (child !=
NULL) {
1237 TRY(dom_xml_serialization_algorithm(ctx, namespace_prefix_map, child,
namespace, prefix_index, indent, require_well_formed));
1238 child = child->next;
1247static int dom_xml_serialization_algorithm(
1248 dom_xml_serialize_ctx *ctx,
1249 dom_xml_ns_prefix_map *namespace_prefix_map,
1251 const xmlChar *
namespace,
1252 unsigned int *prefix_index,
1254 bool require_well_formed
1258 switch (node->type) {
1260 return dom_xml_serialize_element_node(ctx,
namespace, namespace_prefix_map, node, prefix_index, indent, require_well_formed);
1263 return dom_xml_serializing_a_document_fragment_node(ctx, namespace_prefix_map, node,
namespace, prefix_index, indent, require_well_formed);
1267 return dom_xml_serializing_a_document_node(ctx, namespace_prefix_map, node,
namespace, prefix_index, indent, require_well_formed);
1270 return dom_xml_serialize_text_node(ctx->out, node, require_well_formed);
1273 return dom_xml_serialize_comment_node(ctx->out, node, require_well_formed);
1276 return dom_xml_serialize_processing_instruction(ctx->out, node, require_well_formed);
1279 return dom_xml_serialize_cdata_section_node(ctx->out, node);
1282 return dom_xml_serialize_attribute_node(ctx->out, node);
1285 TRY(xmlOutputBufferFlush(ctx->out));
1286 TRY(xmlSaveTree(ctx->ctxt, node));
1287 TRY(xmlSaveFlush(ctx->ctxt));
1289 return xmlOutputBufferWriteLit(ctx->out,
"\n");
1301 const xmlChar *
namespace =
NULL;
1304 dom_xml_ns_prefix_map namespace_prefix_map;
1305 dom_xml_ns_prefix_map_ctor(&namespace_prefix_map);
1311 unsigned int prefix_index = 1;
1314 dom_xml_serialize_ctx ctx;
1317 ctx.private_data = private_data;
1318 int indent = format ? 0 : -1;
1319 int result = dom_xml_serialization_algorithm(&ctx, &namespace_prefix_map, node,
namespace, &prefix_index, indent, require_well_formed);
1321 dom_xml_ns_prefix_map_dtor(&namespace_prefix_map);
strstr(string $haystack, string $needle, bool $before_needle=false)
strcspn(string $string, string $characters, int $offset=0, ?int $length=null)
strchr(string $haystack, string $needle, bool $before_needle=false)
#define DOM_Z_IS_OWNED(z)
#define DOM_Z_UNOWNED(z, v)
#define DOM_Z_OWNED(z, v)
PHP_DOM_EXPORT const php_dom_ns_magic_token * php_dom_ns_is_html_magic_token
PHP_DOM_EXPORT const php_dom_ns_magic_token * php_dom_ns_is_xmlns_magic_token
PHP_DOM_EXPORT bool php_dom_ns_is_fast(const xmlNode *nodep, const php_dom_ns_magic_token *magic_token)
PHP_DOM_EXPORT const php_dom_ns_magic_token * php_dom_ns_is_xml_magic_token
const XML_HTML_DOCUMENT_NODE
const XML_CDATA_SECTION_NODE
const XML_DOCUMENT_FRAG_NODE
const XML_ENTITY_REF_NODE
unsigned const char * text
unsigned char key[REFLECTION_KEY_LEN]
struct php_dom_private_data php_dom_private_data
xmlNodePtr php_dom_retrieve_templated_content(php_dom_private_data *private_data, const xmlNode *template_node)
int dom_xml_serialize(xmlSaveCtxtPtr ctx, xmlOutputBufferPtr out, xmlNodePtr node, bool format, bool require_well_formed, php_dom_private_data *private_data)
#define ALLOC_HASHTABLE(ht)
strcmp(string $string1, string $string2)
zend_string_release_ex(func->internal_function.function_name, 0)
#define strcasecmp(s1, s2)
ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht)
ZEND_API zval *ZEND_FASTCALL zend_hash_next_index_insert_new(HashTable *ht, zval *pData)
ZEND_API HashTable *ZEND_FASTCALL zend_array_dup(HashTable *source)
ZEND_API zval *ZEND_FASTCALL zend_hash_add_empty_element(HashTable *ht, zend_string *key)
#define zend_hash_init(ht, nSize, pHashFunction, pDestructor, persistent)
#define ZEND_HASH_MAP_FOREACH_PTR(ht, _ptr)
#define ZEND_HASH_PACKED_FOREACH_PTR(ht, _ptr)
#define ZEND_HASH_PACKED_REVERSE_FOREACH_PTR(ht, _ptr)
#define ZEND_HASH_PACKED_FOREACH_VAL(ht, _val)
#define ZEND_HASH_FOREACH_END()
struct _zend_string zend_string
#define EXPECTED(condition)
#define zend_always_inline
#define ZEND_UNREACHABLE()
ZEND_API zend_string * zend_string_concat3(const char *str1, size_t str1_len, const char *str2, size_t str2_len, const char *str3, size_t str3_len)
struct _zend_array HashTable