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