PHP_ME(domcharacterdata, insertData, arginfo_class_DOMCharacterData_insertData, ZEND_ACC_PUBLIC)
PHP_ME(domcharacterdata, deleteData, arginfo_class_DOMCharacterData_deleteData, ZEND_ACC_PUBLIC)
PHP_ME(domcharacterdata, replaceData, arginfo_class_DOMCharacterData_replaceData, ZEND_ACC_PUBLIC)
+ PHP_ME(domcharacterdata, remove, arginfo_class_DOMChildNode_remove, ZEND_ACC_PUBLIC)
+ PHP_ME(domcharacterdata, after, arginfo_class_DOMChildNode_after, ZEND_ACC_PUBLIC)
+ PHP_ME(domcharacterdata, before, arginfo_class_DOMChildNode_before, ZEND_ACC_PUBLIC)
+ PHP_ME(domcharacterdata, replaceWith, arginfo_class_DOMChildNode_replaceWith, ZEND_ACC_PUBLIC)
PHP_FE_END
};
}
/* }}} end dom_characterdata_replace_data */
+PHP_METHOD(domcharacterdata, remove)
+{
+ zval *id = ZEND_THIS;
+ xmlNodePtr children, child;
+ dom_object *intern;
+ int stricterror;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ RETURN_THROWS();
+ }
+
+ DOM_GET_OBJ(child, id, xmlNodePtr, intern);
+
+ if (dom_node_children_valid(child) == FAILURE) {
+ RETURN_NULL();
+ }
+
+ stricterror = dom_get_strict_error(intern->document);
+
+ if (dom_node_is_read_only(child) == SUCCESS ||
+ (child->parent != NULL && dom_node_is_read_only(child->parent) == SUCCESS)) {
+ php_dom_throw_error(NO_MODIFICATION_ALLOWED_ERR, stricterror);
+ RETURN_NULL();
+ }
+
+ if (!child->parent) {
+ php_dom_throw_error(NOT_FOUND_ERR, stricterror);
+ RETURN_NULL();
+ }
+
+ children = child->parent->children;
+ if (!children) {
+ php_dom_throw_error(NOT_FOUND_ERR, stricterror);
+ RETURN_NULL();
+ }
+
+ while (children) {
+ if (children == child) {
+ xmlUnlinkNode(child);
+ RETURN_NULL();
+ }
+ children = children->next;
+ }
+
+ php_dom_throw_error(NOT_FOUND_ERR, stricterror);
+ RETURN_NULL();
+}
+
+PHP_METHOD(domcharacterdata, after)
+{
+ int argc;
+ zval *args, *id;
+ dom_object *intern;
+ xmlNode *context;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
+ RETURN_THROWS();
+ }
+
+ id = ZEND_THIS;
+ DOM_GET_OBJ(context, id, xmlNodePtr, intern);
+
+ dom_parent_node_after(intern, args, argc);
+}
+
+PHP_METHOD(domcharacterdata, before)
+{
+ int argc;
+ zval *args, *id;
+ dom_object *intern;
+ xmlNode *context;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
+ RETURN_THROWS();
+ }
+
+ id = ZEND_THIS;
+ DOM_GET_OBJ(context, id, xmlNodePtr, intern);
+
+ dom_parent_node_before(intern, args, argc);
+}
+
+PHP_METHOD(domcharacterdata, replaceWith)
+{
+ int argc;
+ zval *args, *id;
+ dom_object *intern;
+ xmlNode *context;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
+ RETURN_THROWS();
+ }
+
+ id = ZEND_THIS;
+ DOM_GET_OBJ(context, id, xmlNodePtr, intern);
+
+ dom_parent_node_after(intern, args, argc);
+ dom_child_node_remove(intern);
+}
+
#endif
PHP_SETUP_LIBXML(DOM_SHARED_LIBADD, [
AC_DEFINE(HAVE_DOM,1,[ ])
PHP_NEW_EXTENSION(dom, [php_dom.c attr.c document.c \
- domexception.c \
+ domexception.c parentnode.c \
processinginstruction.c cdatasection.c \
documentfragment.c domimplementation.c \
element.c node.c characterdata.c \
CHECK_HEADER_ADD_INCLUDE("libxml/parser.h", "CFLAGS_DOM", PHP_PHP_BUILD + "\\include\\libxml2")
) {
EXTENSION("dom", "php_dom.c attr.c document.c \
- domexception.c processinginstruction.c \
+ domexception.c parentnode.c processinginstruction.c \
cdatasection.c documentfragment.c domimplementation.c element.c \
node.c characterdata.c documenttype.c \
entity.c nodelist.c text.c comment.c \
PHP_ME(domdocument, relaxNGValidateSource, arginfo_class_DOMDocument_relaxNGValidateSource, ZEND_ACC_PUBLIC)
#endif
PHP_ME(domdocument, registerNodeClass, arginfo_class_DOMDocument_registerNodeClass, ZEND_ACC_PUBLIC)
+ PHP_ME(domdocument, append, arginfo_class_DOMParentNode_append, ZEND_ACC_PUBLIC)
+ PHP_ME(domdocument, prepend, arginfo_class_DOMParentNode_prepend, ZEND_ACC_PUBLIC)
PHP_FE_END
};
/* }}} */
}
/* }}} */
+/* {{{ proto void domdocument::append(string|DOMNode ...$nodes)
+URL: https://dom.spec.whatwg.org/#dom-parentnode-append
+Since: DOM Living Standard (DOM4)
+*/
+PHP_METHOD(domdocument, append)
+{
+ int argc;
+ zval *args, *id;
+ dom_object *intern;
+ xmlNode *context;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
+ RETURN_THROWS();
+ }
+
+ id = ZEND_THIS;
+ DOM_GET_OBJ(context, id, xmlNodePtr, intern);
+
+ dom_parent_node_append(intern, args, argc);
+}
+/* }}} */
+
+/* {{{ proto void domdocument::prepend(string|DOMNode ...$nodes)
+URL: https://dom.spec.whatwg.org/#dom-parentnode-prepend
+Since: DOM Living Standard (DOM4)
+*/
+PHP_METHOD(domdocument, prepend)
+{
+ int argc;
+ zval *args, *id;
+ dom_object *intern;
+ xmlNode *context;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
+ RETURN_THROWS();
+ }
+
+ id = ZEND_THIS;
+ DOM_GET_OBJ(context, id, xmlNodePtr, intern);
+
+ dom_parent_node_prepend(intern, args, argc);
+}
+/* }}} */
+
#endif /* HAVE_LIBXML && HAVE_DOM */
const zend_function_entry php_dom_documentfragment_class_functions[] = {
PHP_ME(domdocumentfragment, __construct, arginfo_class_DOMDocumentFragment___construct, ZEND_ACC_PUBLIC)
PHP_ME(domdocumentfragment, appendXML, arginfo_class_DOMDocumentFragment_appendXML, ZEND_ACC_PUBLIC)
+ PHP_ME(domdocumentfragment, append, arginfo_class_DOMParentNode_append, ZEND_ACC_PUBLIC)
+ PHP_ME(domdocumentfragment, prepend, arginfo_class_DOMParentNode_prepend, ZEND_ACC_PUBLIC)
PHP_FE_END
};
}
/* }}} */
+/* {{{ proto void domdocumentfragment::append(string|DOMNode ...$nodes)
+URL: https://dom.spec.whatwg.org/#dom-parentnode-append
+Since: DOM Living Standard (DOM4)
+*/
+PHP_METHOD(domdocumentfragment, append)
+{
+ int argc;
+ zval *args, *id;
+ dom_object *intern;
+ xmlNode *context;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
+ RETURN_THROWS();
+ }
+
+ id = ZEND_THIS;
+ DOM_GET_OBJ(context, id, xmlNodePtr, intern);
+
+ dom_parent_node_append(intern, args, argc);
+}
+/* }}} */
+
+/* {{{ proto void domdocumentfragment::prepend(string|DOMNode ...$nodes)
+URL: https://dom.spec.whatwg.org/#dom-parentnode-prepend
+Since: DOM Living Standard (DOM4)
+*/
+PHP_METHOD(domdocumentfragment, prepend)
+{
+ int argc;
+ zval *args, *id;
+ dom_object *intern;
+ xmlNode *context;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
+ RETURN_THROWS();
+ }
+
+ id = ZEND_THIS;
+ DOM_GET_OBJ(context, id, xmlNodePtr, intern);
+
+ dom_parent_node_prepend(intern, args, argc);
+}
+/* }}} */
+
#endif
<?php
+interface DOMChildNode
+{
+ public function remove(): void;
+
+ /** @var ...DOMNode|string $nodes */
+ public function before(... $nodes): void;
+
+ /** @var ...DOMNode|string $nodes */
+ public function after(...$nodes): void;
+
+ /** @var ...DOMNode|string $nodes */
+ public function replaceWith(...$nodes): void;
+}
+
+interface DOMParentNode
+{
+ /** @var ...DOMNode|string $nodes */
+ public function append(...$nodes): void;
+
+ /** @var ...DOMNode|string $nodes */
+ public function prepend(...$nodes): void;
+}
+
class DOMNode {
/** @return DOMNode|false */
public function appendChild(DOMNode $newChild) {}
public function __construct(string $value) {}
}
-class DOMCharacterData {
+class DOMCharacterData implements DOMChildNode {
/** @return bool */
public function appendData(string $data) {}
public function __construct(string $value = "") {}
}
-class DOMDocument {
+class DOMDocument implements DOMParentNode {
public function __construct(string $version = "1.0", string $encoding = UNKNOWN) {}
/** @return DOMAttr|false */
public function adoptNode(DOMNode $source) {}
}
-class DOMDocumentFragment {
+class DOMDocumentFragment implements DOMParentNode {
public function __construct() {}
/** @return bool */
public function appendXML(string $data) {}
}
-class DOMElement {
+class DOMElement implements DOMParentNode, DOMChildNode {
public function __construct(string $name, ?string $value = null, string $uri = "") {}
/** @return string */
/* This is a generated file, edit the .stub.php file instead. */
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_DOMChildNode_remove, 0, 0, IS_VOID, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_DOMChildNode_before, 0, 0, IS_VOID, 0)
+ ZEND_ARG_VARIADIC_INFO(0, nodes)
+ZEND_END_ARG_INFO()
+
+#define arginfo_class_DOMChildNode_after arginfo_class_DOMChildNode_before
+
+#define arginfo_class_DOMChildNode_replaceWith arginfo_class_DOMChildNode_before
+
+#define arginfo_class_DOMParentNode_append arginfo_class_DOMChildNode_before
+
+#define arginfo_class_DOMParentNode_prepend arginfo_class_DOMChildNode_before
+
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_DOMNode_appendChild, 0, 0, 1)
ZEND_ARG_OBJ_INFO(0, newChild, DOMNode, 0)
ZEND_END_ARG_INFO()
#define DOM_FE_H
extern const zend_function_entry php_dom_domexception_class_functions[];
+extern const zend_function_entry php_dom_parent_node_class_functions[];
+extern const zend_function_entry php_dom_child_node_class_functions[];
extern const zend_function_entry php_dom_domimplementation_class_functions[];
extern const zend_function_entry php_dom_documentfragment_class_functions[];
extern const zend_function_entry php_dom_document_class_functions[];
/* domdocumentfragment methods */
PHP_METHOD(domdocumentfragment, __construct);
PHP_METHOD(domdocumentfragment, appendXML);
+PHP_METHOD(domdocumentfragment, append);
+PHP_METHOD(domdocumentfragment, prepend);
/* domdocument methods */
PHP_METHOD(domdocument, createElement);
PHP_METHOD(domdocument, validate);
PHP_METHOD(domdocument, xinclude);
PHP_METHOD(domdocument, registerNodeClass);
+PHP_METHOD(domdocument, append);
+PHP_METHOD(domdocument, prepend);
#if defined(LIBXML_HTML_ENABLED)
PHP_METHOD(domdocument, loadHTML);
PHP_METHOD(domcharacterdata, insertData);
PHP_METHOD(domcharacterdata, deleteData);
PHP_METHOD(domcharacterdata, replaceData);
+PHP_METHOD(domcharacterdata, remove);
+PHP_METHOD(domcharacterdata, after);
+PHP_METHOD(domcharacterdata, before);
+PHP_METHOD(domcharacterdata, replaceWith);
/* domattr methods */
PHP_METHOD(domattr, isId);
PHP_METHOD(domelement, setIdAttributeNS);
PHP_METHOD(domelement, setIdAttributeNode);
PHP_METHOD(domelement, __construct);
+PHP_METHOD(domelement, remove);
+PHP_METHOD(domelement, after);
+PHP_METHOD(domelement, before);
+PHP_METHOD(domelement, append);
+PHP_METHOD(domelement, prepend);
+PHP_METHOD(domelement, replaceWith);
/* domtext methods */
PHP_METHOD(domtext, splitText);
/* namednodemap properties */
int dom_namednodemap_length_read(dom_object *obj, zval *retval);
+/* parent node properties */
+int dom_parent_node_first_element_child_read(dom_object *obj, zval *retval);
+int dom_parent_node_last_element_child_read(dom_object *obj, zval *retval);
+int dom_parent_node_child_element_count(dom_object *obj, zval *retval);
+
/* node properties */
int dom_node_node_name_read(dom_object *obj, zval *retval);
int dom_node_node_value_read(dom_object *obj, zval *retval);
int dom_node_last_child_read(dom_object *obj, zval *retval);
int dom_node_previous_sibling_read(dom_object *obj, zval *retval);
int dom_node_next_sibling_read(dom_object *obj, zval *retval);
+int dom_node_previous_element_sibling_read(dom_object *obj, zval *retval);
+int dom_node_next_element_sibling_read(dom_object *obj, zval *retval);
int dom_node_attributes_read(dom_object *obj, zval *retval);
int dom_node_owner_document_read(dom_object *obj, zval *retval);
int dom_node_namespace_uri_read(dom_object *obj, zval *retval);
PHP_ME(domelement, setIdAttributeNS, arginfo_class_DOMElement_setIdAttributeNS, ZEND_ACC_PUBLIC)
PHP_ME(domelement, setIdAttributeNode, arginfo_class_DOMElement_setIdAttributeNode, ZEND_ACC_PUBLIC)
PHP_ME(domelement, __construct, arginfo_class_DOMElement___construct, ZEND_ACC_PUBLIC)
+ PHP_ME(domelement, remove, arginfo_class_DOMChildNode_remove, ZEND_ACC_PUBLIC)
+ PHP_ME(domelement, after, arginfo_class_DOMChildNode_after, ZEND_ACC_PUBLIC)
+ PHP_ME(domelement, before, arginfo_class_DOMChildNode_before, ZEND_ACC_PUBLIC)
+ PHP_ME(domelement, replaceWith, arginfo_class_DOMChildNode_replaceWith, ZEND_ACC_PUBLIC)
+ PHP_ME(domelement, append, arginfo_class_DOMParentNode_append, ZEND_ACC_PUBLIC)
+ PHP_ME(domelement, prepend, arginfo_class_DOMParentNode_prepend, ZEND_ACC_PUBLIC)
PHP_FE_END
};
/* }}} */
}
/* }}} end dom_element_set_id_attribute_node */
+/* {{{ proto void DOMElement::remove();
+URL:
+Since:
+*/
+PHP_METHOD(domelement, remove)
+{
+ zval *id;
+ xmlNodePtr child;
+ dom_object *intern;
+
+ if (zend_parse_parameters_none() == FAILURE) {
+ RETURN_THROWS();
+ }
+
+ id = ZEND_THIS;
+ DOM_GET_OBJ(child, id, xmlNodePtr, intern);
+
+ dom_child_node_remove(intern);
+}
+/* }}} end DOMElement::remove */
+
+PHP_METHOD(domelement, after)
+{
+ int argc;
+ zval *args, *id;
+ dom_object *intern;
+ xmlNode *context;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
+ RETURN_THROWS();
+ }
+
+ id = ZEND_THIS;
+ DOM_GET_OBJ(context, id, xmlNodePtr, intern);
+
+ dom_parent_node_after(intern, args, argc);
+}
+
+PHP_METHOD(domelement, before)
+{
+ int argc;
+ zval *args, *id;
+ dom_object *intern;
+ xmlNode *context;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
+ RETURN_THROWS();
+ }
+
+ id = ZEND_THIS;
+ DOM_GET_OBJ(context, id, xmlNodePtr, intern);
+
+ dom_parent_node_before(intern, args, argc);
+}
+
+/* {{{ proto void domelement::append(string|DOMNode ...$nodes)
+URL: https://dom.spec.whatwg.org/#dom-parentnode-append
+Since: DOM Living Standard (DOM4)
+*/
+PHP_METHOD(domelement, append)
+{
+ int argc;
+ zval *args, *id;
+ dom_object *intern;
+ xmlNode *context;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
+ RETURN_THROWS();
+ }
+
+ id = ZEND_THIS;
+ DOM_GET_OBJ(context, id, xmlNodePtr, intern);
+
+ dom_parent_node_append(intern, args, argc);
+}
+/* }}} end DOMElement::append */
+
+/* {{{ proto void domelement::prepend(string|DOMNode ...$nodes)
+URL: https://dom.spec.whatwg.org/#dom-parentnode-prepend
+Since: DOM Living Standard (DOM4)
+*/
+PHP_METHOD(domelement, prepend)
+{
+ int argc;
+ zval *args, *id;
+ dom_object *intern;
+ xmlNode *context;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
+ RETURN_THROWS();
+ }
+
+ id = ZEND_THIS;
+ DOM_GET_OBJ(context, id, xmlNodePtr, intern);
+
+ dom_parent_node_prepend(intern, args, argc);
+}
+/* }}} end DOMElement::prepend */
+
+/* {{{ proto void domelement::replaceWith(string|DOMNode ...$nodes)
+URL: https://dom.spec.whatwg.org/#dom-parentnode-prepend
+Since: DOM Living Standard (DOM4)
+*/
+PHP_METHOD(domelement, replaceWith)
+{
+ int argc;
+ zval *args, *id;
+ dom_object *intern;
+ xmlNode *context;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argc) == FAILURE) {
+ RETURN_THROWS();
+ }
+
+ id = ZEND_THIS;
+ DOM_GET_OBJ(context, id, xmlNodePtr, intern);
+
+ dom_parent_node_after(intern, args, argc);
+ dom_child_node_remove(intern);
+}
+/* }}} end DOMElement::prepend */
+
#endif
};
/* }}} */
-static void dom_reconcile_ns(xmlDocPtr doc, xmlNodePtr nodep) /* {{{ */
-{
- xmlNsPtr nsptr, nsdftptr, curns, prevns = NULL;
-
- if (nodep->type == XML_ELEMENT_NODE) {
- /* Following if block primarily used for inserting nodes created via createElementNS */
- if (nodep->nsDef != NULL) {
- curns = nodep->nsDef;
- while (curns) {
- nsdftptr = curns->next;
- if (curns->href != NULL) {
- if((nsptr = xmlSearchNsByHref(doc, nodep->parent, curns->href)) &&
- (curns->prefix == NULL || xmlStrEqual(nsptr->prefix, curns->prefix))) {
- curns->next = NULL;
- if (prevns == NULL) {
- nodep->nsDef = nsdftptr;
- } else {
- prevns->next = nsdftptr;
- }
- dom_set_old_ns(doc, curns);
- curns = prevns;
- }
- }
- prevns = curns;
- curns = nsdftptr;
- }
- }
- xmlReconciliateNs(doc, nodep);
- }
-}
+const zend_function_entry php_dom_child_node_class_functions[] = { /* {{{ */
+ PHP_ABSTRACT_ME(DOMChildNode, remove, arginfo_class_DOMChildNode_remove)
+ PHP_ABSTRACT_ME(DOMChildNode, after, arginfo_class_DOMChildNode_after)
+ PHP_ABSTRACT_ME(DOMChildNode, before, arginfo_class_DOMChildNode_before)
+ PHP_FE_END
+};
/* }}} */
/* {{{ nodeName string
return SUCCESS;
}
-
/* }}} */
/* {{{ firstChild DomNode
/* }}} */
+/* {{{ previousElementSibling DomNode
+readonly=yes
+URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-640FB3C8
+Since:
+*/
+int dom_node_previous_element_sibling_read(dom_object *obj, zval *retval)
+{
+ xmlNode *nodep, *prevsib;
+
+ nodep = dom_object_get_node(obj);
+
+ if (nodep == NULL) {
+ php_dom_throw_error(INVALID_STATE_ERR, 0);
+ return FAILURE;
+ }
+
+ prevsib = nodep->prev;
+
+ while (prevsib && prevsib->type != XML_ELEMENT_NODE) {
+ prevsib = prevsib->prev;
+ }
+
+ if (!prevsib) {
+ ZVAL_NULL(retval);
+ return SUCCESS;
+ }
+
+ php_dom_create_object(prevsib, retval, obj);
+ return SUCCESS;
+}
+
+/* }}} */
+
+/* {{{ nextElementSibling DomNode
+readonly=yes
+URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-6AC54C2F
+Since:
+*/
+int dom_node_next_element_sibling_read(dom_object *obj, zval *retval)
+{
+ xmlNode *nodep, *nextsib;
+
+ nodep = dom_object_get_node(obj);
+
+ if (nodep == NULL) {
+ php_dom_throw_error(INVALID_STATE_ERR, 0);
+ return FAILURE;
+ }
+
+ nextsib = nodep->next;
+
+ while (nextsib != NULL && nextsib->type != XML_ELEMENT_NODE) {
+ nextsib = nextsib->next;
+ }
+
+ if (!nextsib) {
+ ZVAL_NULL(retval);
+ return SUCCESS;
+ }
+
+ php_dom_create_object(nextsib, retval, obj);
+ return SUCCESS;
+}
+
+/* }}} */
+
/* {{{ attributes DomNamedNodeMap
readonly=yes
URL: http://www.w3.org/TR/2003/WD-DOM-Level-3-Core-20030226/DOM3-Core.html#core-ID-84CF096
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 7 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Benjamin Eberlei <beberlei@php.net> |
+ +----------------------------------------------------------------------+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+#if HAVE_LIBXML && HAVE_DOM
+#include "php_dom.h"
+#include "dom_arginfo.h"
+
+
+/* {{{ DOMParentNode methods */
+const zend_function_entry php_dom_parent_node_class_functions[] = { /* {{{ */
+ PHP_ABSTRACT_ME(DOMParentNode, append, arginfo_class_DOMParentNode_append)
+ PHP_ABSTRACT_ME(DOMParentNode, prepend, arginfo_class_DOMParentNode_prepend)
+ PHP_FE_END
+};
+/* }}} */
+
+/* {{{ firstElementChild DomParentNode
+readonly=yes
+URL: https://www.w3.org/TR/dom/#dom-parentnode-firstelementchild
+*/
+int dom_parent_node_first_element_child_read(dom_object *obj, zval *retval)
+{
+ xmlNode *nodep, *first = NULL;
+
+ nodep = dom_object_get_node(obj);
+
+ if (nodep == NULL) {
+ php_dom_throw_error(INVALID_STATE_ERR, 0);
+ return FAILURE;
+ }
+
+ if (dom_node_children_valid(nodep) == SUCCESS) {
+ first = nodep->children;
+
+ while (first && first->type != XML_ELEMENT_NODE) {
+ first = first->next;
+ }
+ }
+
+ if (!first) {
+ ZVAL_NULL(retval);
+ return SUCCESS;
+ }
+
+ php_dom_create_object(first, retval, obj);
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ lastElementChild DomParentNode
+readonly=yes
+URL: https://www.w3.org/TR/dom/#dom-parentnode-lastelementchild
+*/
+int dom_parent_node_last_element_child_read(dom_object *obj, zval *retval)
+{
+ xmlNode *nodep, *last = NULL;
+
+ nodep = dom_object_get_node(obj);
+
+ if (nodep == NULL) {
+ php_dom_throw_error(INVALID_STATE_ERR, 0);
+ return FAILURE;
+ }
+
+ if (dom_node_children_valid(nodep) == SUCCESS) {
+ last = nodep->last;
+
+ while (last && last->type != XML_ELEMENT_NODE) {
+ last = last->prev;
+ }
+ }
+
+ if (!last) {
+ ZVAL_NULL(retval);
+ return SUCCESS;
+ }
+
+ php_dom_create_object(last, retval, obj);
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ childElementCount DomParentNode
+readonly=yes
+https://www.w3.org/TR/dom/#dom-parentnode-childelementcount
+*/
+int dom_parent_node_child_element_count(dom_object *obj, zval *retval)
+{
+ xmlNode *nodep, *first = NULL;
+ zend_long count = 0;
+
+ nodep = dom_object_get_node(obj);
+
+ if (nodep == NULL) {
+ php_dom_throw_error(INVALID_STATE_ERR, 0);
+ return FAILURE;
+ }
+
+ if (dom_node_children_valid(nodep) == SUCCESS) {
+ first = nodep->children;
+
+ while (first != NULL) {
+ if (first->type == XML_ELEMENT_NODE) {
+ count++;
+ }
+
+ first = first->next;
+ }
+ }
+
+ ZVAL_LONG(retval, count);
+
+ return SUCCESS;
+}
+/* }}} */
+
+xmlNode* dom_zvals_to_fragment(php_libxml_ref_obj *document, xmlNode *contextNode, zval *nodes, int nodesc)
+{
+ int i;
+ xmlDoc *documentNode;
+ xmlNode *fragment;
+ xmlNode *newNode;
+ zend_class_entry *ce;
+ dom_object *newNodeObj;
+ int stricterror;
+
+ if (contextNode->type == XML_DOCUMENT_NODE || contextNode->type == XML_HTML_DOCUMENT_NODE) {
+ documentNode = (xmlDoc *) contextNode;
+ } else {
+ documentNode = contextNode->doc;
+ }
+
+ fragment = xmlNewDocFragment(documentNode);
+
+ if (!fragment) {
+ return NULL;
+ }
+
+ stricterror = dom_get_strict_error(document);
+
+ for (i = 0; i < nodesc; i++) {
+ if (Z_TYPE(nodes[i]) == IS_OBJECT) {
+ ce = Z_OBJCE(nodes[i]);
+
+ if (instanceof_function(ce, dom_node_class_entry)) {
+ newNodeObj = Z_DOMOBJ_P(&nodes[i]);
+ newNode = dom_object_get_node(newNodeObj);
+
+ if (newNode->doc != documentNode) {
+ php_dom_throw_error(WRONG_DOCUMENT_ERR, stricterror);
+ return NULL;
+ }
+
+ if (newNode->parent != NULL) {
+ xmlUnlinkNode(newNode);
+ }
+
+ newNodeObj->document = document;
+ xmlSetTreeDoc(newNode, documentNode);
+
+ if (!xmlAddChild(fragment, newNode)) {
+ xmlFree(fragment);
+
+ php_dom_throw_error(HIERARCHY_REQUEST_ERR, stricterror);
+ return NULL;
+ }
+
+ continue;
+ } else {
+ xmlFree(fragment);
+
+ zend_type_error("Invalid argument type must be either DOMNode or string");
+ return NULL;
+ }
+ } else if (Z_TYPE(nodes[i]) == IS_STRING) {
+ newNode = xmlNewDocText(documentNode, (xmlChar *) Z_STRVAL(nodes[i]));
+
+ xmlSetTreeDoc(newNode, documentNode);
+
+ if (!xmlAddChild(fragment, newNode)) {
+ xmlFree(fragment);
+
+ return NULL;
+ }
+ } else {
+ xmlFree(fragment);
+
+ zend_type_error("Invalid argument type must be either DOMNode or string");
+
+ return NULL;
+ }
+ }
+
+ return fragment;
+}
+
+static void dom_fragment_assign_parent_node(xmlNodePtr parentNode, xmlNodePtr fragment)
+{
+ xmlNodePtr node = fragment->children;
+
+ while (node != NULL) {
+ node->parent = parentNode;
+
+ if (node == fragment->last) {
+ break;
+ }
+ node = node->next;
+ }
+
+ fragment->children = NULL;
+ fragment->last = NULL;
+}
+
+void dom_parent_node_append(dom_object *context, zval *nodes, int nodesc)
+{
+ xmlNode *parentNode = dom_object_get_node(context);
+ xmlNodePtr newchild, prevsib;
+ xmlNode *fragment = dom_zvals_to_fragment(context->document, parentNode, nodes, nodesc);
+
+ if (fragment == NULL) {
+ return;
+ }
+
+ newchild = fragment->children;
+ prevsib = parentNode->last;
+
+ if (newchild) {
+ if (prevsib != NULL) {
+ prevsib->next = newchild;
+ } else {
+ parentNode->children = newchild;
+ }
+
+ parentNode->last = fragment->last;
+
+ newchild->prev = prevsib;
+
+ dom_fragment_assign_parent_node(parentNode, fragment);
+
+ dom_reconcile_ns(parentNode->doc, newchild);
+ }
+
+ xmlFree(fragment);
+}
+
+void dom_parent_node_prepend(dom_object *context, zval *nodes, int nodesc)
+{
+ xmlNode *parentNode = dom_object_get_node(context);
+
+ if (parentNode->children == NULL) {
+ dom_parent_node_append(context, nodes, nodesc);
+ return;
+ }
+
+ xmlNodePtr newchild, nextsib;
+ xmlNode *fragment = dom_zvals_to_fragment(context->document, parentNode, nodes, nodesc);
+
+ if (fragment == NULL) {
+ return;
+ }
+
+ newchild = fragment->children;
+ nextsib = parentNode->children;
+
+ if (newchild) {
+ parentNode->children = newchild;
+ fragment->last->next = nextsib;
+ nextsib->prev = fragment->last;
+
+ dom_fragment_assign_parent_node(parentNode, fragment);
+
+ dom_reconcile_ns(parentNode->doc, newchild);
+ }
+
+ xmlFree(fragment);
+}
+
+void dom_parent_node_after(dom_object *context, zval *nodes, int nodesc)
+{
+ xmlNode *prevsib = dom_object_get_node(context);
+ xmlNodePtr newchild, parentNode;
+ xmlNode *fragment;
+
+ int stricterror = dom_get_strict_error(context->document);
+
+ if (!prevsib->parent) {
+ php_dom_throw_error(NO_MODIFICATION_ALLOWED_ERR, stricterror);
+ return;
+ }
+
+ parentNode = prevsib->parent;
+ fragment = dom_zvals_to_fragment(context->document, parentNode, nodes, nodesc);
+
+ if (fragment == NULL) {
+ return;
+ }
+
+ newchild = fragment->children;
+
+ if (newchild) {
+ fragment->last->next = prevsib->next;
+ prevsib->next = newchild;
+
+ newchild->prev = prevsib;
+
+ dom_fragment_assign_parent_node(parentNode, fragment);
+ dom_reconcile_ns(prevsib->doc, newchild);
+ }
+
+ xmlFree(fragment);
+}
+
+void dom_parent_node_before(dom_object *context, zval *nodes, int nodesc)
+{
+ xmlNode *nextsib = dom_object_get_node(context);
+ xmlNodePtr newchild, prevsib, parentNode;
+ xmlNode *fragment;
+
+ prevsib = nextsib->prev;
+ parentNode = nextsib->parent;
+ fragment = dom_zvals_to_fragment(context->document, parentNode, nodes, nodesc);
+
+ if (fragment == NULL) {
+ return;
+ }
+
+ newchild = fragment->children;
+
+ if (newchild) {
+ if (parentNode->children == nextsib) {
+ parentNode->children = newchild;
+ } else {
+ prevsib->next = newchild;
+ }
+ fragment->last->next = nextsib;
+ nextsib->prev = fragment->last;
+
+ newchild->prev = prevsib;
+
+ dom_fragment_assign_parent_node(parentNode, fragment);
+
+ dom_reconcile_ns(nextsib->doc, newchild);
+ }
+
+ xmlFree(fragment);
+}
+
+void dom_child_node_remove(dom_object *context)
+{
+ xmlNode *child = dom_object_get_node(context);
+ xmlNodePtr children;
+ int stricterror;
+
+ if (dom_node_children_valid(child) == FAILURE) {
+ return;
+ }
+
+ stricterror = dom_get_strict_error(context->document);
+
+ if (dom_node_is_read_only(child) == SUCCESS ||
+ (child->parent != NULL && dom_node_is_read_only(child->parent) == SUCCESS)) {
+ php_dom_throw_error(NO_MODIFICATION_ALLOWED_ERR, stricterror);
+ return;
+ }
+
+ if (!child->parent) {
+ php_dom_throw_error(NOT_FOUND_ERR, stricterror);
+ return;
+ }
+
+ children = child->parent->children;
+ if (!children) {
+ php_dom_throw_error(NOT_FOUND_ERR, stricterror);
+ return;
+ }
+
+ while (children) {
+ if (children == child) {
+ xmlUnlinkNode(child);
+ return;
+ }
+ children = children->next;
+ }
+
+ php_dom_throw_error(NOT_FOUND_ERR, stricterror);
+}
+
+#endif
/* {{{ class entries */
PHP_DOM_EXPORT zend_class_entry *dom_node_class_entry;
PHP_DOM_EXPORT zend_class_entry *dom_domexception_class_entry;
+PHP_DOM_EXPORT zend_class_entry *dom_parentnode_class_entry;
+PHP_DOM_EXPORT zend_class_entry *dom_childnode_class_entry;
PHP_DOM_EXPORT zend_class_entry *dom_domimplementation_class_entry;
PHP_DOM_EXPORT zend_class_entry *dom_documentfragment_class_entry;
PHP_DOM_EXPORT zend_class_entry *dom_document_class_entry;
static HashTable classes;
/* {{{ prop handler tables */
static HashTable dom_document_prop_handlers;
+static HashTable dom_documentfragment_prop_handlers;
static HashTable dom_node_prop_handlers;
static HashTable dom_nodelist_prop_handlers;
static HashTable dom_namednodemap_prop_handlers;
dom_domexception_class_entry->ce_flags |= ZEND_ACC_FINAL;
zend_declare_property_long(dom_domexception_class_entry, "code", sizeof("code")-1, 0, ZEND_ACC_PUBLIC);
+ INIT_CLASS_ENTRY(ce, "DOMParentNode", php_dom_parent_node_class_functions);
+ dom_parentnode_class_entry = zend_register_internal_interface(&ce);
+
+ INIT_CLASS_ENTRY(ce, "DOMChildNode", php_dom_child_node_class_functions);
+ dom_childnode_class_entry = zend_register_internal_interface(&ce);
+
REGISTER_DOM_CLASS(ce, "DOMImplementation", NULL, php_dom_domimplementation_class_functions, dom_domimplementation_class_entry);
REGISTER_DOM_CLASS(ce, "DOMNode", NULL, php_dom_node_class_functions, dom_node_class_entry);
zend_hash_add_ptr(&classes, ce.name, &dom_namespace_node_prop_handlers);
REGISTER_DOM_CLASS(ce, "DOMDocumentFragment", dom_node_class_entry, php_dom_documentfragment_class_functions, dom_documentfragment_class_entry);
- zend_hash_add_ptr(&classes, ce.name, &dom_node_prop_handlers);
+ zend_hash_init(&dom_documentfragment_prop_handlers, 0, NULL, dom_dtor_prop_handler, 1);
+
+ dom_register_prop_handler(&dom_documentfragment_prop_handlers, "firstElementChild", sizeof("firstElementChild")-1, dom_parent_node_first_element_child_read, NULL);
+ dom_register_prop_handler(&dom_documentfragment_prop_handlers, "lastElementChild", sizeof("lastElementChild")-1, dom_parent_node_last_element_child_read, NULL);
+ dom_register_prop_handler(&dom_documentfragment_prop_handlers, "childElementCount", sizeof("childElementCount")-1, dom_parent_node_child_element_count, NULL);
+
+ zend_hash_merge(&dom_documentfragment_prop_handlers, &dom_node_prop_handlers, dom_copy_prop_handler, 0);
+ zend_hash_add_ptr(&classes, ce.name, &dom_documentfragment_prop_handlers);
+ zend_class_implements(dom_documentfragment_class_entry, 1, dom_parentnode_class_entry);
REGISTER_DOM_CLASS(ce, "DOMDocument", dom_node_class_entry, php_dom_document_class_functions, dom_document_class_entry);
zend_hash_init(&dom_document_prop_handlers, 0, NULL, dom_dtor_prop_handler, 1);
dom_register_prop_handler(&dom_document_prop_handlers, "recover", sizeof("recover")-1, dom_document_recover_read, dom_document_recover_write);
dom_register_prop_handler(&dom_document_prop_handlers, "substituteEntities", sizeof("substituteEntities")-1, dom_document_substitue_entities_read, dom_document_substitue_entities_write);
+ dom_register_prop_handler(&dom_document_prop_handlers, "firstElementChild", sizeof("firstElementChild")-1, dom_parent_node_first_element_child_read, NULL);
+ dom_register_prop_handler(&dom_document_prop_handlers, "lastElementChild", sizeof("lastElementChild")-1, dom_parent_node_last_element_child_read, NULL);
+ dom_register_prop_handler(&dom_document_prop_handlers, "childElementCount", sizeof("childElementCount")-1, dom_parent_node_child_element_count, NULL);
+
zend_hash_merge(&dom_document_prop_handlers, &dom_node_prop_handlers, dom_copy_prop_handler, 0);
zend_hash_add_ptr(&classes, ce.name, &dom_document_prop_handlers);
+ zend_class_implements(dom_document_class_entry, 1, dom_parentnode_class_entry);
INIT_CLASS_ENTRY(ce, "DOMNodeList", php_dom_nodelist_class_functions);
ce.create_object = dom_nnodemap_objects_new;
zend_hash_init(&dom_characterdata_prop_handlers, 0, NULL, dom_dtor_prop_handler, 1);
dom_register_prop_handler(&dom_characterdata_prop_handlers, "data", sizeof("data")-1, dom_characterdata_data_read, dom_characterdata_data_write);
dom_register_prop_handler(&dom_characterdata_prop_handlers, "length", sizeof("length")-1, dom_characterdata_length_read, NULL);
+ dom_register_prop_handler(&dom_characterdata_prop_handlers, "previousElementSibling", sizeof("previousElementSibling")-1, dom_node_previous_element_sibling_read, NULL);
+ dom_register_prop_handler(&dom_characterdata_prop_handlers, "nextElementSibling", sizeof("nextElementSibling")-1, dom_node_next_element_sibling_read, NULL);
zend_hash_merge(&dom_characterdata_prop_handlers, &dom_node_prop_handlers, dom_copy_prop_handler, 0);
zend_hash_add_ptr(&classes, ce.name, &dom_characterdata_prop_handlers);
+ zend_class_implements(dom_characterdata_class_entry, 1, dom_childnode_class_entry);
+
REGISTER_DOM_CLASS(ce, "DOMAttr", dom_node_class_entry, php_dom_attr_class_functions, dom_attr_class_entry);
zend_hash_init(&dom_attr_prop_handlers, 0, NULL, dom_dtor_prop_handler, 1);
zend_hash_init(&dom_element_prop_handlers, 0, NULL, dom_dtor_prop_handler, 1);
dom_register_prop_handler(&dom_element_prop_handlers, "tagName", sizeof("tagName")-1, dom_element_tag_name_read, NULL);
dom_register_prop_handler(&dom_element_prop_handlers, "schemaTypeInfo", sizeof("schemaTypeInfo")-1, dom_element_schema_type_info_read, NULL);
+ dom_register_prop_handler(&dom_element_prop_handlers, "firstElementChild", sizeof("firstElementChild")-1, dom_parent_node_first_element_child_read, NULL);
+ dom_register_prop_handler(&dom_element_prop_handlers, "lastElementChild", sizeof("lastElementChild")-1, dom_parent_node_last_element_child_read, NULL);
+ dom_register_prop_handler(&dom_element_prop_handlers, "childElementCount", sizeof("childElementCount")-1, dom_parent_node_child_element_count, NULL);
+ dom_register_prop_handler(&dom_element_prop_handlers, "previousElementSibling", sizeof("previousElementSibling")-1, dom_node_previous_element_sibling_read, NULL);
+ dom_register_prop_handler(&dom_element_prop_handlers, "nextElementSibling", sizeof("nextElementSibling")-1, dom_node_next_element_sibling_read, NULL);
zend_hash_merge(&dom_element_prop_handlers, &dom_node_prop_handlers, dom_copy_prop_handler, 0);
zend_hash_add_ptr(&classes, ce.name, &dom_element_prop_handlers);
+ zend_class_implements(dom_element_class_entry, 2, dom_parentnode_class_entry, dom_childnode_class_entry);
+
REGISTER_DOM_CLASS(ce, "DOMText", dom_characterdata_class_entry, php_dom_text_class_functions, dom_text_class_entry);
zend_hash_init(&dom_text_prop_handlers, 0, NULL, dom_dtor_prop_handler, 1);
PHP_MSHUTDOWN_FUNCTION(dom) /* {{{ */
{
zend_hash_destroy(&dom_document_prop_handlers);
+ zend_hash_destroy(&dom_documentfragment_prop_handlers);
zend_hash_destroy(&dom_node_prop_handlers);
zend_hash_destroy(&dom_namespace_node_prop_handlers);
zend_hash_destroy(&dom_nodelist_prop_handlers);
}
/* }}} end dom_set_old_ns */
+void dom_reconcile_ns(xmlDocPtr doc, xmlNodePtr nodep) /* {{{ */
+{
+ xmlNsPtr nsptr, nsdftptr, curns, prevns = NULL;
+
+ if (nodep->type == XML_ELEMENT_NODE) {
+ /* Following if block primarily used for inserting nodes created via createElementNS */
+ if (nodep->nsDef != NULL) {
+ curns = nodep->nsDef;
+ while (curns) {
+ nsdftptr = curns->next;
+ if (curns->href != NULL) {
+ if((nsptr = xmlSearchNsByHref(doc, nodep->parent, curns->href)) &&
+ (curns->prefix == NULL || xmlStrEqual(nsptr->prefix, curns->prefix))) {
+ curns->next = NULL;
+ if (prevns == NULL) {
+ nodep->nsDef = nsdftptr;
+ } else {
+ prevns->next = nsdftptr;
+ }
+ dom_set_old_ns(doc, curns);
+ curns = prevns;
+ }
+ }
+ prevns = curns;
+ curns = nsdftptr;
+ }
+ }
+ xmlReconciliateNs(doc, nodep);
+ }
+}
+/* }}} */
+
/*
http://www.w3.org/TR/2004/REC-DOM-Level-3-Core-20040407/core.html#ID-DocCrElNS
int dom_check_qname(char *qname, char **localname, char **prefix, int uri_len, int name_len);
xmlNsPtr dom_get_ns(xmlNodePtr node, char *uri, int *errorcode, char *prefix);
void dom_set_old_ns(xmlDoc *doc, xmlNs *ns);
+void dom_reconcile_ns(xmlDocPtr doc, xmlNodePtr nodep);
xmlNsPtr dom_get_nsdecl(xmlNode *node, xmlChar *localName);
void dom_normalize (xmlNodePtr nodep);
xmlNode *dom_get_elements_by_tag_name_ns_raw(xmlNodePtr nodep, char *ns, char *local, int *cur, int index);
zend_object_iterator *php_dom_get_iterator(zend_class_entry *ce, zval *object, int by_ref);
void dom_set_doc_classmap(php_libxml_ref_obj *document, zend_class_entry *basece, zend_class_entry *ce);
+void dom_parent_node_prepend(dom_object *context, zval *nodes, int nodesc);
+void dom_parent_node_append(dom_object *context, zval *nodes, int nodesc);
+void dom_parent_node_after(dom_object *context, zval *nodes, int nodesc);
+void dom_parent_node_before(dom_object *context, zval *nodes, int nodesc);
+void dom_child_node_remove(dom_object *context);
+
#define REGISTER_DOM_CLASS(ce, name, parent_ce, funcs, entry) \
INIT_CLASS_ENTRY(ce, name, funcs); \
ce.create_object = dom_objects_new; \
--- /dev/null
+--TEST--
+DOMChildNode::after(), before, replaceWith with DOMNode from wrong document throws exception
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+require_once("dom_test.inc");
+
+$dom1 = new DOMDocument;
+$dom1->loadXML('<test/>');
+
+$dom2 = new DOMDocument;
+$dom2->loadXML('<test><foo /></test>');
+
+$element = $dom1->documentElement;
+
+try {
+ $element->after($dom2->documentElement->firstChild);
+ echo "FAIL";
+} catch (DOMException $e) {
+ echo $e->getMessage() . "\n";
+}
+
+try {
+ $element->before($dom2->documentElement->firstChild);
+ echo "FAIL";
+} catch (DOMException $e) {
+ echo $e->getMessage() . "\n";
+}
+
+try {
+ $element->replaceWith($dom2->documentElement->firstChild);
+ echo "FAIL";
+} catch (DOMException $e) {
+ echo $e->getMessage();
+}
+?>
+--EXPECT--
+Wrong Document Error
+Wrong Document Error
+Wrong Document Error
--- /dev/null
+--TEST--
+DOMNode: Element Siblings
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+require_once("dom_test.inc");
+
+$dom = new DOMDocument;
+$dom->loadXML('<test>foo<bar>FirstElement</bar><bar>LastElement</bar>bar</test>');
+
+$element = $dom->documentElement;
+print_node($element->firstElementChild->nextElementSibling);
+print_node($element->lastElementChild->previousElementSibling);
+?>
+--EXPECT--
+Node Name: bar
+Node Type: 1
+Num Children: 1
+Node Content: LastElement
+
+Node Name: bar
+Node Type: 1
+Num Children: 1
+Node Content: FirstElement
--- /dev/null
+--TEST--
+DOMNode::after()
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+require_once("dom_test.inc");
+
+$dom = new DOMDocument;
+$dom->loadXML('<test><mark>first</mark><mark>second</mark></test>');
+
+$element = $dom->documentElement->firstElementChild;
+$secondMark = $dom->documentElement->lastElementChild;
+
+$element->after(
+ 'text inserted after',
+ $dom->createElement('inserted-after', 'content')
+);
+
+$secondMark->after('text inserted after second');
+
+print_node_list_compact($dom->documentElement->childNodes);
+?>
+--EXPECT--
+<mark>
+ first
+</mark>
+text inserted after
+<inserted-after>
+ content
+</inserted-after>
+<mark>
+ second
+</mark>
+text inserted after second
--- /dev/null
+--TEST--
+DOMNode::after() with namespace
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+require_once("dom_test.inc");
+
+$doc = new DOMDocument('1.0', 'utf-8');
+$doc->formatOutput = true;
+
+$root = $doc->createElementNS('http://www.w3.org/2005/Atom', 'element');
+$doc->appendChild($root);
+$root->setAttributeNS('http://www.w3.org/2000/xmlns/' ,'xmlns:g', 'http://base.google.com/ns/1.0');
+
+$item = $doc->createElementNS('http://base.google.com/ns/1.0', 'g:item_type', 'house');
+$root->append($item);
+
+$item2 = $doc->createElementNS('http://base.google.com/ns/1.0', 'g:item_type', 'street');
+$item->after($item2);
+
+echo $doc->saveXML(), "\n";
+?>
+--EXPECT--
+<?xml version="1.0" encoding="utf-8"?>
+<element xmlns="http://www.w3.org/2005/Atom" xmlns:g="http://base.google.com/ns/1.0">
+ <g:item_type>house</g:item_type>
+ <g:item_type>street</g:item_type>
+</element>
--- /dev/null
+--TEST--
+DOMNode::append() with namespace
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+require_once("dom_test.inc");
+
+$doc = new DOMDocument('1.0', 'utf-8');
+$doc->formatOutput = true;
+
+$root = $doc->createElementNS('http://www.w3.org/2005/Atom', 'element');
+$doc->appendChild($root);
+$root->setAttributeNS('http://www.w3.org/2000/xmlns/' ,'xmlns:g', 'http://base.google.com/ns/1.0');
+
+$item = $doc->createElementNS('http://base.google.com/ns/1.0', 'g:item_type', 'house');
+$root->append($item);
+
+echo $doc->saveXML(), "\n";
+?>
+--EXPECT--
+<?xml version="1.0" encoding="utf-8"?>
+<element xmlns="http://www.w3.org/2005/Atom" xmlns:g="http://base.google.com/ns/1.0">
+ <g:item_type>house</g:item_type>
+</element>
--- /dev/null
+--TEST--
+DOMNode::before()
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+require_once("dom_test.inc");
+
+$dom = new DOMDocument;
+$dom->loadXML('<test><mark>first</mark><mark>second</mark></test>');
+
+$element = $dom->documentElement->firstElementChild;
+$secondMark = $dom->documentElement->lastElementChild;
+
+$element->before(
+ $dom->createElement('inserted-before', 'content'),
+ 'text inserted before'
+);
+
+$secondMark->before('text inserted before second');
+
+print_node_list_compact($dom->documentElement->childNodes);
+?>
+--EXPECT--
+<inserted-before>
+ content
+</inserted-before>
+text inserted before
+<mark>
+ first
+</mark>
+text inserted before second
+<mark>
+ second
+</mark>
--- /dev/null
+--TEST--
+DOMNode::before() with namespace
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+require_once("dom_test.inc");
+
+$doc = new DOMDocument('1.0', 'utf-8');
+$doc->formatOutput = true;
+
+$root = $doc->createElementNS('http://www.w3.org/2005/Atom', 'element');
+$doc->appendChild($root);
+$root->setAttributeNS('http://www.w3.org/2000/xmlns/' ,'xmlns:g', 'http://base.google.com/ns/1.0');
+
+$item = $doc->createElementNS('http://base.google.com/ns/1.0', 'g:item_type', 'house');
+$root->append($item);
+
+$item2 = $doc->createElementNS('http://base.google.com/ns/1.0', 'g:item_type', 'street');
+$item->before($item2);
+
+echo $doc->saveXML(), "\n";
+?>
+--EXPECT--
+<?xml version="1.0" encoding="utf-8"?>
+<element xmlns="http://www.w3.org/2005/Atom" xmlns:g="http://base.google.com/ns/1.0">
+ <g:item_type>street</g:item_type>
+ <g:item_type>house</g:item_type>
+</element>
--- /dev/null
+--TEST--
+DOMNode::prepend() with namespace
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+require_once("dom_test.inc");
+
+$doc = new DOMDocument('1.0', 'utf-8');
+$doc->formatOutput = true;
+
+$root = $doc->createElementNS('http://www.w3.org/2005/Atom', 'element');
+$doc->appendChild($root);
+$root->setAttributeNS('http://www.w3.org/2000/xmlns/' ,'xmlns:g', 'http://base.google.com/ns/1.0');
+
+$item = $doc->createElementNS('http://base.google.com/ns/1.0', 'g:item_type', 'house');
+$root->prepend($item);
+
+echo $doc->saveXML(), "\n";
+?>
+--EXPECT--
+<?xml version="1.0" encoding="utf-8"?>
+<element xmlns="http://www.w3.org/2005/Atom" xmlns:g="http://base.google.com/ns/1.0">
+ <g:item_type>house</g:item_type>
+</element>
--- /dev/null
+--TEST--
+DOMNode::remove()
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+require_once("dom_test.inc");
+
+$dom = new DOMDocument;
+$dom->loadXML('<test><one>first</one><two>second</two></test>');
+
+$element = $dom->documentElement;
+print_node($element->firstChild);
+$returnValue = $element->firstChild->remove();
+print_node($element->firstChild);
+var_dump($returnValue);
+?>
+--EXPECT--
+Node Name: one
+Node Type: 1
+Num Children: 1
+Node Content: first
+
+Node Name: two
+Node Type: 1
+Num Children: 1
+Node Content: second
+
+NULL
+
--- /dev/null
+--TEST--
+DOMNode::remove() dangling element
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+
+$dom = new DOMDocument();
+
+$element = $dom->createElement('test');
+
+try {
+ $element->remove();
+} catch (DOMException $e) {
+ echo $e->getMessage();
+}
+--EXPECT--
+Not Found Error
--- /dev/null
+--TEST--
+DOMNode::replaceWith()
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+require_once("dom_test.inc");
+
+$dom = new DOMDocument;
+$dom->loadXML('<test><mark>first</mark><mark>second</mark></test>');
+
+$element = $dom->documentElement->firstChild;
+$element->replaceWith(
+ $dom->createElement('element', 'content'),
+ 'content'
+);
+
+print_node_list_compact($dom->documentElement->childNodes);
+?>
+--EXPECT--
+<element>
+ content
+</element>
+content
+<mark>
+ second
+</mark>
--- /dev/null
+--TEST--
+DOMParentNode: Child Element Handling
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+require_once("dom_test.inc");
+
+$dom = new DOMDocument;
+$dom->loadXML('<test>foo<bar>FirstElement</bar><bar>LastElement</bar>bar</test>');
+
+var_dump($dom instanceof DOMParentNode);
+print_node($dom->firstElementChild);
+print_node($dom->lastElementChild);
+var_dump($dom->childElementCount);
+
+$element = $dom->documentElement;
+var_dump($element instanceof DOMParentNode);
+print_node($element->firstElementChild);
+print_node($element->lastElementChild);
+var_dump($element->childElementCount);
+var_dump($element->lastElementChild->firstElementChild);
+var_dump($element->lastElementChild->lastElementChild);
+var_dump($element->lastElementChild->childElementCount);
+?>
+--EXPECT--
+bool(true)
+Node Name: test
+Node Type: 1
+Num Children: 4
+
+Node Name: test
+Node Type: 1
+Num Children: 4
+
+int(1)
+bool(true)
+Node Name: bar
+Node Type: 1
+Num Children: 1
+Node Content: FirstElement
+
+Node Name: bar
+Node Type: 1
+Num Children: 1
+Node Content: LastElement
+
+int(2)
+NULL
+NULL
+int(0)
--- /dev/null
+--TEST--
+DOMParentNode: Child Element Handling
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+require_once("dom_test.inc");
+
+$dom = new DOMDocument;
+$dom->loadXML('<test></test>');
+
+$fragment = $dom->createDocumentFragment();
+$fragment->appendChild($dom->createTextNode('foo'));
+$fragment->appendChild($dom->createElement('bar', 'FirstElement'));
+$fragment->appendChild($dom->createElement('bar', 'LastElement'));
+$fragment->appendChild($dom->createTextNode('bar'));
+
+var_dump($fragment instanceof DOMParentNode);
+print_node($fragment->firstElementChild);
+print_node($fragment->lastElementChild);
+var_dump($fragment->childElementCount);
+var_dump($fragment->lastElementChild->firstElementChild);
+var_dump($fragment->lastElementChild->lastElementChild);
+var_dump($fragment->lastElementChild->childElementCount);
+?>
+--EXPECT--
+bool(true)
+Node Name: bar
+Node Type: 1
+Num Children: 1
+Node Content: FirstElement
+
+Node Name: bar
+Node Type: 1
+Num Children: 1
+Node Content: LastElement
+
+int(2)
+NULL
+NULL
+int(0)
--- /dev/null
+--TEST--
+DOMParentNode::append()
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+declare(strict_types=1);
+
+require_once("dom_test.inc");
+
+$dom = new DOMDocument;
+$dom->loadXML('<test><mark/><mark /><mark /></test>');
+
+$element = $dom->documentElement;
+$element->append(
+ $dom->createElement('element', 'content'),
+ 'content'
+);
+
+var_dump($dom->documentElement->childElementCount);
+print_node_list_compact($element->childNodes);
+
+$element->append(
+ $dom->createElement('element', 'content'),
+ 'content'
+);
+var_dump($dom->documentElement->childElementCount);
+?>
+--EXPECT--
+int(4)
+<mark>
+</mark>
+<mark>
+</mark>
+<mark>
+</mark>
+<element>
+ content
+</element>
+content
+int(5)
--- /dev/null
+--TEST--
+DOMParentNode::append() exception on invalid argument
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+require_once("dom_test.inc");
+
+$dom = new DOMDocument;
+$dom->loadXML('<test />');
+
+try {
+ $dom->documentElement->append(array());
+} catch(TypeError $e) {
+ echo "OK! {$e->getMessage()}";
+}
+--EXPECT--
+OK! Invalid argument type must be either DOMNode or string
--- /dev/null
+--TEST--
+DOMParentNode::append() with attributes
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+require_once("dom_test.inc");
+
+$dom = new DOMDocument;
+$dom->loadXML('<test attr-one="21"/>');
+
+$replacement = $dom->createAttribute('attr-one');
+$replacement->value ='42';
+$addition = $dom->createAttribute('attr-two');
+$addition->value = '23';
+
+$element = $dom->documentElement;
+
+try {
+ $element->append($replacement, $addition);
+} catch (DOMException $e) {
+ echo $e->getMessage();
+}
+?>
+--EXPECT--
+Hierarchy Request Error
--- /dev/null
+--TEST--
+DOMParentNode::append() with DOMNode from wrong document throws exception
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+require_once("dom_test.inc");
+
+$dom1 = new DOMDocument;
+$dom1->loadXML('<test/>');
+
+$dom2 = new DOMDocument;
+$dom2->loadXML('<test><foo /></test>');
+
+$element = $dom1->documentElement;
+
+try {
+ $element->append($dom2->documentElement->firstChild);
+ echo "FAIL";
+} catch (DOMException $e) {
+ echo $e->getMessage() . "\n";
+}
+
+try {
+ $element->prepend($dom2->documentElement->firstChild);
+ echo "FAIL";
+} catch (DOMException $e) {
+ echo $e->getMessage();
+}
+?>
+--EXPECT--
+Wrong Document Error
+Wrong Document Error
--- /dev/null
+--TEST--
+DOMParentNode::prepend()
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+--FILE--
+<?php
+declare(strict_types=1);
+
+require_once("dom_test.inc");
+
+$dom = new DOMDocument;
+$dom->loadXML('<test><mark/><mark><nested /></mark><mark/></test>');
+
+$element = $dom->documentElement;
+$firstMark = $element->childNodes[0];
+$element->prepend(
+ $dom->createElement('element', 'content'),
+ 'content'
+);
+
+var_dump($element->childElementCount);
+print_node_list_compact($element->childNodes);
+
+$element = $dom->documentElement;
+$element->prepend(
+ $dom->createElement('element', 'content'),
+ 'content'
+);
+var_dump($element->childElementCount);
+
+$firstMark->prepend('content');
+print_node_list_compact($firstMark->childNodes);
+?>
+--EXPECT--
+int(4)
+<element>
+ content
+</element>
+content
+<mark>
+</mark>
+<mark>
+ <nested>
+ </nested>
+</mark>
+<mark>
+</mark>
+int(5)
+content
?>
--EXPECTF--
int(3)
-object(DOMText)#%d (19) {
+object(DOMText)#%d (21) {
["wholeText"]=>
string(3) "
"
"
["length"]=>
int(3)
+ ["previousElementSibling"]=>
+ NULL
+ ["nextElementSibling"]=>
+ NULL
["nodeName"]=>
string(5) "#text"
["nodeValue"]=>
string(3) "
"
}
-object(DOMElement)#%d (18) {
+object(DOMElement)#%d (23) {
["tagName"]=>
string(5) "form1"
["schemaTypeInfo"]=>
NULL
+ ["firstElementChild"]=>
+ string(22) "(object value omitted)"
+ ["lastElementChild"]=>
+ string(22) "(object value omitted)"
+ ["childElementCount"]=>
+ int(3)
+ ["previousElementSibling"]=>
+ NULL
+ ["nextElementSibling"]=>
+ NULL
["nodeName"]=>
string(5) "form1"
["nodeValue"]=>
Value C
"
}
-object(DOMText)#%d (19) {
+object(DOMText)#%d (21) {
["wholeText"]=>
string(1) "
"
"
["length"]=>
int(1)
+ ["previousElementSibling"]=>
+ NULL
+ ["nextElementSibling"]=>
+ NULL
["nodeName"]=>
string(5) "#text"
["nodeValue"]=>
}
}
+function print_node_compact($node, $spaces)
+{
+ if ($node->nodeType == 3) {
+ print str_repeat(" ", $spaces) . trim($node->nodeValue) . "\n";
+ } else {
+ print str_repeat(" ", $spaces) . "<" . $node->nodeName . ">\n";
+ print_node_list_compact($node->childNodes, $spaces + 2);
+ print str_repeat(" ", $spaces) . "</" . $node->nodeName . ">\n";
+ }
+}
+
+function print_node_list_compact($nodelist, $spaces = 0)
+{
+ foreach ($nodelist as $node) {
+ print_node_compact($node, $spaces);
+ }
+}
+
?>
[preserveWhiteSpace] => 1
[recover] =>
[substituteEntities] =>
+ [firstElementChild] => (object value omitted)
+ [lastElementChild] => (object value omitted)
+ [childElementCount] => 1
[nodeName] => #document
[nodeValue] =>
[nodeType] => 9