php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
html5_parser.c
Go to the documentation of this file.
1/*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Authors: Niels Dossche <nielsdos@php.net> |
14 +----------------------------------------------------------------------+
15*/
16
17#ifdef HAVE_CONFIG_H
18#include <config.h>
19#endif
20
21#include "php.h"
22#if defined(HAVE_LIBXML) && defined(HAVE_DOM)
23#include "php_dom.h"
24#include "html5_parser.h"
25#include "private_data.h"
26#include <lexbor/html/parser.h>
29#include <lexbor/dom/dom.h>
30#include <libxml/parserInternals.h>
31#include <libxml/HTMLtree.h>
32
33#define WORK_LIST_INIT_SIZE 128
34/* libxml2 reserves 2 pointer-sized words for interned strings */
35#define LXML_INTERNED_STRINGS_SIZE (sizeof(void *) * 2)
36
37typedef struct work_list_item {
38 lxb_dom_node_t *node;
39 uintptr_t current_active_namespace;
40 xmlNodePtr lxml_parent;
41 xmlNsPtr lxml_ns;
42} work_list_item;
43
44static void lexbor_libxml2_bridge_work_list_item_push(
45 lexbor_array_obj_t *array,
46 lxb_dom_node_t *node,
47 uintptr_t current_active_namespace,
48 xmlNodePtr lxml_parent,
49 xmlNsPtr lxml_ns
50)
51{
52 work_list_item *item = (work_list_item *) lexbor_array_obj_push_wo_cls(array);
53 item->node = node;
54 item->current_active_namespace = current_active_namespace;
55 item->lxml_parent = lxml_parent;
56 item->lxml_ns = lxml_ns;
57}
58
59static unsigned short sanitize_line_nr(size_t line)
60{
61 if (line > USHRT_MAX) {
62 return USHRT_MAX;
63 }
64 return (unsigned short) line;
65}
66
67struct lxml_ns {
68 const php_dom_ns_magic_token *token;
69 const char *href;
70 size_t href_len;
71};
72
73static struct lxml_ns get_libxml_namespace_href(uintptr_t lexbor_namespace)
74{
75 if (lexbor_namespace == LXB_NS_SVG) {
76 return (struct lxml_ns) { php_dom_ns_is_svg_magic_token, ZEND_STRL(DOM_SVG_NS_URI) };
77 } else if (lexbor_namespace == LXB_NS_MATH) {
79 } else {
80 return (struct lxml_ns) { php_dom_ns_is_html_magic_token, ZEND_STRL(DOM_XHTML_NS_URI) };
81 }
82}
83
84static zend_always_inline xmlNodePtr lexbor_libxml2_bridge_new_text_node_fast(xmlDocPtr lxml_doc, const lxb_char_t *data, size_t data_length, bool compact_text_nodes)
85{
86 if (compact_text_nodes && data_length < LXML_INTERNED_STRINGS_SIZE) {
87 /* See xmlSAX2TextNode() in libxml2 */
88 xmlNodePtr lxml_text = xmlMalloc(sizeof(*lxml_text));
89 if (UNEXPECTED(lxml_text == NULL)) {
90 return NULL;
91 }
92 memset(lxml_text, 0, sizeof(*lxml_text));
93 lxml_text->name = xmlStringText;
94 lxml_text->type = XML_TEXT_NODE;
95 lxml_text->doc = lxml_doc;
96 lxml_text->content = BAD_CAST &lxml_text->properties;
97 if (data != NULL) {
98 memcpy(lxml_text->content, data, data_length);
99 }
100 return lxml_text;
101 } else {
102 return xmlNewDocTextLen(lxml_doc, (const xmlChar *) data, data_length);
103 }
104}
105
106static lexbor_libxml2_bridge_status lexbor_libxml2_bridge_convert(
107 lxb_dom_node_t *start_node,
108 xmlDocPtr lxml_doc,
109 xmlNodePtr root,
110 bool compact_text_nodes,
111 bool create_default_ns,
112 php_dom_private_data *private_data
113)
114{
116
118 xmlNsPtr html_ns = php_dom_libxml_ns_mapper_ensure_html_ns(ns_mapper);
119 xmlNsPtr xlink_ns = NULL;
120 xmlNsPtr prefixed_xmlns_ns = NULL;
121
122 lexbor_array_obj_t work_list;
123 lexbor_array_obj_init(&work_list, WORK_LIST_INIT_SIZE, sizeof(work_list_item));
124
125 for (lxb_dom_node_t *node = start_node; node != NULL; node = node->prev) {
126 lexbor_libxml2_bridge_work_list_item_push(&work_list, node, LXB_NS__UNDEF, root, NULL);
127 }
128
129 work_list_item *current_stack_item;
130 while ((current_stack_item = lexbor_array_obj_pop(&work_list)) != NULL) {
131 lxb_dom_node_t *node = current_stack_item->node;
132 xmlNodePtr lxml_parent = current_stack_item->lxml_parent;
133
134 /* CDATA section and processing instructions don't occur in parsed HTML documents.
135 * The historical types are not emitted by the parser either. */
136 if (node->type == LXB_DOM_NODE_TYPE_ELEMENT) {
137 /* Note: HTML isn't exactly XML-namespace-aware; as this is an HTML parser we only care about the local name.
138 * If a prefix:name format is used, then the local name will be "prefix:name" and the prefix will be empty.
139 * There is however still somewhat of a concept of namespaces. There are three: HTML (the default), SVG, and MATHML. */
142 ZEND_ASSERT(!element->node.prefix);
143
144 xmlNodePtr lxml_element = xmlNewDocNode(lxml_doc, NULL, name, NULL);
145 if (UNEXPECTED(lxml_element == NULL)) {
147 break;
148 }
149 xmlAddChild(lxml_parent, lxml_element);
150 lxml_element->line = sanitize_line_nr(node->line);
151
152 /* Namespaces, note: namespace switches are uncommon */
153 uintptr_t entering_namespace = element->node.ns;
154 xmlNsPtr current_lxml_ns = current_stack_item->lxml_ns;
155 if (create_default_ns && UNEXPECTED(entering_namespace != current_stack_item->current_active_namespace)) {
156 if (entering_namespace == LXB_NS_HTML) {
157 current_lxml_ns = html_ns;
158 } else {
159 struct lxml_ns ns = get_libxml_namespace_href(entering_namespace);
160 zend_string *uri = zend_string_init(ns.href, ns.href_len, false);
161 current_lxml_ns = php_dom_libxml_ns_mapper_get_ns(ns_mapper, NULL, uri);
162 zend_string_release_ex(uri, false);
163 if (EXPECTED(current_lxml_ns != NULL)) {
164 current_lxml_ns->_private = (void *) ns.token;
165 }
166 }
167 }
168 /* Instead of xmlSetNs() because we know the arguments are valid. Prevents overhead. */
169 lxml_element->ns = current_lxml_ns;
170
171 /* Handle template element by creating a fragment node to contain its children.
172 * Other types of nodes contain their children directly. */
173 xmlNodePtr lxml_child_parent = lxml_element;
174 lxb_dom_node_t *child_node = element->node.last_child;
176 if (create_default_ns) {
177 lxml_child_parent = xmlNewDocFragment(lxml_doc);
178 if (UNEXPECTED(lxml_child_parent == NULL)) {
180 break;
181 }
182
183 lxml_child_parent->parent = lxml_element;
184 dom_add_element_ns_hook(private_data, lxml_element);
185 php_dom_add_templated_content(private_data, lxml_element, lxml_child_parent);
186 }
187
189 if (template->content != NULL) {
190 child_node = template->content->node.last_child;
191 }
192 }
193
194 for (; child_node != NULL; child_node = child_node->prev) {
195 lexbor_libxml2_bridge_work_list_item_push(
196 &work_list,
197 child_node,
198 entering_namespace,
199 lxml_child_parent,
200 current_lxml_ns
201 );
202 }
203
204 xmlAttrPtr last_added_attr = NULL;
205 for (lxb_dom_attr_t *attr = element->first_attr; attr != NULL; attr = attr->next) {
206 /* Same namespace remark as for elements */
207 size_t local_name_length, value_length;
208 const lxb_char_t *local_name = lxb_dom_attr_qualified_name(attr, &local_name_length);
209 if (attr->node.prefix) {
210 const char *pos = strchr((const char *) local_name, ':');
211 if (EXPECTED(pos)) {
212 local_name = (const lxb_char_t *) pos + 1;
213 }
214 }
215 const lxb_char_t *value = lxb_dom_attr_value(attr, &value_length);
216
217 if (UNEXPECTED(local_name_length >= INT_MAX || value_length >= INT_MAX)) {
219 break;
220 }
221
222 xmlAttrPtr lxml_attr = xmlMalloc(sizeof(xmlAttr));
223 if (UNEXPECTED(lxml_attr == NULL)) {
225 break;
226 }
227
228 memset(lxml_attr, 0, sizeof(xmlAttr));
229 lxml_attr->type = XML_ATTRIBUTE_NODE;
230 lxml_attr->parent = lxml_element;
231 lxml_attr->name = xmlDictLookup(lxml_doc->dict, local_name, local_name_length);
232 lxml_attr->doc = lxml_doc;
233 xmlNodePtr lxml_text = lexbor_libxml2_bridge_new_text_node_fast(lxml_doc, value, value_length, true /* Always true for optimization purposes */);
234 if (UNEXPECTED(lxml_text == NULL)) {
235 xmlFreeProp(lxml_attr);
237 break;
238 }
239
240 lxml_attr->children = lxml_attr->last = lxml_text;
241 lxml_text->parent = (xmlNodePtr) lxml_attr;
242
243 if (attr->node.ns == LXB_NS_XMLNS) {
244 if (strcmp((const char *) local_name, "xmlns") != 0) {
245 if (prefixed_xmlns_ns == NULL) {
246 prefixed_xmlns_ns = php_dom_libxml_ns_mapper_get_ns_raw_strings_nullsafe(ns_mapper, "xmlns", DOM_XMLNS_NS_URI);
247 }
248 lxml_attr->ns = prefixed_xmlns_ns;
249 } else {
251 }
252 lxml_attr->ns->_private = (void *) php_dom_ns_is_xmlns_magic_token;
253 } else if (attr->node.ns == LXB_NS_XLINK) {
254 if (xlink_ns == NULL) {
256 xlink_ns->_private = (void *) php_dom_ns_is_xlink_magic_token;
257 }
258 lxml_attr->ns = xlink_ns;
259 }
260
261 if (last_added_attr == NULL) {
262 lxml_element->properties = lxml_attr;
263 } else {
264 last_added_attr->next = lxml_attr;
265 lxml_attr->prev = last_added_attr;
266 }
267 last_added_attr = lxml_attr;
268
269 /* xmlIsID does some other stuff too that is irrelevant here. */
270 if (local_name_length == 2 && local_name[0] == 'i' && local_name[1] == 'd' && attr->node.ns == LXB_NS_HTML) {
271 xmlAddID(NULL, lxml_doc, value, lxml_attr);
272 }
273
274 /* libxml2 doesn't support line numbers on this anyway, it derives them instead, so don't bother */
275 }
276 } else if (node->type == LXB_DOM_NODE_TYPE_TEXT) {
278 const lxb_char_t *data = text->char_data.data.data;
279 size_t data_length = text->char_data.data.length;
280 if (UNEXPECTED(data_length >= INT_MAX)) {
282 break;
283 }
284 xmlNodePtr lxml_text = lexbor_libxml2_bridge_new_text_node_fast(lxml_doc, data, data_length, compact_text_nodes);
285 if (UNEXPECTED(lxml_text == NULL)) {
287 break;
288 }
289 xmlAddChild(lxml_parent, lxml_text);
290 if (node->line >= USHRT_MAX) {
291 lxml_text->line = USHRT_MAX;
292 lxml_text->psvi = (void *) (ptrdiff_t) node->line;
293 } else {
294 lxml_text->line = (unsigned short) node->line;
295 }
296 } else if (node->type == LXB_DOM_NODE_TYPE_DOCUMENT_TYPE) {
299 size_t public_id_len, system_id_len;
300 const lxb_char_t *public_id = lxb_dom_document_type_public_id(doctype, &public_id_len);
301 const lxb_char_t *system_id = lxb_dom_document_type_system_id(doctype, &system_id_len);
302 xmlDtdPtr lxml_dtd = xmlCreateIntSubset(
303 lxml_doc,
304 name,
305 public_id_len ? public_id : NULL,
306 system_id_len ? system_id : NULL
307 );
308 if (UNEXPECTED(lxml_dtd == NULL)) {
310 break;
311 }
312 /* libxml2 doesn't support line numbers on this anyway, it returns -1 instead, so don't bother */
313 } else if (node->type == LXB_DOM_NODE_TYPE_COMMENT) {
315 xmlNodePtr lxml_comment = xmlNewDocComment(lxml_doc, comment->char_data.data.data);
316 if (UNEXPECTED(lxml_comment == NULL)) {
318 break;
319 }
320 xmlAddChild(lxml_parent, lxml_comment);
321 lxml_comment->line = sanitize_line_nr(node->line);
322 }
323 }
324
325 lexbor_array_obj_destroy(&work_list, false);
326 return retval;
327}
328
330{
331 memset(ctx, 0, sizeof(*ctx));
332}
333
336 lexbor_libxml2_bridge_tokenizer_error_reporter tokenizer_error_reporter,
338)
339{
340 ctx->tokenizer_error_reporter = tokenizer_error_reporter;
341 ctx->tree_error_reporter = tree_error_reporter;
342}
343
345 lxb_html_document_t *document,
346 xmlDocPtr *doc_out,
347 bool compact_text_nodes,
348 bool create_default_ns,
349 php_dom_private_data *private_data
350)
351{
352 xmlDocPtr lxml_doc = php_dom_create_html_doc();
353 if (UNEXPECTED(!lxml_doc)) {
355 }
356 lexbor_libxml2_bridge_status status = lexbor_libxml2_bridge_convert(
357 lxb_dom_interface_node(document)->last_child,
358 lxml_doc,
359 (xmlNodePtr) lxml_doc,
360 compact_text_nodes,
361 create_default_ns,
362 private_data
363 );
365 xmlFreeDoc(lxml_doc);
366 return status;
367 }
368 *doc_out = lxml_doc;
370}
371
373 lxb_dom_node_t *start_node,
374 xmlDocPtr lxml_doc,
375 xmlNodePtr *fragment_out,
376 bool compact_text_nodes,
377 bool create_default_ns,
378 php_dom_private_data *private_data
379)
380{
381 xmlNodePtr fragment = xmlNewDocFragment(lxml_doc);
382 if (UNEXPECTED(fragment == NULL)) {
384 }
385 lexbor_libxml2_bridge_status status = lexbor_libxml2_bridge_convert(
386 start_node,
387 lxml_doc,
388 fragment,
389 compact_text_nodes,
390 create_default_ns,
391 private_data
392 );
394 xmlFreeNode(fragment);
395 return status;
396 }
397 *fragment_out = fragment;
399}
400
403 lxb_html_parser_t *parser,
404 const lxb_char_t *input_html,
405 size_t chunk_offset,
406 size_t *error_index_offset_tokenizer,
407 size_t *error_index_offset_tree
408)
409{
410 void *error;
411
412 /* Tokenizer errors */
414 size_t index = *error_index_offset_tokenizer;
415 while ((error = lexbor_array_obj_get(parse_errors, index)) != NULL) {
416 /* See https://github.com/lexbor/lexbor/blob/master/source/lexbor/html/tokenizer/error.h */
417 lxb_html_tokenizer_error_t *token_error = error;
418 if (ctx->tokenizer_error_reporter) {
420 ctx->application_data,
421 token_error,
422 token_error->pos - input_html + chunk_offset
423 );
424 }
425 index++;
426 }
427 *error_index_offset_tokenizer = index;
428
429 /* Tree parser errors */
430 parse_errors = lxb_html_parser_tree(parser)->parse_errors;
431 index = *error_index_offset_tree;
432 while ((error = lexbor_array_obj_get(parse_errors, index)) != NULL) {
433 /* See https://github.com/lexbor/lexbor/blob/master/source/lexbor/html/tree/error.h */
434 lxb_html_tree_error_t *tree_error = error;
435 if (ctx->tree_error_reporter) {
437 ctx->application_data,
438 tree_error,
439 tree_error->line + 1,
440 tree_error->column + 1,
441 tree_error->length
442 );
443 }
444 index++;
445 }
446 *error_index_offset_tree = index;
447}
448
449static php_libxml_quirks_mode dom_translate_quirks_mode(lxb_dom_document_cmode_t quirks_mode)
450{
451 switch (quirks_mode) {
452 case LXB_DOM_DOCUMENT_CMODE_NO_QUIRKS: return PHP_LIBXML_NO_QUIRKS;
453 case LXB_DOM_DOCUMENT_CMODE_LIMITED_QUIRKS: return PHP_LIBXML_LIMITED_QUIRKS;
454 case LXB_DOM_DOCUMENT_CMODE_QUIRKS: return PHP_LIBXML_QUIRKS;
456 }
457}
458
460{
461 observations->has_explicit_html_tag = tree->has_explicit_html_tag;
462 observations->has_explicit_head_tag = tree->has_explicit_head_tag;
463 observations->has_explicit_body_tag = tree->has_explicit_body_tag;
464 observations->quirks_mode = dom_translate_quirks_mode(lxb_dom_interface_document(tree->document)->compat_mode);
465}
466
467#endif /* HAVE_LIBXML && HAVE_DOM */
void * lexbor_array_obj_pop(lexbor_array_obj_t *array)
Definition array_obj.c:147
void * lexbor_array_obj_push_wo_cls(lexbor_array_obj_t *array)
Definition array_obj.c:113
lxb_status_t lexbor_array_obj_init(lexbor_array_obj_t *array, size_t size, size_t struct_size)
Definition array_obj.c:17
lexbor_array_obj_t * lexbor_array_obj_destroy(lexbor_array_obj_t *array, bool self_destroy)
Definition array_obj.c:50
lxb_inline void * lexbor_array_obj_get(const lexbor_array_obj_t *array, size_t idx)
Definition array_obj.h:70
lxb_inline const lxb_char_t * lxb_dom_attr_value(lxb_dom_attr_t *attr, size_t *len)
Definition attr.h:124
strchr(string $haystack, string $needle, bool $before_needle=false)
zend_long ptrdiff_t
DNS_STATUS status
Definition dns_win32.c:49
lxb_inline const lxb_char_t * lxb_dom_document_type_system_id(lxb_dom_document_type_t *doc_type, size_t *len)
lxb_inline const lxb_char_t * lxb_dom_document_type_public_id(lxb_dom_document_type_t *doc_type, size_t *len)
lxb_inline const lxb_char_t * lxb_dom_document_type_name(lxb_dom_document_type_t *doc_type, size_t *len)
struct lxb_dom_document_type lxb_dom_document_type_t
Definition interface.h:42
#define lxb_dom_interface_element(obj)
Definition interface.h:28
#define lxb_dom_interface_node(obj)
Definition interface.h:31
struct lxb_dom_comment lxb_dom_comment_t
Definition interface.h:49
#define lxb_dom_interface_document(obj)
Definition interface.h:25
struct lxb_dom_node lxb_dom_node_t
Definition interface.h:38
#define lxb_dom_interface_comment(obj)
Definition interface.h:24
#define lxb_dom_interface_document_type(obj)
Definition interface.h:27
struct lxb_dom_attr lxb_dom_attr_t
Definition interface.h:40
struct lxb_dom_text lxb_dom_text_t
Definition interface.h:46
struct lxb_dom_element lxb_dom_element_t
Definition interface.h:39
#define lxb_dom_interface_text(obj)
Definition interface.h:34
lxb_dom_document_cmode_t
Definition document.h:21
@ LXB_DOM_DOCUMENT_CMODE_QUIRKS
Definition document.h:23
@ LXB_DOM_DOCUMENT_CMODE_LIMITED_QUIRKS
Definition document.h:24
@ LXB_DOM_DOCUMENT_CMODE_NO_QUIRKS
Definition document.h:22
@ LXB_DOM_NODE_TYPE_COMMENT
Definition node.h:32
@ LXB_DOM_NODE_TYPE_DOCUMENT_TYPE
Definition node.h:34
@ LXB_DOM_NODE_TYPE_ELEMENT
Definition node.h:25
@ LXB_DOM_NODE_TYPE_TEXT
Definition node.h:27
error($message)
Definition ext_skel.php:22
memcpy(ptr1, ptr2, size)
memset(ptr, 0, type->size)
new_type attr
Definition ffi.c:4364
#define NULL
Definition gdcache.h:45
void(* lexbor_libxml2_bridge_tokenizer_error_reporter)(void *application_data, lxb_html_tokenizer_error_t *error, size_t offset)
void lexbor_libxml2_bridge_parse_set_error_callbacks(lexbor_libxml2_bridge_parse_context *ctx, lexbor_libxml2_bridge_tokenizer_error_reporter tokenizer_error_reporter, lexbor_libxml2_bridge_tree_error_reporter tree_error_reporter)
lexbor_libxml2_bridge_status lexbor_libxml2_bridge_convert_fragment(lxb_dom_node_t *start_node, xmlDocPtr lxml_doc, xmlNodePtr *fragment_out, bool compact_text_nodes, bool create_default_ns, php_dom_private_data *private_data)
lexbor_libxml2_bridge_status lexbor_libxml2_bridge_convert_document(lxb_html_document_t *document, xmlDocPtr *doc_out, bool compact_text_nodes, bool create_default_ns, php_dom_private_data *private_data)
lexbor_libxml2_bridge_status
@ LEXBOR_LIBXML2_BRIDGE_STATUS_OVERFLOW
@ LEXBOR_LIBXML2_BRIDGE_STATUS_OOM
@ LEXBOR_LIBXML2_BRIDGE_STATUS_OK
void lexbor_libxml2_bridge_copy_observations(lxb_html_tree_t *tree, lexbor_libxml2_bridge_extracted_observations *observations)
void lexbor_libxml2_bridge_parse_context_init(lexbor_libxml2_bridge_parse_context *ctx)
void lexbor_libxml2_bridge_report_errors(const lexbor_libxml2_bridge_parse_context *ctx, lxb_html_parser_t *parser, const lxb_char_t *input_html, size_t chunk_offset, size_t *error_index_offset_tokenizer, size_t *error_index_offset_tree)
void(* lexbor_libxml2_bridge_tree_error_reporter)(void *application_data, lxb_html_tree_error_t *error, size_t line, size_t column, size_t len)
struct lxb_html_tree lxb_html_tree_t
Definition base.h:28
struct lxb_html_template_element lxb_html_template_element_t
Definition interface.h:159
#define lxb_html_interface_template(obj)
Definition interface.h:84
struct lxb_html_document lxb_html_document_t
Definition interface.h:95
lxb_inline lxb_html_tokenizer_t * lxb_html_parser_tokenizer(lxb_html_parser_t *parser)
Definition parser.h:108
lxb_inline lxb_html_tree_t * lxb_html_parser_tree(lxb_html_parser_t *parser)
Definition parser.h:114
const lxb_char_t * lxb_dom_attr_qualified_name(lxb_dom_attr_t *attr, size_t *len)
Definition attr.c:463
const lxb_char_t * lxb_dom_element_qualified_name(lxb_dom_element_t *element, size_t *len)
Definition element.c:651
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 xmlNsPtr php_dom_libxml_ns_mapper_ensure_html_ns(php_dom_libxml_ns_mapper *mapper)
#define DOM_XLINK_NS_URI
PHP_DOM_EXPORT const php_dom_ns_magic_token * php_dom_ns_is_xlink_magic_token
struct php_dom_ns_magic_token php_dom_ns_magic_token
PHP_DOM_EXPORT xmlNsPtr php_dom_libxml_ns_mapper_ensure_prefixless_xmlns_ns(php_dom_libxml_ns_mapper *mapper)
PHP_DOM_EXPORT xmlNsPtr php_dom_libxml_ns_mapper_get_ns(php_dom_libxml_ns_mapper *mapper, zend_string *prefix, zend_string *uri)
PHP_DOM_EXPORT const php_dom_ns_magic_token * php_dom_ns_is_svg_magic_token
#define DOM_MATHML_NS_URI
PHP_DOM_EXPORT const php_dom_ns_magic_token * php_dom_ns_is_mathml_magic_token
#define DOM_XHTML_NS_URI
PHP_DOM_EXPORT xmlNsPtr php_dom_libxml_ns_mapper_get_ns_raw_strings_nullsafe(php_dom_libxml_ns_mapper *mapper, const char *prefix, const char *uri)
#define DOM_SVG_NS_URI
#define DOM_XMLNS_NS_URI
@ LXB_NS_MATH
Definition const.h:27
@ LXB_NS__UNDEF
Definition const.h:24
@ LXB_NS_XMLNS
Definition const.h:31
@ LXB_NS_SVG
Definition const.h:28
@ LXB_NS_XLINK
Definition const.h:29
@ LXB_NS_HTML
Definition const.h:26
#define INT_MAX
Definition php.h:237
xmlDocPtr php_dom_create_html_doc(void)
const XML_TEXT_NODE
const XML_ATTRIBUTE_NODE
int line
Definition php_ffi.h:54
unsigned const char * pos
Definition php_ffi.h:52
unsigned const char * text
Definition php_ffi.h:53
zend_constant * data
void php_dom_add_templated_content(php_dom_private_data *private_data, const xmlNode *template_node, xmlNodePtr fragment)
php_dom_libxml_ns_mapper * php_dom_ns_mapper_from_private(php_dom_private_data *private_data)
void dom_add_element_ns_hook(php_dom_private_data *private_data, xmlNodePtr element)
lexbor_libxml2_bridge_tree_error_reporter tree_error_reporter
lexbor_libxml2_bridge_tokenizer_error_reporter tokenizer_error_reporter
lxb_char_t * data
Definition str.h:47
lxb_dom_character_data_t char_data
Definition comment.h:19
lxb_dom_node_t node
Definition element.h:33
lxb_dom_attr_t * first_attr
Definition element.h:45
lxb_dom_node_t * prev
Definition node.h:53
uintptr_t ns
Definition node.h:48
uintptr_t prefix
Definition node.h:47
lxb_dom_node_t * last_child
Definition node.h:56
lxb_dom_node_type_t type
Definition node.h:59
size_t line
Definition node.h:61
const lxb_char_t * pos
Definition error.h:124
lexbor_array_obj_t * parse_errors
Definition tokenizer.h:56
bool has_explicit_html_tag
Definition tree.h:58
bool has_explicit_head_tag
Definition tree.h:59
lexbor_array_obj_t * parse_errors
Definition tree.h:53
lxb_html_document_t * document
Definition tree.h:42
bool has_explicit_body_tag
Definition tree.h:60
@ LXB_TAG_TEMPLATE
Definition const.h:203
lxb_inline bool lxb_html_tree_node_is(lxb_dom_node_t *node, lxb_tag_id_t tag_id)
Definition tree.h:280
unsigned char lxb_char_t
Definition types.h:27
strcmp(string $string1, string $string2)
zend_string_release_ex(func->internal_function.function_name, 0)
struct _zend_string zend_string
#define EXPECTED(condition)
#define zend_always_inline
#define ZEND_ASSERT(c)
#define ZEND_STRL(str)
#define EMPTY_SWITCH_DEFAULT_CASE()
#define UNEXPECTED(condition)
zval retval
zend_string * name
value