Project

Profile

Help

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

he / latest9.4 / hen / csource / api / Saxon.Api / Extensibility.cs @ c3c84ba2

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 JExpression = net.sf.saxon.expr.Expression;
15

    
16
namespace Saxon.Api
17
{
18

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

    
23
    public class StaticContext {
24

    
25
        private JStaticContext env;
26

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

    
31

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

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

    
52

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

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

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

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

    
111
            }
112
        }
113

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

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

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

    
142
        internal JXPathContext context;
143

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

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

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

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

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

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

    
201
    }
202

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

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

    
233
        public abstract QName FunctionName {get;}
234

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

    
242
        public abstract int MinimumNumberOfArguments {get;}
243

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

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

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

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

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

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

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

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

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

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

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

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

    
343
        public abstract ExtensionFunctionCall MakeFunctionCall();
344
    }
345

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

    
354
    public abstract class ExtensionFunctionCall {
355

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
468
    }
469

    
470
    internal class WrappedExtensionFunctionCall : JExtensionFunctionCall {
471

    
472
        ExtensionFunctionCall functionCall;
473

    
474
        public WrappedExtensionFunctionCall(ExtensionFunctionCall call)
475
        {
476
            this.functionCall = call;
477
        }
478

    
479
        public override void supplyStaticContext(JStaticContext context, int locationId, JExpression[] arguments)
480
        {
481
            StaticContext sc = new StaticContext(context);
482
            functionCall.SupplyStaticContext(sc);
483
        }
484

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

    
490
        public override JSequenceIterator call(JSequenceIterator[] arguments, JXPathContext context)
491
        {
492
            SequenceEnumerator[] na = new SequenceEnumerator[arguments.Length];
493
            for (int i = 0; i < na.Length; i++)
494
            {
495
                na[i] = new SequenceEnumerator(arguments[i]);
496
            }
497
            DynamicContext dc = new DynamicContext(context);
498
            IXdmEnumerator result = functionCall.Call(na, dc);
499
            return new DotNetSequenceIterator(result);
500
        }
501
    }
502
}
(4-4/12)