Sophie

Sophie

distrib > Mageia > 7 > armv7hl > by-pkgid > b3bdfe6d859a3d6920ff2c44b38e9a6f > files > 260

saxon-manual-9.4.0.9-2.mga7.noarch.rpm

<?xml version="1.0" encoding="iso-8859-1"?>
<?xml-stylesheet href="../make-menu.xsl" type="text/xsl"?><html>
   <head>
      <this-is section="extensibility" page="dotnetextensions" subpage=""/>
      <!--
           Generated at 2011-12-09T20:47:22.916Z--><title>Saxonica: XSLT and XQuery Processing: Writing reflexive extension functions for .NET</title>
      <meta name="coverage" content="Worldwide"/>
      <meta name="copyright" content="Copyright Saxonica Ltd"/>
      <meta name="title"
            content="Saxonica: XSLT and XQuery Processing: Writing reflexive extension functions for .NET"/>
      <meta name="robots" content="noindex,nofollow"/>
      <link rel="stylesheet" href="../saxondocs.css" type="text/css"/>
   </head>
   <body class="main">
      <h1>Writing reflexive extension functions for .NET</h1>
      <div class="boxed"
           style="border: solid thin; background-color: #B1CCC7; padding: 2px">Reflexive extension functions involve dynamic loading of assemblies, which
    can be tricky to get working. Also, they aren't supported under Saxon-HE.
    Consider using <a class="bodylink" href="../extensibility/integratedfunctions.xml">integrated extension functions</a> instead.</div>
      <p>On the .NET platform extension functions may be implemented in any
.NET language (the examples here assume C#).</p>
      <div class="boxed"
           style="border: solid thin; background-color: #B1CCC7; padding: 2px">Queries and stylesheets running on the .NET platform may also call
Java extension functions, provided the Java class is part of the standard library
implemented in the OpenJDK DLL, or in Saxon itself. For calling conventions,
see <a class="bodylink" href="../extensibility/functions.xml">Writing extension functions in Java</a>. If
you want to write your own extensions in Java, you will need to compile them
to .NET assemblies using IKVMC.</div>
      <p>An extension function is invoked using a name such as <code>prefix:localname()</code>.
The prefix must be the prefix associated with a namespace declaration that is in scope. 
The namespace URI is used to identify a .NET class, and the local name is used to identify
a method, property, or constructor within the class.</p>
      <p><b>The command line option -TJ is useful for debugging the loading of .NET
extensions. It gives detailed information about the methods that are examined for
a possible match.</b></p>
      <p>The basic form of the namespace URI is
 "clitype:" followed by the fully-qualified type name
 (for example <code>xmlns:env="clitype:System.Environment"</code>). This form
 works for system classes and classes in a loaded assembly. If an assembly needs
 to be loaded, extra information can be given in the form of URI query parameters. For example
 <code>xmlns:env="clitype:Acme.Payroll.Employee?asm=payroll;version=4.12.0.0"</code>.</p>
      <p>The parameters that are recognized are:</p>
      <table>
         <tr>
            <td content="para">
               <p>Keyword</p>
            </td>
            <td content="para">
               <p>Value</p>
            </td>
         </tr>
         <tr>
            <td content="para">
               <p>asm</p>
            </td>
            <td content="para">
               <p>The simple name of the assembly</p>
            </td>
         </tr>
         <tr>
            <td content="para">
               <p>ver</p>
            </td>
            <td content="para">
               <p>The version number, up to four integers separated by periods</p>
            </td>
         </tr>
         <tr>
            <td content="para">
               <p>loc</p>
            </td>
            <td content="para">
               <p>The culture (locale), for example "en-US"</p>
            </td>
         </tr>
         <tr>
            <td content="para">
               <p>sn</p>
            </td>
            <td content="para">
               <p>The public key token of the assembly's strong name, as 16 hex digits</p>
            </td>
         </tr>
         <tr>
            <td content="para">
               <p>from</p>
            </td>
            <td content="para">
               <p>The location of the assembly, as a URI</p>
            </td>
         </tr>
         <tr>
            <td content="para">
               <p>partialname</p>
            </td>
            <td content="para">
               <p>The partial name of the assembly (as supplied to 
<code>Assembly.LoadWithPartialName()</code>).</p>
            </td>
         </tr>
      </table>
      <p>If the <code>from</code> keyword is present, the other parameters are ignored. The value of
<code>from</code> must be the URI of the DLL to be loaded: if it is relative, it is relative to the base URI of the expression
containing the call to the extension function (regardless of where the namespace is actually declared).</p>
      <p>If the <code>partialName</code> keyword is present, the assembly is loaded (if possible) using
<code>Assembly.LoadWithPartialName()</code> and the other parameters are ignored.</p>
      <p>If the assembly is a library DLL in the global assembly cache, use the <code>gacutil /l</code> command
to list the assemblies present in the GAC, and to extract the required version, culture, and strong name attributes.
For example, suppose you want to call a static method <code>disappear()</code> in class <code>Conjurer</code> in 
namespace <code>Magic.Circle</code>, and this class is contained in an assembly <code>Magic</code> 
listed as:</p>
      <p><code>Magic, Version=7.2.2200.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a4b, Custom=null</code></p>
      <p>Then the URI you would use to identify this class is
<code>clitype:Magic.Circle.Conjurer?asm=Magic;ver=7.2.2200.0;sn=b03f5f7f11d50a4b</code>, and an actual call
of the function might take the form:</p>
      <div class="codeblock"
           style="border: solid thin; background-color: #B1CCC7; padding: 2px">
         <pre>
            <code>
&lt;xsl:value-of select="m:disappear()"
     xmlns:m="clitype:Magic.Circle.Conjurer?asm=Magic;ver=7.2.2200.0;sn=b03f5f7f11d50a4b"/&gt; 
</code>
         </pre>
      </div>
      <p class="subhead">Tips for Dynamic Loading in .NET"</p>
      <p>Here are some hints and tips that might help you to get dynamic loading working under .NET.</p>
      <p><b>The command line option -TJ is useful for debugging the loading of .NET
extensions. It gives detailed information about the methods that are examined for
a possible match. The equivalent in the API is to set the Processor property 
<code>"http://saxon.sf.net/feature/trace-external-functions"</code></b>.</p>
      <p>First decide whether you want to load the assembly (DLL) containing the extension functions from local
filestore or from the Global Assembly Cache.</p>
      <p>If you want to load it from the GAC you must compile the assembly with a strong name, and deploy it to the GAC.
      For advice on doing this, see <a href="http://support.microsoft.com/kb/324168" class="bodylink">http://support.microsoft.com/kb/324168</a>.
      (In .NET framework 2.0 there was a handy Control Panel tool for this, but it is no longer available for security reasons.)</p>
      <p>For local loading, the following techniques work:</p>
      <ul>
         <li content="para">
            <p>If the query or transformation is controlled from a user-written application in C# or another .NET language,
include the extension function implementation in the same assembly as the controlling application, or in another
assembly which is statically referenced from the controlling application. In this case it is only necessary to name the
assembly, for example <code>&lt;e att="{my:ext()}" xmlns:my="clitype:Namespace.ClassName?asm=Samples"/&gt;</code>
         </p>
         </li>
         <li content="para">
            <p>Another approach is to copy the assembly into the same directory as the controlling application or, if using the
Saxon <code>Query</code> or <code>Transform</code> command from the command line, the directory containing the Saxon
<code>Query.exe</code> and <code>Transform.exe</code> executables. Again in this case it should simply be necessary
to give the assembly name as above.</p>
         </li>
         <li content="para">
            <p>As an alternative, an assembly held in local filestore can be loaded by reference to the file, for example
<code>xmlns:my="clitype:Namespace.ClassName?from=file:///c:/lib/Samples.dll"</code>. The URI can be given as an absolute URI,
or as a relative URI which is interpreted relative to the base URI of the expression containing the function call.</p>
         </li>
      </ul>
      <p>For production running it is probably more appropriate to place the assembly holding extension functions in the
global assembly cache. It can then generally be referenced in one of two ways:</p>
      <ul>
         <li content="para">
            <p>By partial name, for example <code>xmlns:my="clitype:Namespace.ClassName?partialname=Samples"</code>
         </p>
         </li>
         <li content="para">
            <p>By fully-qualified name, for example 
<code>xmlns:my="clitype:Namespace.ClassName?asm=Samples;ver=3.0.0.1;loc=neutral;sn=e1f2a3b4e1f2a3b4"</code>
         </p>
         </li>
      </ul>
      <p>The following example shows how to call system methods in the .NET framework:</p>
      <div class="codeblock"
           style="border: solid thin; background-color: #B1CCC7; padding: 2px">
         <pre>
            <code>&lt;out xmlns:Environment="clitype:System.Environment" 
     xmlns:OS="clitype:System.OperatingSystem"&gt;
    &lt;xsl:variable name="os" select="Environment:OSVersion()"/&gt;
    &lt;v platform="{OS:Platform($os)}" version="{OS:Version($os)}"/&gt;
&lt;/out&gt;
</code>
         </pre>
      </div>
      <p class="subhead">Identifying and Calling Specific Methods</p>
      <p>The rest of this section considers how a .NET method, property, or constructor is identified. This decision
(called binding) is always made at the time the XPath expression is compiled.</p>
      <p>There are three cases to consider: static methods, constructors, and instance-level methods. In
addition, a public property in a class is treated as if it were a zero-argument method, so static properties
can be accessed in the same way as static methods, and instance-level properties
in the same way as instance-level methods. (Note that the property name is used directly: it is not
prefixed by "get".)</p>
      <ul>
         <li>
            <p><a class="bodylink" href="dotnetextensions/staticmethods.net.xml">Calling Static Methods in a .NET Class</a></p>
         </li>
         <li>
            <p><a class="bodylink" href="dotnetextensions/constructors.net.xml">Calling .NET Constructors</a></p>
         </li>
         <li>
            <p><a class="bodylink" href="dotnetextensions/instance-methods.net.xml">Calling .NET Instance-Level Methods</a></p>
         </li>
      </ul>
      <table width="100%">
         <tr>
            <td>
               <p align="right"><a class="nav" href="dotnetextensions/staticmethods.net.xml">Next</a></p>
            </td>
         </tr>
      </table>
   </body>
</html>