Hi all,

this patch adds a function that builds an XML fragment from a array. 
Implementation of var_dump has been taken as a skeleton.
The main reason for this patch was that using DOM interface to create a long 
XML (approx 2.5MB) was slow.

Regards

Petr Tuma
? ext/domxml/tests/domxml003.phpt
Index: ext/domxml/php_domxml.c
===================================================================
RCS file: /repository/php4/ext/domxml/php_domxml.c,v
retrieving revision 1.235
diff -u -r1.235 php_domxml.c
--- ext/domxml/php_domxml.c	18 Jan 2003 19:49:23 -0000	1.235
+++ ext/domxml/php_domxml.c	26 Jan 2003 23:13:28 -0000
@@ -276,6 +276,7 @@
 #endif
 #if HAVE_DOMXSLT
 	PHP_FE(domxml_xslt_version,											NULL)
+	PHP_FE(domxml_build,												NULL)
 	PHP_FE(domxml_xslt_stylesheet,										NULL)
 	PHP_FE(domxml_xslt_stylesheet_doc,									NULL)
 	PHP_FE(domxml_xslt_stylesheet_file,									NULL)
@@ -5152,6 +5153,247 @@
 	return params;
 }
 /* }}} */
+
+
+/* {{{ php_domxml_build_array_element()
+*/
+static int php_domxml_build_array_element(zval **zv, int num_args, va_list args, zend_hash_key *hash_key)
+{
+	char  **buffer;
+	unsigned int *bufsize;
+	unsigned int *length;
+	int   enc;
+	int   indent;
+	int   i,j;
+	char *p;
+	TSRMLS_FETCH();
+
+	/* get parameters */
+	buffer  = va_arg(args, char**);
+	bufsize = va_arg(args, unsigned int*);
+	length  = va_arg(args, unsigned int*);
+	enc     = va_arg(args, int);
+	indent  = va_arg(args, int);
+	/* indention */
+	if((*length+32) >= *bufsize) {
+		*bufsize*=2;
+		*buffer=erealloc(*buffer,*bufsize);
+	}
+	if(indent)
+		(*buffer)[(*length)++]='\n';
+	/* opening tag */
+	if (hash_key->nKeyLength==0) {
+		/* numeric key */
+		memcpy(*buffer+*length,"<item index=\"",13);
+		(*length)+=13;
+		p=*buffer+*length;
+		for(i=0,j=hash_key->h;j;i++) {
+			p[i]='0'+j%10;
+			j/=10;
+		}
+		if(!i)
+			p[i++]='0';
+		p[i++]='"';
+		*length+=i;
+	} else {
+		if((*length+hash_key->nKeyLength+1)>=*bufsize) {
+			*bufsize*=2;
+			*buffer=erealloc(*buffer,*bufsize);
+		}
+		/* string key */
+		(*buffer)[(*length)++]='<';
+		memcpy(*buffer+(*length),hash_key->arKey,hash_key->nKeyLength-1);
+		*length+=hash_key->nKeyLength-1;
+	}
+	(*buffer)[(*length)++]='>';
+	/* subtree content */
+	i=php_domxml_build_var(zv, buffer,bufsize,length,enc,indent TSRMLS_CC);
+	/* indention */
+	if(indent && i) {
+		if((*length+1)>+*bufsize) {
+			*bufsize*=2;
+			*buffer=erealloc(*buffer,*bufsize);
+		}
+		(*buffer)[(*length)++]='\n';
+	}
+	/* closing tag */
+	if(hash_key->nKeyLength==0) {
+		if((*length+hash_key->nKeyLength+7)>=*bufsize) {
+			*bufsize*=2;
+			*buffer=erealloc(*buffer,*bufsize);
+		}
+		/* numeric key */
+		memcpy(*buffer+*length,"</item>",7);
+		*length+=7;
+	} else {
+		if((*length+hash_key->nKeyLength+2)>=*bufsize) {
+			*bufsize*=2;
+			*buffer=erealloc(*buffer,*bufsize);
+		}
+		/* string key */
+		(*buffer)[(*length)++]='<';
+		(*buffer)[(*length)++]='/';
+		memcpy(*buffer+(*length),hash_key->arKey,hash_key->nKeyLength-1);
+		*length+=hash_key->nKeyLength-1;
+		(*buffer)[(*length)++]='>';
+	}
+	return 0;
+}
+/* }}} */
+
+
+/* {{{ php_domxml_build_var()
+*/
+static int php_domxml_build_var(zval **struc, char **buffer, unsigned int *bufsize, unsigned int *length, int enc, int indent TSRMLS_DC)
+{
+	HashTable *myht;
+	char*     tmp_str;
+	int       tmp_len;
+	int res=0;
+	static char hexcodes[16]="0123456789abcdef";
+
+	switch (Z_TYPE_PP(struc)) {
+		case IS_STRING: {
+			char *buf=*buffer+*length;
+			char *p=Z_STRVAL_PP(struc);
+			int i=0,j=Z_STRLEN_PP(struc);
+			for(;j>0;j--,p++) {
+				if((*length+i+6)>=*bufsize) {
+					*bufsize*=2;
+					*buffer=erealloc(*buffer,*bufsize);
+					buf=*buffer+*length;
+				}
+				switch(*p) {
+					case '<':
+						buf[i++]='&';
+						buf[i++]='l';
+						buf[i++]='t';
+						buf[i++]=';';
+						break;
+					case '>':
+						buf[i++]='&';
+						buf[i++]='g';
+						buf[i++]='t';
+						buf[i++]=';';
+						break;
+					case '&':
+						buf[i++]='&';
+						buf[i++]='a';
+						buf[i++]='m';
+						buf[i++]='p';
+						buf[i++]=';';
+						break;
+					default:
+						/* already encoded? */
+						if(!enc) {
+							unsigned char c=(unsigned char)*p;
+							if(c<32 || c>127) {
+								buf[i++]='&';
+								buf[i++]='#';
+								buf[i++]='x';
+								buf[i++]=hexcodes[(c>>4)&15];
+								buf[i++]=hexcodes[c&15];
+								buf[i++]=';';
+							} else
+								buf[i++]=*p;
+						} else {
+							buf[i++]=*p;
+						}
+						break;
+				}
+			}
+			*length+=i;
+			break;
+		}
+		case IS_NULL:
+			break;
+		case IS_BOOL:
+			if(Z_LVAL_PP(struc)) {
+				if((*length+1)>=*bufsize) {
+					*bufsize*=2;
+					*buffer=erealloc(*buffer,*bufsize);
+				}
+				(*buffer)[(*length)++]='1';
+			}
+			break;
+		case IS_LONG:
+			if((*length+32)>=*bufsize) {
+				*bufsize*=2;
+				*buffer=erealloc(*buffer,*bufsize);
+			}
+			*length+=sprintf(*buffer+*length,"%ld",Z_LVAL_PP(struc));
+			break;
+		case IS_DOUBLE:
+			if((*length+32)>=*bufsize) {
+				*bufsize*=2;
+				*buffer=erealloc(*buffer,*bufsize);
+			}
+			*length+=sprintf(*buffer+*length,"%G",Z_DVAL_PP(struc));
+			break;
+		case IS_ARRAY:
+			res=1;
+			myht = Z_ARRVAL_PP(struc);
+			zend_hash_apply_with_arguments(myht, (apply_func_args_t) php_domxml_build_array_element, 1, buffer,bufsize,length,enc,indent);
+			break;
+		default:
+			if((*length+1)>=*bufsize) {
+				*bufsize*=2;
+				*buffer=erealloc(*buffer,*bufsize);
+			}
+			(*buffer)[(*length)++]='#';
+			break;
+	}
+	return res;
+}
+/* }}} */
+
+
+/* {{{ proto string domxml_build(array data [, bool encoded [, bool indent]])
+   Dumps an array as an XML fragment. If encoded is false all the characters
+   out of range 32-127 are encoded in the form of &#x??;.
+   If indent is true some kind of indentation is done. */
+PHP_FUNCTION(domxml_build)
+{
+	/* function parameters */
+	zval *array;
+	zend_bool enc=0;
+	zend_bool indent=1;
+	/* output buffer */
+	char *buffer;
+	/* allocated buffer size */
+	unsigned int bufsize=4096;
+	/* actual data length */
+	unsigned int length=0;
+
+	/* get parameters */
+	if(zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|bb", &array, &enc, &indent) == FAILURE) {
+		RETURN_FALSE;
+	}
+	/* init buffer */
+	buffer=emalloc(bufsize);
+	/* fill output element */
+	memcpy(buffer,"<data>",6);
+	length+=6;
+	if(indent)
+		buffer[length++]='\n';
+	/* output array */
+	php_domxml_build_var(&array,&buffer,&bufsize,&length,(int)enc,(int)indent);
+	/* fill the rest */
+	if(length+8>=bufsize) {
+		bufsize+=8;
+		buffer=realloc(buffer,bufsize);
+	}
+	memcpy(buffer+length,"</data>\n",7);
+	length+=7;
+	if(indent)
+		buffer[length++]='\n';
+	/* return string */
+	RETVAL_STRINGL(buffer,length,1);
+	/* free buffer */
+	efree(buffer);
+}
+/* }}} */
+
 
 /* {{{ proto object domxml_xslt_process(object xslstylesheet, object xmldoc [, array xslt_parameters [, bool xpath_parameters [, string profileFilename]]])
    Perform an XSLT transformation */
Index: ext/domxml/php_domxml.h
===================================================================
RCS file: /repository/php4/ext/domxml/php_domxml.h,v
retrieving revision 1.75
diff -u -r1.75 php_domxml.h
--- ext/domxml/php_domxml.h	6 Jan 2003 09:59:53 -0000	1.75
+++ ext/domxml/php_domxml.h	26 Jan 2003 23:13:29 -0000
@@ -227,6 +227,7 @@
 
 /* DOMXSLT functions */
 #if HAVE_DOMXSLT
+PHP_FUNCTION(domxml_build);
 PHP_FUNCTION(domxml_xslt_stylesheet);
 PHP_FUNCTION(domxml_xslt_stylesheet_doc);
 PHP_FUNCTION(domxml_xslt_stylesheet_file);
--TEST--
domxml_build() basic functionality test
--SKIPIF--
<?php require_once('skipif.inc'); ?>
--FILE--
<?php

$a=array(
  "title"   => "Test",
  "rev"     => 10,
  "working" => true,
  "q"       => 4.5783,
  "lines"   => array("something",false,76.5,34));
var_dump(domxml_build($a,true,false));

?>
--EXPECT--
string(200) 
"<data><title>Test</title><rev>10</rev><working>1</working><q>4.5783</q><lines><item 
index="0">something</item><item index="1"></item><item index="2">76.5</item><item 
index="3">34</item></lines></data>"


-- 
PHP Development Mailing List <http://www.php.net/>
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to