Project

Profile

Help

How to connect?
Download (21.9 KB) Statistics
| Branch: | Tag: | Revision:

he / tags / 9.6.0.7 / hen / csource / api / Saxon.Api / Extensibility.cs @ aa733b18

1
using System;
2
using System.Collections.Generic;
3
using System.Text;
4

    
5
using JConfiguration = net.sf.saxon.Configuration;
6
using JStaticContext = net.sf.saxon.expr.StaticContext;
7
using JXPathException = net.sf.saxon.trans.XPathException;
8
using JXPathContext = net.sf.saxon.expr.XPathContext;
9
using JExtensionFunctionDefinition = net.sf.saxon.lib.ExtensionFunctionDefinition;
10
using JExtensionFunctionCall = net.sf.saxon.lib.ExtensionFunctionCall;
11
using JStructuredQName = net.sf.saxon.om.StructuredQName;
12
using JSequenceIterator = net.sf.saxon.om.SequenceIterator;
13
using JSequenceType = net.sf.saxon.value.SequenceType;
14
using JSequence = net.sf.saxon.om.Sequence;
15
using JExpression = net.sf.saxon.expr.Expression;
16

    
17
namespace Saxon.Api
18
{
19

    
20
    /// <summary>
21
    /// The class <c>StaticContext</c> provides information about the static context of an expression
22
    /// </summary>
23

    
24
    public class StaticContext {
25

    
26
        private JStaticContext env;
27

    
28
        internal StaticContext(JStaticContext jsc) {
29
            env = jsc;
30
        }
31

    
32

    
33
        /// <summary>
34
        /// The URI of the module where an expression appears, suitable for use in diagnostics
35
        /// </summary>
36
        /// 
37
        public Uri ModuleUri {
38
            get {
39
                return new Uri(env.getSystemId());
40
            }
41
        }
42

    
43
        /// <summary>
44
        /// The line number within a module where an expression appears, suitable for use in diagnostics
45
        /// </summary>
46
        /// 
47
        public int LineNumber {
48
            get {
49
                return env.getLineNumber();
50
            }
51
        }
52

    
53

    
54
        /// <summary>
55
        /// The static base URI of the expression. Often the same as the URI of the containing module,
56
        /// but not necessarily so, for example in a stylesheet that uses external XML entities or the
57
        /// xml:base attribute
58
        /// </summary>
59
        /// 
60
        public Uri BaseUri {
61
            get {
62
                return new Uri(env.getBaseURI());
63
            }
64
        }
65

    
66
        /// <summary>
67
        /// Resolve an in-scope namespace prefix to obtain the corresponding namespace URI. If the prefix
68
        /// is a zero-length string, the default namespace for elements and types is returned.
69
        /// </summary>
70
        /// <param name="Prefix">The namespace prefix</param>
71
        /// <returns>The corresponding namespace URI if there is one, or null otherwise</returns>
72
        /// 
73
        public String GetNamespaceForPrefix(string Prefix) {
74
            if (Prefix == "") {
75
                return env.getDefaultElementNamespace();
76
            }
77
            try {
78
                return env.getURIForPrefix(Prefix);
79
            } catch (JXPathException) {
80
                return null;
81
            }
82
        }
83

    
84
        /// <summary>
85
        /// The <c>Processor</c> that was used to create the query or stylesheet from which this extension
86
        /// function was invoked.
87
        /// </summary>
88
        /// <remarks>
89
        /// <para>This property is useful if the extension function wishes to create new nodes (the <code>Processor</code>
90
        /// can be used to obtain a <code>DocumentBuilder</code>), or to execute XPath expressions or queries.</para>
91
        /// <para>There may be circumstances in which the <c>Processor</c> is not available, in which case this method
92
        /// may return null, or may return a different <c>Processor</c>. This will happen only if low-level interfaces
93
        /// have been used to cause a <c>Configuration</c> to be shared between several <c>Processor</c> instances,
94
        /// or between a <c>Processor</c> and other applications.</para>
95
        /// </remarks>
96

    
97
        public Processor Processor
98
        {
99
            get
100
            {
101
                JConfiguration config = env.getConfiguration();
102
                Object p = config.getProcessor();
103
                if (p is Processor)
104
                {
105
                    return (Processor)p;
106
                }
107
                else
108
                {
109
                    return null;
110
                }
111

    
112
            }
113
        }
114

    
115
        /// <summary>
116
        /// The underlying object in the Saxon implementation, an instance of class
117
        /// <code>net.sf.saxon.expr.StaticContext</code>
118
        /// </summary>
119
        /// <remarks>
120
        /// <para>This property provides access to internal methods in the Saxon engine that are
121
        /// not specifically exposed in the .NET API. In general these methods should be
122
        /// considered to be less stable than the classes in the Saxon.Api namespace.</para> 
123
        /// <para>The internal methods follow
124
        /// Java naming conventions rather than .NET conventions.</para>
125
        /// <para>Information about the returned object (and the objects it provides access to)
126
        /// is included in the Saxon JavaDoc docmentation, available 
127
        /// <link href="http://www.saxonica.com/documentation/javadoc/index.html">online</link>.
128
        /// </para>
129
        /// </remarks>
130

    
131
        public JStaticContext Implementation
132
        {
133
            get { return env; }
134
        }
135
    }
136

    
137
    /// <summary>
138
    /// The class <c>DynamicContext</c> provides information about the dynamic context of an expression
139
    /// </summary>
140
    /// 
141
    public class DynamicContext {
142

    
143
        internal JXPathContext context;
144

    
145
        internal DynamicContext(JXPathContext context) {
146
            this.context = context;
147
        }
148

    
149
        /// <summary>
150
        /// The context item. May be null if no context item is defined
151
        /// </summary>
152
        /// 
153
        public XdmItem ContextItem {
154
            get {
155
                return (XdmItem)XdmItem.Wrap(context.getContextItem());
156
            }
157
        }
158

    
159
        /// <summary>
160
        /// The context position (equivalent to the XPath position() function).
161
        /// </summary>
162
        /// <remarks>Calling this method throws an exception if the context item is undefined.</remarks>
163
        /// 
164
        public int ContextPosition {
165
            get {
166
                return context.getCurrentIterator().position();
167
            }
168
        }
169

    
170
        /// <summary>
171
        /// The context size (equivalent to the XPath last() function).
172
        /// </summary>
173
        /// <remarks>Calling this method throws an exception if the context item is undefined.</remarks>
174
        /// 
175
        public int ContextSize {
176
            get {
177
                return context.getLast();
178
            }
179
        }
180

    
181
        /// <summary>
182
        /// The underlying object in the Saxon implementation, an instance of class
183
        /// <code>net.sf.saxon.expr.XPathContext</code>
184
        /// </summary>
185
        /// <remarks>
186
        /// <para>This property provides access to internal methods in the Saxon engine that are
187
        /// not specifically exposed in the .NET API. In general these methods should be
188
        /// considered to be less stable than the classes in the Saxon.Api namespace.</para> 
189
        /// <para>The internal methods follow
190
        /// Java naming conventions rather than .NET conventions.</para>
191
        /// <para>Information about the returned object (and the objects it provides access to)
192
        /// is included in the Saxon JavaDoc docmentation, available 
193
        /// <link href="http://www.saxonica.com/documentation/javadoc/index.html">online</link>.
194
        /// </para>
195
        /// </remarks>
196

    
197
        public JXPathContext Implementation
198
        {
199
            get { return context; }
200
        }        
201

    
202
    }
203

    
204
    /// <summary>
205
    /// <para>Abstract superclass for user-written extension functions. An extension function may be implemented as a subclass
206
    /// of this class, with appropriate implementations of the defined methods.</para>
207
    /// <para>More precisely, a subclass of <c>ExtensionFunctionDefinition</c> identifies a family of extension functions
208
    /// with the same (namespace-qualified) name but potentially having different arity (number of arguments).</para>
209
    /// </summary>
210
    /// <remarks>
211
    /// <para>A user-defined extension function is typically implemented using a pair of classes: a class that extends 
212
    /// <code>ExtensionFunctionDefinition</code>, whose purpose is to define the properties of the extension function
213
    /// (in particular, its signature -- the types of its arguments and result); and a class that extends
214
    /// <code>ExtensionFunctionCall</code>, whose purpose is to perform the actual evaluation.</para> 
215
    /// <para>The <code>ExtensionFunctionDefinition</code> is immutable and will normally have a singleton instance
216
    /// for each subclass; this singleton instance is registered with the <code>Processor</code> to associate the
217
    /// name of the extension function with its definition.</para>
218
    /// <para>The <code>ExtensionFunctionCall</code> has one instance for each call on the extension function appearing
219
    /// in the source code of a stylesheet or query; this instance is created when Saxon calls the method <code>MakeFunctionCall</code>
220
    /// provided by the <code>ExtensionFunctionDefinition</code> object. The instance of <code>ExtensionFunctionCall</code>
221
    /// holds information about the static context of the function call, and its <code>Call</code> method is called
222
    /// (by Saxon) to evaluate the extension function at run-time.</para>
223
    /// </remarks>
224

    
225
    public abstract class ExtensionFunctionDefinition
226
    {
227
        /// <summary>
228
        /// Read-only property returning the name of the extension function, as a QName.
229
        /// </summary>
230
        /// <remarks>
231
        /// A getter for this property must be implemented in every subclass.
232
        /// </remarks>
233

    
234
        public abstract QName FunctionName {get;}
235

    
236
        /// <summary>
237
        /// Read-only property giving the minimum number of arguments in a call to this extension function.
238
        /// </summary>
239
        /// <remarks>
240
        /// A getter for this property must be implemented in every subclass.
241
        /// </remarks>
242

    
243
        public abstract int MinimumNumberOfArguments {get;}
244

    
245
        /// <summary>
246
        /// Read-only property giving the maximum number of arguments in a call to this extension function.
247
        /// </summary>
248
        /// <remarks>
249
        /// A getter for this property must be implemented in every subclass.
250
        /// </remarks>
251
        
252
        public abstract int MaximumNumberOfArguments {get;}
253

    
254
        /// <summary>
255
        /// Read-only property giving the required types of the arguments to this extension function. 
256
        /// If the number of items in the array is less than the maximum number of arguments, 
257
        /// then the last entry in the returned ArgumentTypes is assumed to apply to all the rest; 
258
        /// if the returned array is empty, then all arguments are assumed to be of type <c>item()*</c>
259
        /// </summary>
260
        /// <remarks>
261
        /// A getter for this property must be implemented in every subclass.
262
        /// </remarks>
263

    
264
        public abstract XdmSequenceType[] ArgumentTypes {get;}
265

    
266
        /// <summary>
267
        /// Method returning the declared type of the return value from the function. The type of the return
268
        /// value may be known more precisely if the types of the arguments are known (for example, some functions
269
        /// return a value that is the same type as the first argument. The method is therefore called supplying the
270
        /// static types of the actual arguments present in the call.
271
        /// </summary>
272
        /// <remarks>
273
        /// This method must be implemented in every subclass.
274
        /// </remarks>
275
        /// <param name="ArgumentTypes">
276
        /// The static types of the arguments present in the function call
277
        /// </param>
278
        /// <returns>
279
        /// An <c>XdmSequenceType</c> representing the declared return type of the extension function
280
        /// </returns>
281

    
282
        public abstract XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes);
283

    
284
        /// <summary>
285
        /// This property may return true for a subclass if it guarantees that the returned result of the function
286
        /// will always be of the declared return type: setting this to true by-passes the run-time checking of the type
287
        /// of the value, together with code that would otherwise perform atomization, numeric type promotion, and similar
288
        /// conversions. If the value is set to true and the value is not of the correct type, the effect is unpredictable
289
        /// and probably disastrous.
290
        /// </summary>
291
        /// <remarks>
292
        /// The default value of this property is <c>false</c>. A getter for this property may be implemented in a subclass
293
        /// to return a different value.
294
        /// </remarks>
295

    
296
        public virtual Boolean TrustResultType {
297
            get{return false;}
298
        }
299

    
300
        /// <summary>
301
        /// This property must return true for a subclass if the evaluation of the function makes use of the context
302
        /// item, position, or size from the dynamic context. It should also return true (despite the property name)
303
        /// if the function makes use of parts of the static context that vary from one part of the query or stylesheet
304
        /// to another. Setting the property to true inhibits certain Saxon optimizations, such as extracting the call
305
        /// from a loop, or moving it into a global variable.
306
        /// </summary>
307
        /// <remarks>
308
        /// The default value of this property is <c>false</c>. A getter for this property may be implemented in a subclass
309
        /// to return a different value.
310
        /// </remarks>
311

    
312
        public virtual Boolean DependsOnFocus {
313
            get{return false;}
314
        }
315

    
316
        /// <summary>
317
        /// This property should return true for a subclass if the evaluation of the function has side-effects.
318
        /// Saxon never guarantees the result of calling functions with side-effects, but if this property is set,
319
        /// then certain aggressive optimizations will be avoided, making it more likely that the function behaves
320
        /// as expected.
321
        /// </summary>
322
        /// <remarks>
323
        /// The default value of this property is <c>false</c>. A getter for this property may be implemented in a subclass
324
        /// to return a different value.
325
        /// </remarks>
326

    
327
        public virtual Boolean HasSideEffects {
328
            get{return false;}
329
        }
330

    
331
        /// <summary>
332
        /// Factory method to create an <c>ExtensionFunctionCall</c> object, representing a specific function call in the XSLT or XQuery
333
        /// source code. Saxon will call this method once it has identified that a specific call relates to this extension
334
        /// function.
335
        /// </summary>
336
        /// <remarks>
337
        /// This method must be implemented in every subclass. The implementation should normally instantiate the relevant subclass
338
        /// of <code>ExtensionFunctionCall</code>, and return the new instance.
339
        /// </remarks>
340
        /// <returns>
341
        /// An instance of the appropriate implementation of <code>ExtensionFunctionCall</code>
342
        /// </returns>
343

    
344
        public abstract ExtensionFunctionCall MakeFunctionCall();
345
    }
346

    
347
    /// <summary>
348
    /// <para>An instance of this class will be created by the compiler for each function call to this extension function
349
    /// that is found in the source code. The class is always instantiated by calling the method <c>MakeFunctionCall()</c>
350
    /// of the corresponding <c>ExtensionFunctionDefinition</c>. 
351
    /// The implementation may therefore retain information about the static context of the
352
    /// call. Once compiled, however, the instance object must be immutable.</para>
353
    /// </summary>
354

    
355
    public abstract class ExtensionFunctionCall {
356

    
357
        /// <summary>
358
        /// Method called by the compiler (at compile time) to provide information about the static context of the
359
        /// function call. The implementation may retain this information for use at run-time, if the result of the
360
        /// function depends on information in the static context.
361
        /// </summary>
362
        /// <remarks>
363
        /// For efficiency, the implementation should only retain copies of the information that it actually needs. It
364
        /// is not a good idea to hold a reference to the static context itself, since that can result in a great deal of
365
        /// compile-time information being locked into memory during run-time execution.
366
        /// </remarks>
367
        /// <param name="context">Information about the static context in which the function is called</param>
368

    
369
        public virtual void SupplyStaticContext(StaticContext context)
370
        {
371
            // default: no action
372
        }
373

    
374
        /// <summary>
375
        /// A subclass must implement this method if it retains any local data at the instance level. On some occasions
376
        /// (for example, when XSLT or XQuery code is inlined), Saxon will make a copy of an <c>ExtensionFunction</c> object.
377
        /// It will then call this method on the old object, supplying the new object as the value of the argument, and the
378
        /// method must copy all local data items from the old object to the new.
379
        /// </summary>
380
        /// <param name="destination">The new extension function object. This will always be an instance of the same
381
        /// class as the existing object.</param>
382

    
383
        public virtual void CopyLocalData(ExtensionFunctionCall destination) { }
384

    
385
        /// <summary>
386
        /// Method called at run time to evaluate the function.
387
        /// </summary>
388
        /// <param name="arguments">The values of the arguments to the function, supplied as iterators over XPath
389
        /// sequence values.</param>
390
        /// <param name="context">The dynamic context for evaluation of the function. This provides access
391
        /// to the context item, position, and size, and if required to internal data maintained by the Saxon
392
        /// engine.</param>
393
        /// <returns>An iterator over a sequence, representing the result of the extension function.
394
        /// Note that Saxon does not guarantee to read this sequence to completion, so calls on the iterator
395
        /// must have no side-effects. In rare circumstances (for example, when <code>last()</code> is
396
        /// used) Saxon may clone the returned iterator by calling its <c>GetAnother()</c> method, 
397
        /// allowing the function results to be read more than once.</returns>
398

    
399
        public abstract IXdmEnumerator Call(IXdmEnumerator[] arguments, DynamicContext context);
400
    }
401

    
402
    internal class WrappedExtensionFunctionDefinition : JExtensionFunctionDefinition
403
    {
404
        ExtensionFunctionDefinition definition;
405

    
406
        public WrappedExtensionFunctionDefinition(ExtensionFunctionDefinition definition)
407
        {
408
            this.definition = definition;
409
        }
410

    
411
        public override JStructuredQName getFunctionQName()
412
        {
413
            return definition.FunctionName.ToStructuredQName();
414
        }
415

    
416
        public override int getMinimumNumberOfArguments()
417
        {
418
            return definition.MinimumNumberOfArguments;
419
        }
420

    
421
        public override int getMaximumNumberOfArguments()
422
        {
423
            return definition.MaximumNumberOfArguments;
424
        }
425

    
426
        public override JSequenceType[] getArgumentTypes()
427
        {
428
            XdmSequenceType[] dt = definition.ArgumentTypes;
429
            JSequenceType[] jt = new JSequenceType[dt.Length];
430
            for (int i = 0; i < dt.Length; i++)
431
            {
432
                jt[i] = dt[i].ToSequenceType();
433
            }
434
            return jt;
435
        }
436

    
437
        public override JSequenceType getResultType(JSequenceType[] argumentTypes)
438
        {
439
            XdmSequenceType[] dt = new XdmSequenceType[argumentTypes.Length];
440
            for (int i = 0; i < dt.Length; i++)
441
            {
442
                dt[i] = XdmSequenceType.FromSequenceType(argumentTypes[i]);
443
            }
444

    
445
            XdmSequenceType rt = definition.ResultType(dt);
446
            return rt.ToSequenceType();
447
        }
448

    
449
        public override Boolean trustResultType()
450
        {
451
            return definition.TrustResultType;
452
        }
453

    
454
        public override Boolean dependsOnFocus()
455
        {
456
            return definition.DependsOnFocus;
457
        }
458

    
459
        public override Boolean hasSideEffects()
460
        {
461
            return definition.HasSideEffects;
462
        }
463

    
464
        public override JExtensionFunctionCall makeCallExpression()
465
        {
466
            return new WrappedExtensionFunctionCall(definition.MakeFunctionCall());
467
        }
468

    
469
    }
470

    
471
    internal class WrappedExtensionFunctionCall : JExtensionFunctionCall {
472

    
473
        ExtensionFunctionCall functionCall;
474

    
475
        public WrappedExtensionFunctionCall(ExtensionFunctionCall call)
476
        {
477
            this.functionCall = call;
478
        }
479
        
480
        public override void supplyStaticContext(JStaticContext context, int locationId, JExpression[] arguments)
481
        {
482
            StaticContext sc = new StaticContext(context);
483
            functionCall.SupplyStaticContext(sc);
484
        }
485

    
486
        public override void copyLocalData(JExtensionFunctionCall destination)
487
        {
488
            functionCall.CopyLocalData(((WrappedExtensionFunctionCall)destination).functionCall);
489
        }
490

    
491
        public override JSequence call(JXPathContext context, JSequence [] argument)
492
        {
493
            SequenceEnumerator[] na = new SequenceEnumerator[argument.Length];
494
            for (int i = 0; i < na.Length; i++)
495
            {
496
                na[i] = new SequenceEnumerator(argument[i].iterate());
497
            }
498
            DynamicContext dc = new DynamicContext(context);
499
            IXdmEnumerator result = functionCall.Call(na, dc);
500
            return new net.sf.saxon.om.LazySequence(new DotNetSequenceIterator(result));
501
        }
502
    }
503
}
504

    
505
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
506
// Copyright (c) 2013 Saxonica Limited.
507
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
508
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
509
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
510
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
(4-4/13)