Commits

pa...@9ae0c189-cd1f-4510-a509-f4891f5cf20d  committed 970403f

XPathContext can be passed to toStringC14N and toStringEC14N (e.g. to provide ns mapping)

  • Participants
  • Parent commits 07a0070

Comments (0)

Files changed (4)

 }
 
 sub toStringC14N {
-    my ($self, $comments, $xpath) = (shift, shift, shift);
+    my ($self, $comments, $xpath, $xpc) = @_;
     return $self->_toStringC14N( $comments || 0,
 				 (defined $xpath ? $xpath : undef),
 				 0,
-				 undef );
+				 undef,
+				 (defined $xpc ? $xpc : undef)
+				);
 }
 sub toStringEC14N {
-    my ($self, $comments, $xpath, $inc_prefix_list) = @_;
+    my ($self, $comments, $xpath, $xpc, $inc_prefix_list) = @_;
+    unless (UNIVERSAL::isa($xpc,'XML::LibXML::XPathContext')) {
+      if ($inc_prefix_list) {
+	croak("toStringEC14N: 3rd argument is not an XML::LibXML::XPathContext");
+      } else {
+	$inc_prefix_list=$xpc;
+	$xpc=undef;
+      }
+    }
     if (defined($inc_prefix_list) and !UNIVERSAL::isa($inc_prefix_list,'ARRAY')) {
       croak("toStringEC14N: inclusive_prefix_list must be undefined or ARRAY");
     }
     return $self->_toStringC14N( $comments || 0,
 				 (defined $xpath ? $xpath : undef),
 				 1,
-				 (defined $inc_prefix_list ? $inc_prefix_list : undef));
+				 (defined $inc_prefix_list ? $inc_prefix_list : undef),
+				 (defined $xpc ? $xpc : undef)
+				);
 }
 
 *serialize_c14n = \&toStringC14N;
 
 
 SV *
-_toStringC14N(self, comments=0, xpath=&PL_sv_undef, exclusive=0, inc_prefix_list=NULL)
+_toStringC14N(self, comments=0, xpath=&PL_sv_undef, exclusive=0, inc_prefix_list=NULL, xpath_context)
         xmlNodePtr self
         int comments
         SV * xpath
         int exclusive
         char** inc_prefix_list
+        SV * xpath_context
 
     PREINIT:
         xmlChar *result               = NULL;
         xmlChar *nodepath             = NULL;
         xmlXPathContextPtr child_ctxt = NULL;
-        xmlXPathObjectPtr child_xpath = NULL;
+        xmlXPathObjectPtr xpath_res = NULL;
         xmlNodeSetPtr nodelist        = NULL;
         xmlNodePtr refNode            = NULL;
         PREINIT_SAVED_ERROR
             if (comments)
 	      nodepath = xmlStrdup( (const xmlChar *) "(. | .//node() | .//@* | .//namespace::*)" );
             else
-                nodepath = xmlStrdup( (const xmlChar *) "(. | .//node() | .//@* | .//namespace::*)[not(self::comment())]" );
+              nodepath = xmlStrdup( (const xmlChar *) "(. | .//node() | .//@* | .//namespace::*)[not(self::comment())]" );
         }
 
         if ( nodepath != NULL ) {
                  || self->type == XML_DOCB_DOCUMENT_NODE ) {
                 refNode = xmlDocGetRootElement( self->doc );
             }
-
-            child_ctxt = xmlXPathNewContext(self->doc);
+	    if (SvOK(xpath_context)) {
+	      child_ctxt = INT2PTR(xmlXPathContextPtr,SvIV(SvRV(xpath_context)));
+	      if ( child_ctxt == NULL ) {
+		croak("XPathContext: missing xpath context\n");
+	      }
+	    } else {
+	      xpath_context = NULL;
+	      child_ctxt = xmlXPathNewContext(self->doc);
+	    }
             if (!child_ctxt) {
                 if ( nodepath != NULL ) {
                     xmlFree( nodepath );
             }
 
             child_ctxt->node = self;
-            /* get the namespace information */
-            if (self->type == XML_DOCUMENT_NODE) {
-                child_ctxt->namespaces = xmlGetNsList( self->doc,
-                                                       xmlDocGetRootElement( self->doc ) );
-            }
-            else {
-                child_ctxt->namespaces = xmlGetNsList(self->doc, self);
-            }
-            child_ctxt->nsNr = 0;
-            if (child_ctxt->namespaces != NULL) {
-                while (child_ctxt->namespaces[child_ctxt->nsNr] != NULL)
-                child_ctxt->nsNr++;
-            }
-
-            child_xpath = xmlXPathEval(nodepath, child_ctxt);
-            if (child_xpath == NULL) {
-                if (child_ctxt->namespaces != NULL) {
-                    xmlFree( child_ctxt->namespaces );
-                }
-                xmlXPathFreeContext(child_ctxt);
-                if ( nodepath != NULL ) {
-                    xmlFree( nodepath );
-                }
+	    LibXML_configure_namespaces(child_ctxt);
+
+            xpath_res = xmlXPathEval(nodepath, child_ctxt);
+	    if (child_ctxt->namespaces != NULL) {
+	      xmlFree( child_ctxt->namespaces );
+	      child_ctxt->namespaces = NULL;
+	    }
+	    if (!xpath_context) xmlXPathFreeContext(child_ctxt);
+	    if ( nodepath != NULL ) {
+	      xmlFree( nodepath );
+	    }
+
+            if (xpath_res == NULL) {
                 croak("2 Failed to compile xpath expression");
             }
 
-            nodelist = child_xpath->nodesetval;
+            nodelist = xpath_res->nodesetval;
             if ( nodelist == NULL ) {
-                xmlFree( nodepath );
-                xmlXPathFreeObject(child_xpath);
-                if (child_ctxt->namespaces != NULL) {
-                    xmlFree( child_ctxt->namespaces );
-                }
-                xmlXPathFreeContext(child_ctxt);
+                xmlXPathFreeObject(xpath_res);
                 croak( "cannot canonize empty nodeset!" );
             }
         }
                               comments,
                               &result );
 
-        if ( child_xpath ) {
-            xmlXPathFreeObject(child_xpath);
-        }
-        if ( child_ctxt ) {
-            if (child_ctxt->namespaces != NULL) {
-                xmlFree( child_ctxt->namespaces );
-            }
-            xmlXPathFreeContext(child_ctxt);
-        }
-        if ( nodepath != NULL ) {
-            xmlFree( nodepath );
-        }
+        if ( xpath_res ) xmlXPathFreeObject(xpath_res);
         CLEANUP_ERROR_HANDLER;
         REPORT_ERROR(0);
 

File docs/libxml.dbk

                 <term>toStringC14N</term>
 
                 <listitem>
-                    <para><funcsynopsis><funcsynopsisinfo>$c14nstr = $doc-&gt;toStringC14N($comment_flag,$xpath); </funcsynopsisinfo></funcsynopsis>
+                    <para><funcsynopsis><funcsynopsisinfo>$c14nstr = $doc-&gt;toStringC14N($comment_flag, $xpath [, $xpath_context ]); </funcsynopsisinfo></funcsynopsis>
 	            See the documentation in <xref linkend="XML-LibXML-Node"/>.
                     </para>
                 </listitem>
                 <term>toStringEC14N</term>
 
                 <listitem>
-                    <para><funcsynopsis><funcsynopsisinfo>$ec14nstr = $doc-&gt;toStringEC14N($inclusive_prefix_list, $comment_flag,$xpath); </funcsynopsisinfo></funcsynopsis>
+                    <para><funcsynopsis><funcsynopsisinfo>$ec14nstr = $doc-&gt;toStringEC14N($comment_flag, $xpath [, $xpath_context ], $inclusive_prefix_list); </funcsynopsisinfo></funcsynopsis>
 	            See the documentation in <xref linkend="XML-LibXML-Node"/>.
                    </para>
                 </listitem>
                 <term>serialize_c14n</term>
 
                 <listitem>
-                    <funcsynopsis>
-                        <funcsynopsisinfo>$c14nstr = $doc-&gt;serialize_c14n($comment_flag,$xpath); </funcsynopsisinfo>
-                    </funcsynopsis>
-
                     <para>An alias for toStringC14N().</para>
                 </listitem>
             </varlistentry>
                 <term>serialize_exc_c14n</term>
 
                 <listitem>
-                    <funcsynopsis>
-                        <funcsynopsisinfo>$ec14nstr = $doc-&gt;serialize_exc_c14n($comment_flag,$xpath,$inclusive_prefix_list); </funcsynopsisinfo>
-                    </funcsynopsis>
-
                     <para>An alias for toStringEC14N().</para>
                 </listitem>
             </varlistentry>
 
                 <listitem>
                     <funcsynopsis>
-                        <funcsynopsisinfo>$c14nstring = $node-&gt;toStringC14N($with_comments, $xpath_expression);</funcsynopsisinfo>
-                    </funcsynopsis>
-
-                    <para>The function is similar to toString(). Instead of simply serializing the document tree, it transforms it as it is specified in the
-                    XML-C14N Specification (see <ulink url="http://www.w3.org/TR/xml-c14n">http://www.w3.org/TR/xml-c14n</ulink>). 
-                    Such transformation is known as canonization.</para>
-
-                    <para>If $with_comments is 0 or not defined, the result-document will not contain any comments that exist in the original document. To
-                    include comments into the canonized document, $with_comments has to be set to 1.</para>
-
-                    <para>The parameter $xpath_expression defines the nodeset of nodes that should be visible in the resulting document. This can be used to
-                    filter out some nodes. One has to note, that only the nodes that are part of the nodeset, will be included into the result-document. Their
-                    child-nodes will not exist in the resulting document, unless they are part of the nodeset defined by the xpath expression.</para>
-
-                    <para>If $xpath_expression is omitted or empty, toStringC14N() will include all nodes in the given sub-tree.</para>
+                        <funcsynopsisinfo>$c14nstring = $node-&gt;toStringC14N();
+$c14nstring = $node-&gt;toStringC14N($with_comments, $xpath_expression , $xpath_context);</funcsynopsisinfo>
+                    </funcsynopsis>
+
+                    <para>The function is similar to
+                    toString(). Instead of simply serializing the
+                    document tree, it transforms it as it is specified
+                    in the XML-C14N Specification
+                    (see <ulink url="http://www.w3.org/TR/xml-c14n">http://www.w3.org/TR/xml-c14n</ulink>).
+                    Such transformation is known as
+                    canonization.</para>
+
+                    <para>If $with_comments is 0 or not defined, the
+                    result-document will not contain any comments that
+                    exist in the original document. To include
+                    comments into the canonized document,
+                    $with_comments has to be set to 1.</para>
+
+                    <para>The parameter $xpath_expression defines the
+                    nodeset of nodes that should be visible in the
+                    resulting document. This can be used to filter out
+                    some nodes. One has to note, that only the nodes
+                    that are part of the nodeset, will be included
+                    into the result-document. Their child-nodes will
+                    not exist in the resulting document, unless they
+                    are part of the nodeset defined by the xpath
+                    expression.
+		    </para>
+                    <para>If $xpath_expression is omitted or empty,
+                    toStringC14N() will include all nodes in the given
+                    sub-tree, using the following XPath expressions:
+		    with comments
+		    <programlisting>(. | .//node() | .//@* | .//namespace::*)</programlisting>
+		    and without comments
+		    <programlisting>(. | .//node() | .//@* | .//namespace::*)[not(self::comment())]</programlisting>
+		    </para>
+		    <para>
+		      An optional parameter $xpath_context can be used
+		      to pass an <xref linkend="XML-LibXML-XPathContext"/> object defining
+		      the context for evaluation of $xpath_expression. 
+		      This is useful for mapping namespace prefixes used in the XPath expression 
+		      to namespace URIs.
+		      Note, however, that
+		      $node will be used as the context node for the evaluation, not
+		      the context node of $xpath_context!
+		    </para>
                 </listitem>
             </varlistentry>
             <varlistentry>
 
                 <listitem>
                     <funcsynopsis>
-                        <funcsynopsisinfo>$ec14nstring = $node-&gt;toStringEC14N($with_comments, $xpath_expression, $inclusive_prefix_list);</funcsynopsisinfo>
+                        <funcsynopsisinfo>$ec14nstring = $node-&gt;toStringEC14N();
+$ec14nstring = $node-&gt;toStringEC14N($with_comments, $xpath_expression, $inclusive_prefix_list);
+$ec14nstring = $node-&gt;toStringEC14N($with_comments, $xpath_expression, $xpath_context, $inclusive_prefix_list);</funcsynopsisinfo>
                     </funcsynopsis>
 
                     <para>The function is similar to toStringC14N() but follows
                     the XML-EXC-C14N Specification (see <ulink url="http://www.w3.org/TR/xml-exc-c14n">http://www.w3.org/TR/xml-exc-c14n</ulink>)
 	            for exclusive canonization of XML.</para>
 
-                    <para>The first two arguments are as above. If $inclusive_prefix_list is
-	              used, it should be an ARRAY reference listing 
-                      namespace prefixes that are to be handled in the manner described by the Canonical XML Recommendation (i.e. preserved in the output even if the namespace is not used). C.f. the spec for details.
+                    <para>The arguments $with_comments, $xpath_expression, $xpath_context are as in toStringC14N(). 
+		    An ARRAY reference can be passed as the last argument $inclusive_prefix_list, 
+		    listing namespace prefixes that are to be handled in the manner described by the Canonical XML Recommendation (i.e. preserved in the output even if the namespace is not used). C.f. the spec for details.
 	            </para>
                 </listitem>
             </varlistentry>
                 <term>serialize_c14n</term>
 
                 <listitem>
-                    <funcsynopsis>
-                        <funcsynopsisinfo>$c14nstr = $doc-&gt;serialize_c14n($comment_flag,$xpath); </funcsynopsisinfo>
-                    </funcsynopsis>
-
                     <para>An alias for toStringC14N().</para>
                 </listitem>
             </varlistentry>
                 <term>serialize_exc_c14n</term>
 
                 <listitem>
-                    <funcsynopsis>
-                        <funcsynopsisinfo>$ec14nstr = $doc-&gt;serialize_ec14n($comment_flag,$xpath,$inclusive_prefix_list); </funcsynopsisinfo>
-                    </funcsynopsis>
-
                     <para>An alias for toStringEC14N().</para>
                 </listitem>
             </varlistentry>
 use Test;
 use strict;
 
-BEGIN { plan tests => 20 };
+BEGIN { plan tests => 23 };
 use XML::LibXML;
 use XML::LibXML::Common qw(:libxml);
 
   }
 
 }
+
+{
+
+my $xml = <<'EOF';
+<?xml version="1.0" encoding="utf-8"?><soapenv:Envelope xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" xmlns:wsrl="http://docs.oasis-open.org/wsrf/rl-2" xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:Profile="urn:ehealth:profiles:timestamping:1.0" xmlns:tsa="http://www.behealth.be/webservices/tsa" xmlns:urn="urn:oasis:names:tc:dss:1.0:core:schema" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsrp="http://docs.oasis-open.org/wsrf/rp-2" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soapenv:Header><wsa:Action wsu:Id="Action">http://www.behealth.be/webservices/tsa/TSConsultTSBagRequest</wsa:Action><wsa:To wsu:Id="To">https://www.ehealth.fgov.be/timestampauthority_1_5/timestampauthority</wsa:To><wsa:MessageID wsu:Id="MessageID">urn:www.sve.man.ac.uk-54690551758351720271010843310</wsa:MessageID><wsa:ReplyTo wsu:Id="ReplyTo"><wsa:Address>http://www.w3.org/2005/08/addressing/anonymous</wsa:Address></wsa:ReplyTo></soapenv:Header><soapenv:Body wsu:Id="myBody"><TSConsultTSBagRequest xmlns="http://www.behealth.be/webservices/tsa"><tsa:IDHospital>tsa_0406798006_01</tsa:IDHospital><tsa:TSList><tsa:sequenceNumber>80300231753732</tsa:sequenceNumber><tsa:dateTime>1226995312781</tsa:dateTime></tsa:TSList></TSConsultTSBagRequest></soapenv:Body></soapenv:Envelope>
+EOF
+
+my $xpath = q{(//. | //@* | //namespace::*)[ancestor-or-self::x:MessageID]};
+my $xpath2 = q{(//. | //@* | //namespace::*)[ancestor-or-self::*[local-name()='MessageID' and namespace-uri()='http://www.w3.org/2005/08/addressing']]};
+
+my $doc = XML::LibXML->load_xml(string=>$xml);
+my $xpc = XML::LibXML::XPathContext->new($doc);
+$xpc->registerNs(x => "http://www.w3.org/2005/08/addressing");
+my $expect = '<wsa:MessageID xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:wsa="http://www.w3.org/2005/08/addressing" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="MessageID">urn:www.sve.man.ac.uk-54690551758351720271010843310</wsa:MessageID>';
+ok( $doc->toStringEC14N( 0, $xpath2, [qw(soap)] ), $expect );
+ok( $doc->toStringEC14N( 0, $xpath, $xpc, [qw(soap)] ), $expect );
+ok( $doc->toStringEC14N( 0, $xpath2, $xpc, [qw(soap)] ), $expect );
+
+}