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