rrichards               Fri May 26 18:23:50 2006 UTC

  Added files:                 (Branch: PHP_5_2)
    /php-src/ext/dom/tests      canonicalization.phpt 

  Modified files:              
    /php-src/ext/dom    dom_fe.h node.c 
  Log:
  MFH: add C14N() and C14NFile() methods to perform XML canonicalization
  add test
  
http://cvs.php.net/viewcvs.cgi/php-src/ext/dom/dom_fe.h?r1=1.14.2.1.2.1&r2=1.14.2.1.2.2&diff_format=u
Index: php-src/ext/dom/dom_fe.h
diff -u php-src/ext/dom/dom_fe.h:1.14.2.1.2.1 
php-src/ext/dom/dom_fe.h:1.14.2.1.2.2
--- php-src/ext/dom/dom_fe.h:1.14.2.1.2.1       Mon May 22 17:12:25 2006
+++ php-src/ext/dom/dom_fe.h    Fri May 26 18:23:50 2006
@@ -17,7 +17,7 @@
    +----------------------------------------------------------------------+
 */
 
-/* $Id: dom_fe.h,v 1.14.2.1.2.1 2006/05/22 17:12:25 rrichards Exp $ */
+/* $Id: dom_fe.h,v 1.14.2.1.2.2 2006/05/26 18:23:50 rrichards Exp $ */
 #ifndef DOM_FE_H
 #define DOM_FE_H
 
@@ -165,6 +165,8 @@
 PHP_FUNCTION(dom_node_get_feature);
 PHP_FUNCTION(dom_node_set_user_data);
 PHP_FUNCTION(dom_node_get_user_data);
+PHP_METHOD(domnode, C14N);
+PHP_METHOD(domnode, C14NFile);
 
 /* domnodelist methods */
 PHP_FUNCTION(dom_nodelist_item);
http://cvs.php.net/viewcvs.cgi/php-src/ext/dom/node.c?r1=1.37.2.3&r2=1.37.2.3.2.1&diff_format=u
Index: php-src/ext/dom/node.c
diff -u php-src/ext/dom/node.c:1.37.2.3 php-src/ext/dom/node.c:1.37.2.3.2.1
--- php-src/ext/dom/node.c:1.37.2.3     Wed Jan 25 17:34:05 2006
+++ php-src/ext/dom/node.c      Fri May 26 18:23:50 2006
@@ -17,7 +17,7 @@
    +----------------------------------------------------------------------+
 */
 
-/* $Id: node.c,v 1.37.2.3 2006/01/25 17:34:05 rrichards Exp $ */
+/* $Id: node.c,v 1.37.2.3.2.1 2006/05/26 18:23:50 rrichards Exp $ */
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
@@ -53,6 +53,8 @@
        PHP_FALIAS(getFeature, dom_node_get_feature, NULL)
        PHP_FALIAS(setUserData, dom_node_set_user_data, NULL)
        PHP_FALIAS(getUserData, dom_node_get_user_data, NULL)
+       PHP_ME(domnode, C14N, NULL, ZEND_ACC_PUBLIC)
+       PHP_ME(domnode, C14NFile, NULL, ZEND_ACC_PUBLIC)
        {NULL, NULL, NULL}
 };
 
@@ -1669,4 +1671,189 @@
  DOM_NOT_IMPLEMENTED();
 }
 /* }}} end dom_node_get_user_data */
+
+
+static void dom_canonicalization(INTERNAL_FUNCTION_PARAMETERS, int mode)
+{
+       zval *id;
+       zval *xpath_array=NULL, *ns_prefixes=NULL;
+       xmlNodePtr nodep;
+       xmlDocPtr docp;
+       xmlNodeSetPtr nodeset = NULL;
+       dom_object *intern;
+       long exclusive=0, with_comments=0, file_len=0;
+       xmlChar **inclusive_ns_prefixes = NULL;
+       char *file = NULL;
+    int ret = -1;
+    xmlOutputBufferPtr buf;
+       xmlXPathContextPtr ctxp=NULL;
+       xmlXPathObjectPtr xpathobjp=NULL;
+
+       if (mode == 0) {
+               if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, 
getThis(), 
+                       "O|bba!a!", &id, dom_node_class_entry, &exclusive, 
&with_comments, 
+                       &xpath_array, &ns_prefixes) == FAILURE) {
+                       return;
+               }
+       } else {
+               if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, 
getThis(), 
+                       "Os|bba!a!", &id, dom_node_class_entry, &file, 
&file_len, &exclusive, 
+                       &with_comments, &xpath_array, &ns_prefixes) == FAILURE) 
{
+                       return;
+               }
+       }
+
+       DOM_GET_OBJ(nodep, id, xmlNodePtr, intern);
+
+       docp = nodep->doc;
+
+       if (! docp) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Node must be 
associated with a document");
+               RETURN_FALSE;
+       }
+
+       if (xpath_array == NULL) {
+               if (nodep->type != XML_DOCUMENT_NODE) {
+                       ctxp = xmlXPathNewContext(docp);
+                       ctxp->node = nodep;
+                       xpathobjp = xmlXPathEvalExpression("(.//. | .//@* | 
.//namespace::*)", ctxp);
+                       ctxp->node = NULL;
+                       if (xpathobjp && xpathobjp->type == XPATH_NODESET) {
+                               nodeset = xpathobjp->nodesetval;
+                       } else {
+                               if (xpathobjp) {
+                                       xmlXPathFreeObject(xpathobjp);
+                               }
+                               xmlXPathFreeContext(ctxp);
+                               php_error_docref(NULL TSRMLS_CC, E_WARNING, 
"XPath query did not return a nodeset.");
+                               RETURN_FALSE;
+                       }
+               }
+       } else {
+               /*xpath query from xpath_array */
+               HashTable *ht = Z_ARRVAL_P(xpath_array);
+               zval **tmp;
+               char *xquery;
+
+               if (zend_hash_find(ht, "query", sizeof("query"), (void**)&tmp) 
== SUCCESS &&
+                   Z_TYPE_PP(tmp) == IS_STRING) {
+                       xquery = Z_STRVAL_PP(tmp);
+               } else {
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "'query' 
missing from xpath array or is not a string");
+                       RETURN_FALSE;
+               }
+
+               ctxp = xmlXPathNewContext(docp);
+               ctxp->node = nodep;
+
+               if (zend_hash_find(ht, "namespaces", sizeof("namespaces"), 
(void**)&tmp) == SUCCESS &&
+                   Z_TYPE_PP(tmp) == IS_ARRAY) {
+                       zval **tmpns;
+                       while (zend_hash_get_current_data(Z_ARRVAL_PP(tmp), 
(void **)&tmpns) == SUCCESS) {
+                               if (Z_TYPE_PP(tmpns) == IS_STRING) {
+                                       char *prefix;
+                                       ulong idx;
+                                       int prefix_key_len;
+
+                                       if 
(zend_hash_get_current_key_ex(Z_ARRVAL_PP(tmp), 
+                                               &prefix, &prefix_key_len, &idx, 
0, NULL) == HASH_KEY_IS_STRING) {
+                                               xmlXPathRegisterNs(ctxp, 
prefix, Z_STRVAL_PP(tmpns));
+                                       }
+                               }
+                               zend_hash_move_forward(Z_ARRVAL_PP(tmp));
+                       }
+               }
+
+               xpathobjp = xmlXPathEvalExpression(xquery, ctxp);
+               ctxp->node = NULL;
+               if (xpathobjp && xpathobjp->type == XPATH_NODESET) {
+                       nodeset = xpathobjp->nodesetval;
+               } else {
+                       if (xpathobjp) {
+                               xmlXPathFreeObject(xpathobjp);
+                       }
+                       xmlXPathFreeContext(ctxp);
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "XPath 
query did not return a nodeset.");
+                       RETURN_FALSE;
+               }
+       }
+
+       if (ns_prefixes != NULL) {
+               if (exclusive) {
+                       zval **tmpns;
+                       int nscount = 0;
+
+                       inclusive_ns_prefixes = 
safe_emalloc(zend_hash_num_elements(Z_ARRVAL_P(ns_prefixes)) + 1,
+                               sizeof(xmlChar *), 0);
+                       while 
(zend_hash_get_current_data(Z_ARRVAL_P(ns_prefixes), (void **)&tmpns) == 
SUCCESS) {
+                               if (Z_TYPE_PP(tmpns) == IS_STRING) {
+                                       inclusive_ns_prefixes[nscount++] = 
Z_STRVAL_PP(tmpns);
+                               }
+                               zend_hash_move_forward(Z_ARRVAL_P(ns_prefixes));
+                       }
+                       inclusive_ns_prefixes[nscount] = NULL;
+               } else {
+                       php_error_docref(NULL TSRMLS_CC, E_NOTICE, 
+                               "Inclusive namespace prefixes only allowed in 
exlcusive mode.");
+               }
+       }
+
+       if (mode == 1) {
+               buf = xmlOutputBufferCreateFilename(file, NULL, 0);
+       } else {
+               buf = xmlAllocOutputBuffer(NULL);
+       }
+
+    if (buf != NULL) {
+               ret = xmlC14NDocSaveTo(docp, nodeset, exclusive, 
inclusive_ns_prefixes,
+                       with_comments, buf);
+       }
+
+       if (inclusive_ns_prefixes != NULL) {
+               efree(inclusive_ns_prefixes);
+       }
+       if (xpathobjp != NULL) {
+               xmlXPathFreeObject(xpathobjp);
+       }
+       if (ctxp != NULL) {
+               xmlXPathFreeContext(ctxp);
+       }
+
+    if (buf == NULL || ret < 0) {
+        RETVAL_FALSE;
+    } else {
+               if (mode == 0) {
+                       ret = buf->buffer->use;
+                       if (ret > 0) {
+                               RETVAL_STRINGL((char *) buf->buffer->content, 
ret, 1);
+                       } else {
+                               RETVAL_EMPTY_STRING();
+                       }
+               }
+    }
+
+       if (buf) {
+               int bytes;
+
+               bytes = xmlOutputBufferClose(buf);
+               if (mode == 1 && (ret >= 0)) {
+                       RETURN_LONG(bytes);
+               }
+       }
+}
+
+/* {{{ proto string DOMNode::C14N([bool exclusive [, bool with_comments [, 
array xpath [, array ns_prefixes]]]])
+   Canonicalize nodes to a string */
+PHP_METHOD(domnode, C14N)
+{
+       dom_canonicalization(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
+}
+
+/* {{{ proto int DOMNode::C14NFile(string uri [, bool exclusive [, bool 
with_comments [, array xpath [, array ns_prefixes]]]])
+   Canonicalize nodes to a file */
+PHP_METHOD(domnode, C14NFile)
+{
+       dom_canonicalization(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
+}
+
 #endif

http://cvs.php.net/viewcvs.cgi/php-src/ext/dom/tests/canonicalization.phpt?view=markup&rev=1.1
Index: php-src/ext/dom/tests/canonicalization.phpt
+++ php-src/ext/dom/tests/canonicalization.phpt
--TEST--
Test: Canonicalization - C14N()
--SKIPIF--
<?php require_once('skipif.inc'); ?>
--FILE--
<?php
$xml = <<<EOXML
<?xml version="1.0" encoding="ISO-8859-1" ?>
<foo xmlns="http://www.example.com/ns/foo";
     xmlns:fubar="http://www.example.com/ns/fubar"; 
xmlns:test="urn::test"><contain>
  <bar><test1 /></bar>
  <bar><test2 /></bar>
  <fubar:bar xmlns:fubar="http://www.example.com/ns/fubar";><test3 /></fubar:bar>
  <fubar:bar><test4 /></fubar:bar>
<!-- this is a comment -->
</contain>
</foo>
EOXML;

$dom = new DOMDocument();
$dom->loadXML($xml);
$doc = $dom->documentElement->firstChild;

/* inclusive/without comments first child element of doc element is context. */
echo $doc->C14N()."\n\n";

/* exclusive/without comments first child element of doc element is context. */
echo $doc->c14N(TRUE)."\n\n";

/* inclusive/with comments first child element of doc element is context. */
echo $doc->C14N(FALSE, TRUE)."\n\n";

/* exclusive/with comments first child element of doc element is context. */
echo $doc->C14N(TRUE, TRUE)."\n\n";

/* exclusive/without comments using xpath query. */
echo $doc->c14N(TRUE, FALSE, array('query'=>'(//. | //@* | 
//namespace::*)'))."\n\n";

/* exclusive/without comments first child element of doc element is context.
   using xpath query with registered namespace.
   test namespace prefix is also included. */
echo $doc->c14N(TRUE, FALSE, 
                array('query'=>'(//a:contain | //a:bar | .//namespace::*)', 
                      
'namespaces'=>array('a'=>'http://www.example.com/ns/foo')), 
                array('test'))."\n\n";

/* exclusive/without comments first child element of doc element is context. 
   test namespace prefix is also included */
echo $doc->C14N(TRUE, FALSE, NULL, array('test'));
?>
--EXPECTF--

<contain xmlns="http://www.example.com/ns/foo"; 
xmlns:fubar="http://www.example.com/ns/fubar"; xmlns:test="urn::test">
  <bar><test1></test1></bar>
  <bar><test2></test2></bar>
  <fubar:bar><test3></test3></fubar:bar>
  <fubar:bar><test4></test4></fubar:bar>

</contain>

<contain xmlns="http://www.example.com/ns/foo";>
  <bar><test1></test1></bar>
  <bar><test2></test2></bar>
  <fubar:bar 
xmlns:fubar="http://www.example.com/ns/fubar";><test3></test3></fubar:bar>
  <fubar:bar 
xmlns:fubar="http://www.example.com/ns/fubar";><test4></test4></fubar:bar>

</contain>

<contain xmlns="http://www.example.com/ns/foo"; 
xmlns:fubar="http://www.example.com/ns/fubar"; xmlns:test="urn::test">
  <bar><test1></test1></bar>
  <bar><test2></test2></bar>
  <fubar:bar><test3></test3></fubar:bar>
  <fubar:bar><test4></test4></fubar:bar>
<!-- this is a comment -->
</contain>

<contain xmlns="http://www.example.com/ns/foo";>
  <bar><test1></test1></bar>
  <bar><test2></test2></bar>
  <fubar:bar 
xmlns:fubar="http://www.example.com/ns/fubar";><test3></test3></fubar:bar>
  <fubar:bar 
xmlns:fubar="http://www.example.com/ns/fubar";><test4></test4></fubar:bar>
<!-- this is a comment -->
</contain>

<foo xmlns="http://www.example.com/ns/foo";><contain>
  <bar><test1></test1></bar>
  <bar><test2></test2></bar>
  <fubar:bar 
xmlns:fubar="http://www.example.com/ns/fubar";><test3></test3></fubar:bar>
  <fubar:bar 
xmlns:fubar="http://www.example.com/ns/fubar";><test4></test4></fubar:bar>

</contain>
</foo>

<contain xmlns="http://www.example.com/ns/foo"; 
xmlns:test="urn::test"><bar></bar><bar></bar></contain>

<contain xmlns="http://www.example.com/ns/foo"; xmlns:test="urn::test">
  <bar><test1></test1></bar>
  <bar><test2></test2></bar>
  <fubar:bar 
xmlns:fubar="http://www.example.com/ns/fubar";><test3></test3></fubar:bar>
  <fubar:bar 
xmlns:fubar="http://www.example.com/ns/fubar";><test4></test4></fubar:bar>

</contain>

-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to