]> granicus.if.org Git - php/commitdiff
- Synch with head
authorRob Richards <rrichards@php.net>
Tue, 7 Mar 2006 15:22:48 +0000 (15:22 +0000)
committerRob Richards <rrichards@php.net>
Tue, 7 Mar 2006 15:22:48 +0000 (15:22 +0000)
ext/simplexml/simplexml.c
ext/simplexml/tests/027.phpt
ext/simplexml/tests/030.phpt [new file with mode: 0644]
ext/simplexml/tests/031.phpt [new file with mode: 0644]
ext/simplexml/tests/bug35785.phpt

index 9ba15041886bd8aa25649ce1bd34408427090517..30f42ae5b7095ed0bdd6833cf1cfeeab6d39b937 100644 (file)
@@ -632,6 +632,14 @@ static int sxe_prop_dim_exists(zval *object, zval *member, int check_empty, zend
        xmlAttrPtr      attr = NULL;
        int                             exists = 0;
        int             test = 0;
+       zval            tmp_zv;
+
+       if (Z_TYPE_P(member) != IS_STRING && Z_TYPE_P(member) != IS_LONG) {
+               tmp_zv = *member;
+               zval_copy_ctor(&tmp_zv);
+               member = &tmp_zv;
+               convert_to_string(member);
+       }
 
        sxe = php_sxe_fetch_object(object TSRMLS_CC);
 
@@ -661,13 +669,28 @@ static int sxe_prop_dim_exists(zval *object, zval *member, int check_empty, zend
 
        if (node) {
                if (attribs) {
-                       while (attr) {
-                               if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && !xmlStrcmp(attr->name, Z_STRVAL_P(member)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix)) {
-                                       exists = 1;
-                                       break;
+                       if (Z_TYPE_P(member) == IS_LONG) {
+                               int     nodendx = 0;
+
+                               while (attr && nodendx <= Z_LVAL_P(member)) {
+                                       if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix)) {
+                                               if (nodendx == Z_LVAL_P(member)) {
+                                                       exists = 1;
+                                                       break;
+                                               }
+                                               nodendx++;
+                                       }
+                                       attr = attr->next;
                                }
+                       } else {
+                               while (attr) {
+                                       if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && !xmlStrcmp(attr->name, Z_STRVAL_P(member)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix)) {
+                                               exists = 1;
+                                               break;
+                                       }
 
-                               attr = attr->next;
+                                       attr = attr->next;
+                               }
                        }
                }
 
@@ -679,14 +702,6 @@ static int sxe_prop_dim_exists(zval *object, zval *member, int check_empty, zend
                                node = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, NULL);
                        }
                        else {
-                               zval tmp_zv;
-
-                               if (Z_TYPE_P(member) != IS_STRING) {
-                                       tmp_zv = *member;
-                                       zval_copy_ctor(&tmp_zv);
-                                       member = &tmp_zv;
-                                       convert_to_string(member);
-                               }
                                node = node->children;
                                while (node) {
                                        xmlNodePtr nnext;
@@ -696,9 +711,6 @@ static int sxe_prop_dim_exists(zval *object, zval *member, int check_empty, zend
                                        }
                                        node = nnext;
                                }
-                               if (member == &tmp_zv) {
-                                       zval_dtor(&tmp_zv);
-                               }
                        }
                        if (node) {
                                exists = 1;
@@ -706,6 +718,10 @@ static int sxe_prop_dim_exists(zval *object, zval *member, int check_empty, zend
                }
        }
 
+       if (member == &tmp_zv) {
+               zval_dtor(&tmp_zv);
+       }
+
        return exists;
 }
 /* }}} */
@@ -733,12 +749,12 @@ static void sxe_prop_dim_delete(zval *object, zval *member, zend_bool elements,
        php_sxe_object *sxe;
        xmlNodePtr      node;
        xmlNodePtr      nnext;
-       xmlAttrPtr      attr;
+       xmlAttrPtr      attr = NULL;
        xmlAttrPtr      anext;
        zval            tmp_zv;
-       int             test;
+       int             test = 0;
 
-       if (Z_TYPE_P(member) != IS_STRING) {
+       if (Z_TYPE_P(member) != IS_STRING && Z_TYPE_P(member) != IS_LONG) {
                tmp_zv = *member;
                zval_copy_ctor(&tmp_zv);
                member = &tmp_zv;
@@ -748,13 +764,24 @@ static void sxe_prop_dim_delete(zval *object, zval *member, zend_bool elements,
        sxe = php_sxe_fetch_object(object TSRMLS_CC);
 
        GET_NODE(sxe, node);
+
+       if (Z_TYPE_P(member) == IS_LONG) {
+               if (sxe->iter.type != SXE_ITER_ATTRLIST) {
+                       attribs = 0;
+                       elements = 1;
+                       if (sxe->iter.type == SXE_ITER_CHILD) {
+                               node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
+                       }
+               }
+       }
+
        if (sxe->iter.type == SXE_ITER_ATTRLIST) {
                attribs = 1;
                elements = 0;           
                node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
                attr = (xmlAttrPtr)node;
                test = sxe->iter.name != NULL;
-       } else {
+       } else if (sxe->iter.type != SXE_ITER_CHILD) {
                node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
                attr = node ? node->properties : NULL;
                test = 0;
@@ -762,31 +789,58 @@ static void sxe_prop_dim_delete(zval *object, zval *member, zend_bool elements,
 
        if (node) {
                if (attribs) {
-                       while (attr) {
-                               anext = attr->next;
-                               if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && !xmlStrcmp(attr->name, Z_STRVAL_P(member)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix)) {
-                                       xmlUnlinkNode((xmlNodePtr) attr);
-                                       php_libxml_node_free_resource((xmlNodePtr) attr TSRMLS_CC);
-                                       break;
+                       if (Z_TYPE_P(member) == IS_LONG) {
+                               int     nodendx = 0;
+
+                               while (attr && nodendx <= Z_LVAL_P(member)) {
+                                       if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix)) {
+                                               if (nodendx == Z_LVAL_P(member)) {
+                                                       xmlUnlinkNode((xmlNodePtr) attr);
+                                                       php_libxml_node_free_resource((xmlNodePtr) attr TSRMLS_CC);
+                                                       break;
+                                               }
+                                               nodendx++;
+                                       }
+                                       attr = attr->next;
+                               }
+                       } else {
+                               while (attr) {
+                                       anext = attr->next;
+                                       if ((!test || !xmlStrcmp(attr->name, sxe->iter.name)) && !xmlStrcmp(attr->name, Z_STRVAL_P(member)) && match_ns(sxe, (xmlNodePtr) attr, sxe->iter.nsprefix)) {
+                                               xmlUnlinkNode((xmlNodePtr) attr);
+                                               php_libxml_node_free_resource((xmlNodePtr) attr TSRMLS_CC);
+                                               break;
+                                       }
+                                       attr = anext;
                                }
-                               attr = anext;
                        }
                }
 
                if (elements) {
-                       node = node->children;
-                       while (node) {
-                               nnext = node->next;
-
-                               SKIP_TEXT(node);
-
-                               if (!xmlStrcmp(node->name, Z_STRVAL_P(member))) {
+                       if (Z_TYPE_P(member) == IS_LONG) {
+                               if (sxe->iter.type == SXE_ITER_CHILD) {
+                                       node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
+                               }
+                               node = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, NULL);
+                               if (node) {
                                        xmlUnlinkNode(node);
                                        php_libxml_node_free_resource(node TSRMLS_CC);
                                }
+                       } else {
+                               node = node->children;
+                               while (node) {
+                                       nnext = node->next;
+
+                                       SKIP_TEXT(node);
+
+                                       if (!xmlStrcmp(node->name, Z_STRVAL_P(member))) {
+                                               xmlUnlinkNode(node);
+                                               php_libxml_node_free_resource(node TSRMLS_CC);
+                                       }
 
 next_iter:
-                               node = nnext;
+                                       node = nnext;
+                               }
                        }
                }
        }
@@ -1356,6 +1410,129 @@ SXE_METHOD(attributes)
 }
 /* }}} */
 
+/* {{{ proto void SimpleXMLElement::addChild(string qName [, string value [,string ns]])
+   Add Element with optional namespace information */
+SXE_METHOD(addChild)
+{
+       php_sxe_object *sxe;
+       char           *qname, *value = NULL, *nsuri = NULL;
+       int             qname_len, value_len = 0, nsuri_len = 0;
+       xmlNodePtr      node, newnode;
+       xmlNsPtr        nsptr = NULL;
+       xmlChar        *localname, *prefix = NULL;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s!s!",
+               &qname, &qname_len, &value, &value_len, &nsuri, &nsuri_len) == FAILURE) {
+               return;
+       }
+
+       if (qname_len == 0) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Element name is required");
+               return;
+       }
+
+       sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
+       GET_NODE(sxe, node);
+
+       if (sxe->iter.type == SXE_ITER_ATTRLIST) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot add element to attributes");
+               return;
+       }
+
+       node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
+
+       localname = xmlSplitQName2(qname, &prefix);
+       if (localname == NULL) {
+               localname = xmlStrdup(qname);
+       }
+
+
+       newnode = xmlNewChild(node, NULL, localname, value);
+
+       if (nsuri != NULL) {
+               nsptr = xmlSearchNsByHref(node->doc, node, nsuri);
+               if (nsptr == NULL) {
+                       nsptr = xmlNewNs(newnode, nsuri, prefix);
+               }
+               newnode->ns = nsptr;
+       }
+
+       _node_as_zval(sxe, newnode, return_value, SXE_ITER_NONE, localname, prefix TSRMLS_CC);
+
+       xmlFree(localname);
+       if (prefix != NULL) {
+               xmlFree(prefix);
+       }
+}
+/* }}} */
+
+/* {{{ proto void SimpleXMLElement::addAttribute(string qName, string value [,string ns])
+   Add Attribute with optional namespace information */
+SXE_METHOD(addAttribute)
+{
+       php_sxe_object *sxe;
+       char           *qname, *value = NULL, *nsuri = NULL;
+       int             qname_len, value_len = 0, nsuri_len = 0;
+       xmlNodePtr      node;
+       xmlAttrPtr      attrp = NULL;
+       xmlNsPtr        nsptr = NULL;
+       xmlChar        *localname, *prefix = NULL;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|s!",
+               &qname, &qname_len, &value, &value_len, &nsuri, &nsuri_len) == FAILURE) {
+               return;
+       }
+
+       if (qname_len == 0 || value_len == 0) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attribute name and value are required");
+               return;
+       }
+
+       sxe = php_sxe_fetch_object(getThis() TSRMLS_CC);
+       GET_NODE(sxe, node);
+
+       node = php_sxe_get_first_node(sxe, node TSRMLS_CC);
+
+       if (node->type != XML_ELEMENT_NODE) {
+               node = node->parent;
+       }
+
+       if (node == NULL) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to locate parent Element");
+               return;
+       }
+
+       localname = xmlSplitQName2(qname, &prefix);
+       if (localname == NULL) {
+               localname = xmlStrdup(qname);
+       }
+
+       attrp = xmlHasNsProp(node, localname, nsuri);
+       if (attrp != NULL && attrp->type != XML_ATTRIBUTE_DECL) {
+               xmlFree(localname);
+               if (prefix != NULL) {
+                       xmlFree(prefix);
+               }
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Attribute already exists");
+               return;
+       }
+
+       if (nsuri != NULL) {
+               nsptr = xmlSearchNsByHref(node->doc, node, nsuri);
+               if (nsptr == NULL) {
+                       nsptr = xmlNewNs(node, nsuri, prefix);
+               }
+       }
+
+       attrp = xmlNewNsProp(node, nsptr, localname, value);
+
+       xmlFree(localname);
+       if (prefix != NULL) {
+               xmlFree(prefix);
+       }
+}
+/* }}} */
+
 /* {{{ cast_object()
  */
 static int cast_object(zval *object, int type, char *contents TSRMLS_DC)
@@ -2059,6 +2236,8 @@ static zend_function_entry sxe_functions[] = {
        SXE_ME(getNamespaces,          NULL, ZEND_ACC_PUBLIC)
        SXE_ME(getDocNamespaces,       NULL, ZEND_ACC_PUBLIC)
        SXE_ME(getName,                NULL, ZEND_ACC_PUBLIC)
+       SXE_ME(addChild,               NULL, ZEND_ACC_PUBLIC)
+       SXE_ME(addAttribute,           NULL, ZEND_ACC_PUBLIC)
        {NULL, NULL, NULL}
 };
 
index 0c8f4e28474a5a2ae3ecae1d83fc55fae552f11e..f32786c7cc296d642e54cc5004f3ca0cf252cd1f 100755 (executable)
@@ -61,7 +61,7 @@ $people->person[3]['gender'] = 'error';
   </person>
 </people>
 
-Warning: main(): Cannot add element person number 3 when only 2 such elements exist in %sext/simplexml/tests/027.php on line %d
+Warning: main(): Cannot add element person number 3 when only 2 such elements exist in %s027.php on line %d
 <people>
   <person gender="female">Jane
   </person>
@@ -71,4 +71,4 @@ Warning: main(): Cannot add element person number 3 when only 2 such elements ex
   </person>
 </people>
 
-Fatal error: Objects used as arrays in post/pre increment/decrement must return values by reference in %sext/simplexml/tests/027.php on line %d
+Fatal error: Objects used as arrays in post/pre increment/decrement must return values by reference in %s027.php on line %d
diff --git a/ext/simplexml/tests/030.phpt b/ext/simplexml/tests/030.phpt
new file mode 100644 (file)
index 0000000..774a5f1
--- /dev/null
@@ -0,0 +1,44 @@
+--TEST--
+SimpleXML: isset and unset by offset
+--SKIPIF--
+<?php if (!extension_loaded("simplexml")) print "skip"; ?>
+--FILE--
+<?php 
+$xml =<<<EOF
+<root s:att1="b" att1="a" 
+      xmlns:s="urn::test" xmlns:t="urn::test-t">
+   <child1>test</child1>
+   <child1>test 2</child1>
+   <s:child3 />
+</root>
+EOF;
+
+$sxe = simplexml_load_string($xml);
+
+echo $sxe->child1[0]."\n";
+echo $sxe->child1[1]."\n\n";
+
+var_dump(isset($sxe->child1[1]));
+unset($sxe->child1[1]);
+var_dump(isset($sxe->child1[1]));
+echo "\n";
+
+$atts = $sxe->attributes("urn::test");
+var_dump(isset($atts[0]));
+unset($atts[0]);
+var_dump(isset($atts[0]));
+var_dump(isset($atts[TRUE]));
+
+?>
+===DONE===
+--EXPECT--
+test
+test 2
+
+bool(true)
+bool(false)
+
+bool(true)
+bool(false)
+bool(false)
+===DONE===
diff --git a/ext/simplexml/tests/031.phpt b/ext/simplexml/tests/031.phpt
new file mode 100644 (file)
index 0000000..cd2d266
--- /dev/null
@@ -0,0 +1,57 @@
+--TEST--
+SimpleXML: addChild and addAttribute
+--SKIPIF--
+<?php if (!extension_loaded("simplexml")) print "skip"; ?>
+--FILE--
+<?php 
+$xml =<<<EOF
+<root s:att1="b" att1="a" 
+      xmlns:s="urn::test" xmlns:t="urn::test-t">
+   <child1>test</child1>
+   <child1>test 2</child1>
+   <s:child3 />
+</root>
+EOF;
+
+$sxe = simplexml_load_string($xml);
+
+/* Add new attribute in a new namespace */
+$sxe->addAttribute('v:att11', 'xxx', 'urn::test-v');
+
+/* Try to add attribute again -> display warning as method is for new Attr only */
+$sxe->addAttribute('v:att11', 'xxx', 'urn::test-v');
+
+/* Add new attribute w/o namespace */
+$sxe->addAttribute('att2', 'no-ns');
+
+$d = $sxe->attributes();
+/* Try to add element to attribute -> display warning and do not add */
+$d->addChild('m:test', 'myval', 'urn::test');
+
+
+/* Test adding elements in various configurations */
+$sxe->addChild('m:test1', 'myval', 'urn::test');
+
+/* New namespace test */
+$n = $sxe->addChild('m:test2', 'myval', 'urn::testnew');
+
+$sxe->addChild('test3', 'myval', 'urn::testnew');
+$sxe->addChild('test4', 'myval');
+
+/* Does not add prefix here although name is valid (but discouraged) - change behavior? */
+$sxe->addChild('s:test5', 'myval');
+
+echo $sxe->asXML();
+?>
+===DONE===
+--EXPECTF--
+Warning: SimpleXMLElement::addAttribute(): Attribute already exists in %s031.php on line %d
+
+Warning: SimpleXMLElement::addChild(): Cannot add element to attributes in %s031.php on line %d
+<?xml version="1.0"?>
+<root xmlns:s="urn::test" xmlns:t="urn::test-t" xmlns:v="urn::test-v" s:att1="b" att1="a" v:att11="xxx" att2="no-ns">
+   <child1>test</child1>
+   <child1>test 2</child1>
+   <s:child3/>
+<s:test1>myval</s:test1><m:test2 xmlns:m="urn::testnew">myval</m:test2><test3 xmlns="urn::testnew">myval</test3><test4>myval</test4><test5>myval</test5></root>
+===DONE===
index fb3cea231f40b4ec31e0daea94d47309babe5c13..de65a19565b6b670eecc799dcbdc2c25f92a2cc9 100755 (executable)
@@ -23,4 +23,4 @@ echo $xml->asXML();
 ===FAIL===
 int(0)
 
-Fatal error: Objects used as arrays in post/pre increment/decrement must return values by reference in %sext/simplexml/tests/bug35785.php on line %d
+Fatal error: Objects used as arrays in post/pre increment/decrement must return values by reference in %sbug35785.php on line %d