zend_class_entry *sxe_class_entry;
+#define SKIP_TEXT(__p) \
+ if ((__p)->type == XML_TEXT_NODE) { \
+ goto next_iter; \
+ }
+
static php_sxe_object *php_sxe_object_new(TSRMLS_D);
static zend_object_value php_sxe_register_object(php_sxe_object * TSRMLS_DC);
APPEND_PREV_ELEMENT(counter, value);
MAKE_STD_ZVAL(value);
- contents = xmlNodeListGetString(sxe->document, attr->xmlChildrenNode, 1);
+ contents = xmlNodeListGetString(sxe->document, attr->children, 1);
ZVAL_STRING(value, contents, 0);
APPEND_CUR_ELEMENT(counter, value);
if (!sxe->node) {
sxe->node = node;
}
- node = node->xmlChildrenNode;
+ node = node->children;
while (node) {
+ SKIP_TEXT(node);
+
if (node->ns && !xmlStrcmp(node->ns->prefix, name)) {
APPEND_PREV_ELEMENT(counter, value);
APPEND_CUR_ELEMENT(counter, value);
}
+next_iter:
node = node->next;
}
attr = attr->next;
}
- node = node->xmlChildrenNode;
+ node = node->children;
while (node) {
+ SKIP_TEXT(node);
if (!xmlStrcmp(node->name, name)) {
newnode = node;
++counter;
}
+next_iter:
node = node->next;
}
if (counter == 1) {
if (is_attr) {
- change_node_zval(attr->xmlChildrenNode, value);
+ change_node_zval(attr->children, value);
} else {
- change_node_zval(newnode->xmlChildrenNode, value);
+ change_node_zval(newnode->children, value);
}
} else if (counter > 1) {
php_error(E_WARNING, "Cannot assign to an array of nodes (duplicate subnodes or attr detected)\n");
attr = attr->next;
}
- node = node->xmlChildrenNode;
+ node = node->children;
while (node) {
+ SKIP_TEXT(node);
+
if (!xmlStrcmp(node->name, name)) {
return 1;
}
+next_iter:
node = node->next;
}
static void
sxe_property_delete(zval *object, zval *member TSRMLS_DC)
{
+ php_sxe_object *sxe;
+ xmlNodePtr node;
+ xmlNodePtr nnext;
+ xmlAttrPtr attr;
+ xmlAttrPtr anext;
+
+ sxe = php_sxe_fetch_object(object TSRMLS_CC);
+
+ GET_NODE(sxe, node);
+
+ attr = node->properties;
+ while (attr) {
+ anext = attr->next;
+ if (!xmlStrcmp(attr->name, Z_STRVAL_P(member))) {
+ // free
+ }
+ attr = anext;
+ }
+
+ node = node->children;
+ while (node) {
+ nnext = node->next;
+
+ SKIP_TEXT(node);
+
+ if (!xmlStrcmp(node->name, Z_STRVAL_P(member))) {
+ xmlUnlinkNode(node);
+ xmlFreeNode(node);
+ }
+
+next_iter:
+ node = nnext;
+ }
+}
+/* }}} */
+
+/* {{{ _get_base_node_value()
+ */
+static void
+_get_base_node_value(xmlNodePtr node, zval **value TSRMLS_CC)
+{
+ php_sxe_object *subnode;
+ char *contents;
+
+ MAKE_STD_ZVAL(*value);
+ if (node->children && node->children->type == XML_TEXT_NODE && !xmlIsBlankNode(node->children)) {
+ contents = xmlNodeListGetString(node->doc, node->children, 1);
+ if (contents) {
+ ZVAL_STRING(*value, contents, 1);
+ }
+ } else {
+ subnode = php_sxe_object_new(TSRMLS_C);
+ subnode->document = node->doc;
+ subnode->node = node;
+
+ (*value)->type = IS_OBJECT;
+ (*value)->value.obj = php_sxe_register_object(subnode TSRMLS_CC);
+ zval_add_ref(value);
+ }
}
/* }}} */
static HashTable *
sxe_properties_get(zval *object TSRMLS_DC)
{
- HashTable *rv;
- php_sxe_object *sxe;
- xmlNodePtr node;
- int counter = 0;
+ zval **data_ptr;
+ zval *value;
+ zval *newptr;
+ HashTable *rv;
+ php_sxe_object *sxe;
+ char *name;
+ xmlNodePtr node;
+ ulong h;
+ int namelen;
ALLOC_HASHTABLE_REL(rv);
zend_hash_init(rv, 0, NULL, ZVAL_PTR_DTOR, 0);
sxe = php_sxe_fetch_object(object TSRMLS_CC);
GET_NODE(sxe, node);
+ node = node->children;
+
+ while (node) {
+ SKIP_TEXT(node);
+
+ _get_base_node_value(node, &value TSRMLS_CC);
+
+ name = (char *) node->name;
+ namelen = xmlStrlen(node->name) + 1;
+
+ h = zend_hash_func(name, namelen);
+ if (zend_hash_quick_find(rv, name, namelen, h, (void **) &data_ptr) == SUCCESS) {
+ if (Z_TYPE_PP(data_ptr) == IS_ARRAY) {
+ zend_hash_next_index_insert(Z_ARRVAL_PP(data_ptr), &value, sizeof(zval *), NULL);
+ } else {
+ MAKE_STD_ZVAL(newptr);
+ array_init(newptr);
+
+ zend_hash_next_index_insert(Z_ARRVAL_P(newptr), data_ptr, sizeof(zval *), NULL);
+ zend_hash_next_index_insert(Z_ARRVAL_P(newptr), &value, sizeof(zval *), NULL);
+
+ zend_hash_quick_update(rv, name, namelen, h, &newptr, sizeof(zval *), NULL);
+ }
+ } else {
+ zend_hash_quick_update(rv, name, namelen, h, &value, sizeof(zval *), NULL);
+ }
+
+next_iter:
+ node = node->next;
+ }
- /*
- * XXX: TODO
- * Recurse from the current node through the XML document
- * and build an array return value. Expensive? sure. But
- * if you ask for it, you get it :)
- */
-
return rv;
}
/* }}} */
static int
sxe_objects_compare(zval *object1, zval *object2 TSRMLS_DC)
{
- return 0;
+ php_sxe_object *sxe1;
+ php_sxe_object *sxe2;
+
+ sxe1 = php_sxe_fetch_object(object1 TSRMLS_CC);
+ sxe2 = php_sxe_fetch_object(object2 TSRMLS_CC);
+
+ if (sxe1->node == NULL) {
+ if (sxe2->node) {
+ return 1;
+ } else if (sxe1->document == sxe2->document) {
+ return 9;
+ }
+ } else {
+ return !(sxe1->node == sxe2->node);
+ }
}
/* }}} */
for (i = 0; i < result->nodeNr; ++i) {
MAKE_STD_ZVAL(value);
- if (!xmlStrcmp(result->nodeTab[i]->name, "text")) {
+ /**
+ * Detect the case where the last selector is text(), simplexml
+ * always accesses the text() child by default, therefore we assign
+ * to the parent node.
+ */
+ if (result->nodeTab[i]->type == XML_TEXT_NODE) {
_node_as_zval(sxe, result->nodeTab[i]->parent, value);
} else {
_node_as_zval(sxe, result->nodeTab[i], value);
{
*class_name = estrdup("simplexml_element");
*class_name_len = sizeof("simplexml_element");
+
return 0;
}
/* }}} */
-/* {{{ cast_empty_object()
+/* {{{ cast_object()
*/
static inline void
-cast_empty_object(zval *object, int type TSRMLS_DC)
+cast_object(zval *object, int type, char *contents TSRMLS_DC)
{
- object->type = IS_NULL;
- switch (type) {
- case IS_BOOL:
- convert_to_boolean(object);
- break;
- case IS_LONG:
- convert_to_long(object);
- break;
- case IS_DOUBLE:
- convert_to_double(object);
- break;
- case IS_STRING:
- convert_to_string(object);
- break;
+ if (contents) {
+ int len = strlen(contents);
+ ZVAL_STRINGL(object, contents, len, 1);
+ } else {
+ ZVAL_NULL(object);
}
-}
-/* }}} */
-
-/* {{{ cast_object_with_contents()
- */
-static inline void
-cast_object_with_contents(zval *object, int type, char *contents TSRMLS_DC)
-{
- int len = strlen(contents);
-
- object->value.str.val = estrndup(contents, len);
- object->value.str.len = len;
- object->type = IS_STRING;
switch (type) {
case IS_STRING:
}
if (sxe->node) {
- contents = xmlNodeListGetString(sxe->document, sxe->node->xmlChildrenNode, 1);
- if (!xmlIsBlankNode(sxe->node->xmlChildrenNode) && contents) {
- cast_empty_object(writeobj, type TSRMLS_CC);
+ contents = xmlNodeListGetString(sxe->document, sxe->node->children, 1);
+ if (!xmlIsBlankNode(sxe->node->children) && contents) {
+ cast_object(writeobj, type, NULL TSRMLS_CC);
}
}
- cast_object_with_contents(writeobj, type, contents TSRMLS_CC);
+ cast_object(writeobj, type, contents TSRMLS_CC);
}
/* }}} */
{
/* XXX: TODO
* This call is not yet implemented in the engine
- * so leave them blank for now.
+ * so leave it blank for now.
*/
}
/* }}} */
{
/* XXX: TODO
* This call is not yet implemented in the engine
- * so leave them blank for now.
+ * so leave it blank for now.
*/
return NULL;
}
/* {{{ sxe_object_clone()
*/
static void
-sxe_object_clone(void *object, void **clone TSRMLS_DC)
+sxe_object_clone(void *object, void **clone_ptr TSRMLS_DC)
{
-
+ php_sxe_object *sxe = (php_sxe_object *) object;
+ php_sxe_object *clone;
+
+ clone = php_sxe_object_new(TSRMLS_C);
+
+ /**
+ * XXX: Change parts of the code not to rely on sxe->document
+ * being set.
+ */
+ if (xmlDocGetRootElement(sxe->document) == sxe->node) {
+ clone->document = xmlCopyDoc(sxe->document, 1);
+ } else {
+ clone->node = xmlCopyNode(sxe->node, 0);
+ }
+
+ *clone_ptr = (void *) clone;
}
/* }}} */
static void
sxe_object_dtor(void *object, zend_object_handle handle TSRMLS_DC)
{
+ php_sxe_object *sxe;
+
+ sxe = (php_sxe_object *) object;
+
+ if (sxe->document) {
+ xmlFreeDoc(sxe->document);
+ }
+
+ if (sxe->xpath) {
+ xmlXPathFreeContext(sxe->xpath);
+ }
+
zend_objects_destroy_object(object, handle TSRMLS_CC);
}
/* }}} */