@@ -632,6 +632,14 @@ static int sxe_prop_dim_exists(zval *object, zval *member, int check_empty, zend
632632 xmlAttrPtr attr = NULL ;
633633 int exists = 0 ;
634634 int test = 0 ;
635+ zval tmp_zv ;
636+
637+ if (Z_TYPE_P (member ) != IS_STRING && Z_TYPE_P (member ) != IS_LONG ) {
638+ tmp_zv = * member ;
639+ zval_copy_ctor (& tmp_zv );
640+ member = & tmp_zv ;
641+ convert_to_string (member );
642+ }
635643
636644 sxe = php_sxe_fetch_object (object TSRMLS_CC );
637645
@@ -661,13 +669,28 @@ static int sxe_prop_dim_exists(zval *object, zval *member, int check_empty, zend
661669
662670 if (node ) {
663671 if (attribs ) {
664- while (attr ) {
665- if ((!test || !xmlStrcmp (attr -> name , sxe -> iter .name )) && !xmlStrcmp (attr -> name , Z_STRVAL_P (member )) && match_ns (sxe , (xmlNodePtr ) attr , sxe -> iter .nsprefix )) {
666- exists = 1 ;
667- break ;
672+ if (Z_TYPE_P (member ) == IS_LONG ) {
673+ int nodendx = 0 ;
674+
675+ while (attr && nodendx <= Z_LVAL_P (member )) {
676+ if ((!test || !xmlStrcmp (attr -> name , sxe -> iter .name )) && match_ns (sxe , (xmlNodePtr ) attr , sxe -> iter .nsprefix )) {
677+ if (nodendx == Z_LVAL_P (member )) {
678+ exists = 1 ;
679+ break ;
680+ }
681+ nodendx ++ ;
682+ }
683+ attr = attr -> next ;
668684 }
685+ } else {
686+ while (attr ) {
687+ if ((!test || !xmlStrcmp (attr -> name , sxe -> iter .name )) && !xmlStrcmp (attr -> name , Z_STRVAL_P (member )) && match_ns (sxe , (xmlNodePtr ) attr , sxe -> iter .nsprefix )) {
688+ exists = 1 ;
689+ break ;
690+ }
669691
670- attr = attr -> next ;
692+ attr = attr -> next ;
693+ }
671694 }
672695 }
673696
@@ -679,14 +702,6 @@ static int sxe_prop_dim_exists(zval *object, zval *member, int check_empty, zend
679702 node = sxe_get_element_by_offset (sxe , Z_LVAL_P (member ), node , NULL );
680703 }
681704 else {
682- zval tmp_zv ;
683-
684- if (Z_TYPE_P (member ) != IS_STRING ) {
685- tmp_zv = * member ;
686- zval_copy_ctor (& tmp_zv );
687- member = & tmp_zv ;
688- convert_to_string (member );
689- }
690705 node = node -> children ;
691706 while (node ) {
692707 xmlNodePtr nnext ;
@@ -696,16 +711,17 @@ static int sxe_prop_dim_exists(zval *object, zval *member, int check_empty, zend
696711 }
697712 node = nnext ;
698713 }
699- if (member == & tmp_zv ) {
700- zval_dtor (& tmp_zv );
701- }
702714 }
703715 if (node ) {
704716 exists = 1 ;
705717 }
706718 }
707719 }
708720
721+ if (member == & tmp_zv ) {
722+ zval_dtor (& tmp_zv );
723+ }
724+
709725 return exists ;
710726}
711727/* }}} */
@@ -733,12 +749,12 @@ static void sxe_prop_dim_delete(zval *object, zval *member, zend_bool elements,
733749 php_sxe_object * sxe ;
734750 xmlNodePtr node ;
735751 xmlNodePtr nnext ;
736- xmlAttrPtr attr ;
752+ xmlAttrPtr attr = NULL ;
737753 xmlAttrPtr anext ;
738754 zval tmp_zv ;
739- int test ;
755+ int test = 0 ;
740756
741- if (Z_TYPE_P (member ) != IS_STRING ) {
757+ if (Z_TYPE_P (member ) != IS_STRING && Z_TYPE_P ( member ) != IS_LONG ) {
742758 tmp_zv = * member ;
743759 zval_copy_ctor (& tmp_zv );
744760 member = & tmp_zv ;
@@ -748,45 +764,83 @@ static void sxe_prop_dim_delete(zval *object, zval *member, zend_bool elements,
748764 sxe = php_sxe_fetch_object (object TSRMLS_CC );
749765
750766 GET_NODE (sxe , node );
767+
768+ if (Z_TYPE_P (member ) == IS_LONG ) {
769+ if (sxe -> iter .type != SXE_ITER_ATTRLIST ) {
770+ attribs = 0 ;
771+ elements = 1 ;
772+ if (sxe -> iter .type == SXE_ITER_CHILD ) {
773+ node = php_sxe_get_first_node (sxe , node TSRMLS_CC );
774+ }
775+ }
776+ }
777+
751778 if (sxe -> iter .type == SXE_ITER_ATTRLIST ) {
752779 attribs = 1 ;
753780 elements = 0 ;
754781 node = php_sxe_get_first_node (sxe , node TSRMLS_CC );
755782 attr = (xmlAttrPtr )node ;
756783 test = sxe -> iter .name != NULL ;
757- } else {
784+ } else if ( sxe -> iter . type != SXE_ITER_CHILD ) {
758785 node = php_sxe_get_first_node (sxe , node TSRMLS_CC );
759786 attr = node ? node -> properties : NULL ;
760787 test = 0 ;
761788 }
762789
763790 if (node ) {
764791 if (attribs ) {
765- while (attr ) {
766- anext = attr -> next ;
767- if ((!test || !xmlStrcmp (attr -> name , sxe -> iter .name )) && !xmlStrcmp (attr -> name , Z_STRVAL_P (member )) && match_ns (sxe , (xmlNodePtr ) attr , sxe -> iter .nsprefix )) {
768- xmlUnlinkNode ((xmlNodePtr ) attr );
769- php_libxml_node_free_resource ((xmlNodePtr ) attr TSRMLS_CC );
770- break ;
792+ if (Z_TYPE_P (member ) == IS_LONG ) {
793+ int nodendx = 0 ;
794+
795+ while (attr && nodendx <= Z_LVAL_P (member )) {
796+ if ((!test || !xmlStrcmp (attr -> name , sxe -> iter .name )) && match_ns (sxe , (xmlNodePtr ) attr , sxe -> iter .nsprefix )) {
797+ if (nodendx == Z_LVAL_P (member )) {
798+ xmlUnlinkNode ((xmlNodePtr ) attr );
799+ php_libxml_node_free_resource ((xmlNodePtr ) attr TSRMLS_CC );
800+ break ;
801+ }
802+ nodendx ++ ;
803+ }
804+ attr = attr -> next ;
805+ }
806+ } else {
807+ while (attr ) {
808+ anext = attr -> next ;
809+ if ((!test || !xmlStrcmp (attr -> name , sxe -> iter .name )) && !xmlStrcmp (attr -> name , Z_STRVAL_P (member )) && match_ns (sxe , (xmlNodePtr ) attr , sxe -> iter .nsprefix )) {
810+ xmlUnlinkNode ((xmlNodePtr ) attr );
811+ php_libxml_node_free_resource ((xmlNodePtr ) attr TSRMLS_CC );
812+ break ;
813+ }
814+ attr = anext ;
771815 }
772- attr = anext ;
773816 }
774817 }
775818
776819 if (elements ) {
777- node = node -> children ;
778- while (node ) {
779- nnext = node -> next ;
780-
781- SKIP_TEXT (node );
782-
783- if (!xmlStrcmp (node -> name , Z_STRVAL_P (member ))) {
820+ if (Z_TYPE_P (member ) == IS_LONG ) {
821+ if (sxe -> iter .type == SXE_ITER_CHILD ) {
822+ node = php_sxe_get_first_node (sxe , node TSRMLS_CC );
823+ }
824+ node = sxe_get_element_by_offset (sxe , Z_LVAL_P (member ), node , NULL );
825+ if (node ) {
784826 xmlUnlinkNode (node );
785827 php_libxml_node_free_resource (node TSRMLS_CC );
786828 }
829+ } else {
830+ node = node -> children ;
831+ while (node ) {
832+ nnext = node -> next ;
833+
834+ SKIP_TEXT (node );
835+
836+ if (!xmlStrcmp (node -> name , Z_STRVAL_P (member ))) {
837+ xmlUnlinkNode (node );
838+ php_libxml_node_free_resource (node TSRMLS_CC );
839+ }
787840
788841next_iter :
789- node = nnext ;
842+ node = nnext ;
843+ }
790844 }
791845 }
792846 }
@@ -1356,6 +1410,129 @@ SXE_METHOD(attributes)
13561410}
13571411/* }}} */
13581412
1413+ /* {{{ proto void SimpleXMLElement::addChild(string qName [, string value [,string ns]])
1414+ Add Element with optional namespace information */
1415+ SXE_METHOD (addChild )
1416+ {
1417+ php_sxe_object * sxe ;
1418+ char * qname , * value = NULL , * nsuri = NULL ;
1419+ int qname_len , value_len = 0 , nsuri_len = 0 ;
1420+ xmlNodePtr node , newnode ;
1421+ xmlNsPtr nsptr = NULL ;
1422+ xmlChar * localname , * prefix = NULL ;
1423+
1424+ if (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC , "s|s!s!" ,
1425+ & qname , & qname_len , & value , & value_len , & nsuri , & nsuri_len ) == FAILURE ) {
1426+ return ;
1427+ }
1428+
1429+ if (qname_len == 0 ) {
1430+ php_error_docref (NULL TSRMLS_CC , E_WARNING , "Element name is required" );
1431+ return ;
1432+ }
1433+
1434+ sxe = php_sxe_fetch_object (getThis () TSRMLS_CC );
1435+ GET_NODE (sxe , node );
1436+
1437+ if (sxe -> iter .type == SXE_ITER_ATTRLIST ) {
1438+ php_error_docref (NULL TSRMLS_CC , E_WARNING , "Cannot add element to attributes" );
1439+ return ;
1440+ }
1441+
1442+ node = php_sxe_get_first_node (sxe , node TSRMLS_CC );
1443+
1444+ localname = xmlSplitQName2 (qname , & prefix );
1445+ if (localname == NULL ) {
1446+ localname = xmlStrdup (qname );
1447+ }
1448+
1449+
1450+ newnode = xmlNewChild (node , NULL , localname , value );
1451+
1452+ if (nsuri != NULL ) {
1453+ nsptr = xmlSearchNsByHref (node -> doc , node , nsuri );
1454+ if (nsptr == NULL ) {
1455+ nsptr = xmlNewNs (newnode , nsuri , prefix );
1456+ }
1457+ newnode -> ns = nsptr ;
1458+ }
1459+
1460+ _node_as_zval (sxe , newnode , return_value , SXE_ITER_NONE , localname , prefix TSRMLS_CC );
1461+
1462+ xmlFree (localname );
1463+ if (prefix != NULL ) {
1464+ xmlFree (prefix );
1465+ }
1466+ }
1467+ /* }}} */
1468+
1469+ /* {{{ proto void SimpleXMLElement::addAttribute(string qName, string value [,string ns])
1470+ Add Attribute with optional namespace information */
1471+ SXE_METHOD (addAttribute )
1472+ {
1473+ php_sxe_object * sxe ;
1474+ char * qname , * value = NULL , * nsuri = NULL ;
1475+ int qname_len , value_len = 0 , nsuri_len = 0 ;
1476+ xmlNodePtr node ;
1477+ xmlAttrPtr attrp = NULL ;
1478+ xmlNsPtr nsptr = NULL ;
1479+ xmlChar * localname , * prefix = NULL ;
1480+
1481+ if (zend_parse_parameters (ZEND_NUM_ARGS () TSRMLS_CC , "ss|s!" ,
1482+ & qname , & qname_len , & value , & value_len , & nsuri , & nsuri_len ) == FAILURE ) {
1483+ return ;
1484+ }
1485+
1486+ if (qname_len == 0 || value_len == 0 ) {
1487+ php_error_docref (NULL TSRMLS_CC , E_WARNING , "Attribute name and value are required" );
1488+ return ;
1489+ }
1490+
1491+ sxe = php_sxe_fetch_object (getThis () TSRMLS_CC );
1492+ GET_NODE (sxe , node );
1493+
1494+ node = php_sxe_get_first_node (sxe , node TSRMLS_CC );
1495+
1496+ if (node -> type != XML_ELEMENT_NODE ) {
1497+ node = node -> parent ;
1498+ }
1499+
1500+ if (node == NULL ) {
1501+ php_error_docref (NULL TSRMLS_CC , E_WARNING , "Unable to locate parent Element" );
1502+ return ;
1503+ }
1504+
1505+ localname = xmlSplitQName2 (qname , & prefix );
1506+ if (localname == NULL ) {
1507+ localname = xmlStrdup (qname );
1508+ }
1509+
1510+ attrp = xmlHasNsProp (node , localname , nsuri );
1511+ if (attrp != NULL && attrp -> type != XML_ATTRIBUTE_DECL ) {
1512+ xmlFree (localname );
1513+ if (prefix != NULL ) {
1514+ xmlFree (prefix );
1515+ }
1516+ php_error_docref (NULL TSRMLS_CC , E_WARNING , "Attribute already exists ");
1517+ return ;
1518+ }
1519+
1520+ if (nsuri != NULL ) {
1521+ nsptr = xmlSearchNsByHref (node -> doc , node , nsuri );
1522+ if (nsptr == NULL ) {
1523+ nsptr = xmlNewNs (node , nsuri , prefix );
1524+ }
1525+ }
1526+
1527+ attrp = xmlNewNsProp (node , nsptr , localname , value );
1528+
1529+ xmlFree (localname );
1530+ if (prefix != NULL ) {
1531+ xmlFree (prefix );
1532+ }
1533+ }
1534+ /* }}} */
1535+
13591536/* {{{ cast_object()
13601537 */
13611538static int cast_object (zval * object , int type , char * contents TSRMLS_DC )
@@ -2059,6 +2236,8 @@ static zend_function_entry sxe_functions[] = {
20592236 SXE_ME (getNamespaces , NULL , ZEND_ACC_PUBLIC )
20602237 SXE_ME (getDocNamespaces , NULL , ZEND_ACC_PUBLIC )
20612238 SXE_ME (getName , NULL , ZEND_ACC_PUBLIC )
2239+ SXE_ME (addChild , NULL , ZEND_ACC_PUBLIC )
2240+ SXE_ME (addAttribute , NULL , ZEND_ACC_PUBLIC )
20622241 {NULL , NULL , NULL }
20632242};
20642243
0 commit comments