Project

Profile

Help

Download (25.8 KB) Statistics
| Branch: | Tag: | Revision:

he / latest10 / hen / csource / api / Extensibility.cs @ aac4a1be

1 b64b1e89 O'Neil Delpratt
´╗┐using System;
2
3
using JConfiguration = net.sf.saxon.Configuration;
4
using JStaticContext = net.sf.saxon.expr.StaticContext;
5
using JXPathException = net.sf.saxon.trans.XPathException;
6
using JXPathContext = net.sf.saxon.expr.XPathContext;
7
using JExtensionFunctionDefinition = net.sf.saxon.lib.ExtensionFunctionDefinition;
8
using JExtensionFunction = net.sf.saxon.s9api.ExtensionFunction;
9
using JExtensionFunctionCall = net.sf.saxon.lib.ExtensionFunctionCall;
10
using JStructuredQName = net.sf.saxon.om.StructuredQName;
11
using JXdmSequenceIterator = net.sf.saxon.s9api.XdmSequenceIterator;
12
using JSequenceType = net.sf.saxon.value.SequenceType;
13
using JSequence = net.sf.saxon.om.Sequence;
14
using JExpression = net.sf.saxon.expr.Expression;
15
using JXdmSequenceType = net.sf.saxon.s9api.SequenceType;
16
using JItem = net.sf.saxon.om.Item;
17
using System.Collections.Generic;
18
19
namespace Saxon.Api
20
{
21
22
    /// <summary>
23
    /// The class <c>StaticContext</c> provides information about the static context of an expression
24
    /// </summary>
25
26
    public class StaticContext {
27
28
        private JStaticContext env;
29
30
        internal StaticContext(JStaticContext jsc) {
31
            env = jsc;
32
        }
33
34
35
        /// <summary>
36
        /// The URI of the module where an expression appears, suitable for use in diagnostics
37
        /// </summary>
38
        
39
		public Uri ModuleUri {
40
            get {
41
                return new Uri(env.getSystemId());
42
            }
43
        }
44
45
46
        /// <summary>
47
        /// The static base URI of the expression. Often the same as the URI of the containing module,
48
        /// but not necessarily so, for example in a stylesheet that uses external XML entities or the
49
		/// <c>xml:base</c> attribute
50
        /// </summary>
51
        
52
		public Uri BaseUri {
53
            get {
54
				return new Uri(env.getStaticBaseURI());
55
            }
56
        }
57
58
        /// <summary>
59
        /// Resolve an in-scope namespace prefix to obtain the corresponding namespace URI. If the prefix
60
        /// is a zero-length string, the default namespace for elements and types is returned.
61
        /// </summary>
62
        /// <param name="Prefix">The namespace prefix</param>
63
        /// <returns>The corresponding namespace URI if there is one, or null otherwise</returns>
64
        
65
		public String GetNamespaceForPrefix(string Prefix) {
66
            if (Prefix == "") {
67
                return env.getDefaultElementNamespace();
68
            }
69
            try {
70
				return env.getNamespaceResolver().getURIForPrefix(Prefix, false);
71
            } catch (JXPathException) {
72
                return null;
73
            }
74
        }
75
76
        /// <summary>
77
        /// The <c>Processor</c> that was used to create the query or stylesheet from which this extension
78
        /// function was invoked.
79
        /// </summary>
80
        /// <remarks>
81
        /// <para>This property is useful if the extension function wishes to create new nodes (the <code>Processor</code>
82
        /// can be used to obtain a <code>DocumentBuilder</code>), or to execute XPath expressions or queries.</para>
83
        /// <para>There may be circumstances in which the <c>Processor</c> is not available, in which case this method
84
        /// may return null, or may return a different <c>Processor</c>. This will happen only if low-level interfaces
85
        /// have been used to cause a <c>Configuration</c> to be shared between several <c>Processor</c> instances,
86
        /// or between a <c>Processor</c> and other applications.</para>
87
        /// </remarks>
88
89
        public Processor Processor
90
        {
91
            get
92
            {
93
                JConfiguration config = env.getConfiguration();
94
                Object p = config.getProcessor();
95
                if (p is Processor)
96
                {
97
                    return (Processor)p;
98
                }
99
                else
100
                {
101
                    return null;
102
                }
103
104
            }
105
        }
106
107
        /// <summary>
108
        /// The underlying object in the Saxon implementation, an instance of class
109
		/// <code>net.sf.saxon.expr.StaticContext</code>
110
        /// </summary>
111
        /// <remarks>
112
        /// <para>This property provides access to internal methods in the Saxon engine that are
113
        /// not specifically exposed in the .NET API. In general these methods should be
114
        /// considered to be less stable than the classes in the Saxon.Api namespace.</para> 
115
        /// <para>The internal methods follow
116
        /// Java naming conventions rather than .NET conventions.</para>
117
        /// <para>Information about the returned object (and the objects it provides access to)
118
		/// is included in the Saxon JavaDoc documentation, see <see cref="net.sf.saxon.expr.StaticContext"/>.
119
        /// </para>
120
        /// </remarks>
121
122
        public JStaticContext Implementation
123
        {
124
            get { return env; }
125
        }
126
    }
127
128
    /// <summary>
129
    /// The class <c>DynamicContext</c> provides information about the dynamic context of an expression
130
    /// </summary>
131
    
132
	public class DynamicContext {
133
134
        internal JXPathContext context;
135
136
        internal DynamicContext(JXPathContext context) {
137
            this.context = context;
138
        }
139
140
        /// <summary>
141
        /// The context item. May be null if no context item is defined
142
        /// </summary>
143
        
144
		public XdmItem ContextItem {
145
            get {
146
                return context.getContextItem()== null ? null : (XdmItem)XdmItem.Wrap(context.getContextItem());
147
            }
148
        }
149
150
        /// <summary>
151
		/// The context position (equivalent to the XPath <c>position()</c> function).
152
        /// </summary>
153
        /// <remarks>Calling this method throws an exception if the context item is undefined.</remarks>
154
        
155
		public int ContextPosition {
156
            get {
157
                return context.getCurrentIterator().position();
158
            }
159
        }
160
161
        /// <summary>
162
		/// The context size (equivalent to the XPath <c>last()</c> function).
163
        /// </summary>
164
        /// <remarks>Calling this method throws an exception if the context item is undefined.</remarks>
165
        
166
		public int ContextSize {
167
            get {
168
                return context.getLast();
169
            }
170
        }
171
172
        /// <summary>
173
        /// The underlying object in the Saxon implementation, an instance of class
174
		/// <code>net.sf.saxon.expr.XPathContext</code>
175
        /// </summary>
176
        /// <remarks>
177
        /// <para>This property provides access to internal methods in the Saxon engine that are
178
        /// not specifically exposed in the .NET API. In general these methods should be
179
        /// considered to be less stable than the classes in the Saxon.Api namespace.</para> 
180
        /// <para>The internal methods follow
181
        /// Java naming conventions rather than .NET conventions.</para>
182
        /// <para>Information about the returned object (and the objects it provides access to)
183
		/// is included in the Saxon JavaDoc documentation, see <see cref="net.sf.saxon.expr.XPathContext"/>
184
        /// </para>
185
        /// </remarks>
186
187
        public JXPathContext Implementation
188
        {
189
            get { return context; }
190
        }        
191
192
    }
193
194
    /// <summary>
195
    /// <para>Abstract superclass for user-written extension functions. An extension function may be implemented as a subclass
196
    /// of this class, with appropriate implementations of the defined methods.</para>
197
    /// <para>More precisely, a subclass of <c>ExtensionFunctionDefinition</c> identifies a family of extension functions
198
    /// with the same (namespace-qualified) name but potentially having different arity (number of arguments).</para>
199
    /// </summary>
200
    /// <remarks>
201
    /// <para>A user-defined extension function is typically implemented using a pair of classes: a class that extends 
202
    /// <code>ExtensionFunctionDefinition</code>, whose purpose is to define the properties of the extension function
203
    /// (in particular, its signature -- the types of its arguments and result); and a class that extends
204
    /// <code>ExtensionFunctionCall</code>, whose purpose is to perform the actual evaluation.</para> 
205
    /// <para>The <code>ExtensionFunctionDefinition</code> is immutable and will normally have a singleton instance
206
    /// for each subclass; this singleton instance is registered with the <code>Processor</code> to associate the
207
    /// name of the extension function with its definition.</para>
208
    /// <para>The <code>ExtensionFunctionCall</code> has one instance for each call on the extension function appearing
209
    /// in the source code of a stylesheet or query; this instance is created when Saxon calls the method <code>MakeFunctionCall</code>
210
    /// provided by the <code>ExtensionFunctionDefinition</code> object. The instance of <code>ExtensionFunctionCall</code>
211
    /// holds information about the static context of the function call, and its <code>Call</code> method is called
212
    /// (by Saxon) to evaluate the extension function at run-time.</para>
213
    /// </remarks>
214
215
    public abstract class ExtensionFunctionDefinition
216
    {
217
        /// <summary>
218
		/// Read-only property returning the name of the extension function, as a <c>QName</c>.
219
        /// </summary>
220
        /// <remarks>
221
        /// A getter for this property must be implemented in every subclass.
222
        /// </remarks>
223
224
        public abstract QName FunctionName {get;}
225
226
        /// <summary>
227
        /// Read-only property giving the minimum number of arguments in a call to this extension function.
228
        /// </summary>
229
        /// <remarks>
230
        /// A getter for this property must be implemented in every subclass.
231
        /// </remarks>
232
233
        public abstract int MinimumNumberOfArguments {get;}
234
235
        /// <summary>
236
        /// Read-only property giving the maximum 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 MaximumNumberOfArguments {get;}
243
244
        /// <summary>
245
        /// Read-only property giving the required types of the arguments to this extension function. 
246
        /// If the number of items in the array is less than the maximum number of arguments, 
247
		/// then the last entry in the returned <c>ArgumentTypes</c> is assumed to apply to all the rest; 
248
        /// if the returned array is empty, then all arguments are assumed to be of type <c>item()*</c>
249
        /// </summary>
250
        /// <remarks>
251
        /// A getter for this property must be implemented in every subclass.
252
		/// </remarks>
253
		/// <returns>
254
		/// An array of <c>XdmSequenceType</c> objects representing the required types of the arguments 
255
		/// to the extension function.
256
		/// </returns>
257
258
        public abstract XdmSequenceType[] ArgumentTypes {get;}
259
260
        /// <summary>
261
        /// Method returning the declared type of the return value from the function. The type of the return
262
        /// value may be known more precisely if the types of the arguments are known (for example, some functions
263
		/// return a value that is the same type as the first argument). The method is therefore called supplying the
264
        /// static types of the actual arguments present in the call.
265
        /// </summary>
266
        /// <remarks>
267
        /// This method must be implemented in every subclass.
268
        /// </remarks>
269
        /// <param name="ArgumentTypes">
270
        /// The static types of the arguments present in the function call
271
        /// </param>
272
        /// <returns>
273
        /// An <c>XdmSequenceType</c> representing the declared return type of the extension function
274
        /// </returns>
275
276
        public abstract XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes);
277
278
        /// <summary>
279
        /// This property may return true for a subclass if it guarantees that the returned result of the function
280
        /// will always be of the declared return type: setting this to true by-passes the run-time checking of the type
281
        /// of the value, together with code that would otherwise perform atomization, numeric type promotion, and similar
282
        /// conversions. If the value is set to true and the value is not of the correct type, the effect is unpredictable
283
        /// and probably disastrous.
284
        /// </summary>
285
        /// <remarks>
286
        /// The default value of this property is <c>false</c>. A getter for this property may be implemented in a subclass
287
        /// to return a different value.
288
        /// </remarks>
289
290
        public virtual Boolean TrustResultType {
291
            get{return false;}
292
        }
293
294
        /// <summary>
295
        /// This property must return true for a subclass if the evaluation of the function makes use of the context
296
        /// item, position, or size from the dynamic context. It should also return true (despite the property name)
297
        /// if the function makes use of parts of the static context that vary from one part of the query or stylesheet
298
        /// to another. Setting the property to true inhibits certain Saxon optimizations, such as extracting the call
299
        /// from a loop, or moving it into a global variable.
300
        /// </summary>
301
        /// <remarks>
302
        /// The default value of this property is <c>false</c>. A getter for this property may be implemented in a subclass
303
        /// to return a different value.
304
        /// </remarks>
305
306
        public virtual Boolean DependsOnFocus {
307
            get{return false;}
308
        }
309
310
        /// <summary>
311
        /// This property should return true for a subclass if the evaluation of the function has side-effects.
312
        /// Saxon never guarantees the result of calling functions with side-effects, but if this property is set,
313
        /// then certain aggressive optimizations will be avoided, making it more likely that the function behaves
314
        /// as expected.
315
        /// </summary>
316
        /// <remarks>
317
        /// The default value of this property is <c>false</c>. A getter for this property may be implemented in a subclass
318
        /// to return a different value.
319
        /// </remarks>
320
321
        public virtual Boolean HasSideEffects {
322
            get{return false;}
323
        }
324
325
        /// <summary>
326
        /// Factory method to create an <c>ExtensionFunctionCall</c> object, representing a specific function call in the XSLT or XQuery
327
        /// source code. Saxon will call this method once it has identified that a specific call relates to this extension
328
        /// function.
329
        /// </summary>
330
        /// <remarks>
331
        /// This method must be implemented in every subclass. The implementation should normally instantiate the relevant subclass
332
        /// of <code>ExtensionFunctionCall</code>, and return the new instance.
333
        /// </remarks>
334
        /// <returns>
335
        /// An instance of the appropriate implementation of <code>ExtensionFunctionCall</code>
336
        /// </returns>
337
338
        public abstract ExtensionFunctionCall MakeFunctionCall();
339
    }
340
341
    /// <summary>
342
    /// An instance of this class will be created by the compiler for each function call to this extension function
343
    /// that is found in the source code. The class is always instantiated by calling the method <c>MakeFunctionCall()</c>
344
    /// of the corresponding <c>ExtensionFunctionDefinition</c>. 
345
    /// The implementation may therefore retain information about the static context of the
346
    /// call. Once compiled, however, the instance object must be immutable.
347
    /// </summary>
348
349
    public abstract class ExtensionFunctionCall
350
    {
351
352
        /// <summary>
353
        /// Method called by the compiler (at compile time) to provide information about the static context of the
354
        /// function call. The implementation may retain this information for use at run-time, if the result of the
355
        /// function depends on information in the static context.
356
        /// </summary>
357
        /// <remarks>
358
        /// For efficiency, the implementation should only retain copies of the information that it actually needs. It
359
        /// is not a good idea to hold a reference to the static context itself, since that can result in a great deal of
360
        /// compile-time information being locked into memory during run-time execution.
361
        /// </remarks>
362
        /// <param name="context">Information about the static context in which the function is called</param>
363
364
        public virtual void SupplyStaticContext(StaticContext context)
365
        {
366
            // default: no action
367
        }
368
369
        /// <summary>
370
        /// A subclass must implement this method if it retains any local data at the instance level. On some occasions
371
        /// (for example, when XSLT or XQuery code is inlined), Saxon will make a copy of an <c>ExtensionFunction</c> object.
372
        /// It will then call this method on the old object, supplying the new object as the value of the argument, and the
373
        /// method must copy all local data items from the old object to the new.
374
        /// </summary>
375
        /// <param name="destination">The new extension function object. This will always be an instance of the same
376
        /// class as the existing object.</param>
377
378
        public virtual void CopyLocalData(ExtensionFunctionCall destination) { }
379
380
        /// <summary>
381
        /// Method called at run time to evaluate the function.
382
        /// </summary>
383
        /// <param name="arguments">The values of the arguments to the function, supplied as iterators over XPath
384
        /// sequence values.</param>
385
        /// <param name="context">The dynamic context for evaluation of the function. This provides access
386
        /// to the context item, position, and size, and if required to internal data maintained by the Saxon
387
        /// engine.</param>
388
        /// <returns>An iterator over a sequence, representing the result of the extension function.
389
        /// Note that Saxon does not guarantee to read this sequence to completion, so calls on the iterator
390
        /// must have no side-effects. In rare circumstances (for example, when <code>last()</code> is
391
        /// used) Saxon may clone the returned iterator by calling its <c>GetAnother()</c> method, 
392
        /// allowing the function results to be read more than once.</returns>
393
394
        public abstract IEnumerator<XdmItem> Call(IEnumerator<XdmItem>[] arguments, DynamicContext context);
395
    }
396
397
    /// <summary>
398
    /// This is an interface for simple external/extension functions.
399
    /// Users can implement this interface and register the implementation with the <see cref="Saxon.Api.Processor"/>;
400
    /// the function will then be available for calling from all queries, stylesheets, and XPath expressions compiled
401
    /// under this Processor.
402
    /// </summary>
403
    /// <remarks>
404
    /// <para>Extension functions implemented using this interface are expected to be free of side-effects,
405
    /// and to have no dependencies on the static or dynamic context. A richer interface for extension
406
    /// functions is provided via the <see cref="Saxon.Api.ExtensionFunctionDefinition"/> class.</para>
407
    /// </remarks>
408
409
    public interface ExtensionFunction
410
    {
411
412
        /// <summary>
413
        /// Return the name of the external function
414
        /// </summary>
415
        /// <returns>the name of the function, as a <c>QName</c></returns>
416
417
		/**public**/ 
418
		QName GetName();
419
420
421
        /// <summary>
422
        /// Declare the result type of the external function
423
        /// </summary>
424
        /// <returns>the result type of the external function</returns>
425
426
		/**public**/ 
427
		XdmSequenceType GetResultType();
428
429
        /// <summary>
430
        /// Declare the type of the arguments
431
        /// </summary>
432
        /// <returns>an array of <c>XdmSequenceType</c> objects, one for each argument to the function,
433
        /// representing the expected types of the arguments</returns>
434
435
		/**public**/ 
436
		XdmSequenceType[] GetArgumentTypes();
437
438
439
        /// <summary>
440
        /// Method called at run time to evaluate the function.
441
        /// </summary>
442
        /// <param name="arguments">The values of the arguments supplied in the XPath function call.</param>
443
        /// <returns>An <c>XdmValue</c>, representing the result of the extension function. 
444
        /// (Note: in many cases it will be convenient to return an <c>XdmAtomicValue</c> or <c>XdmNode</c>, 
445
        /// both of which are instances of <c>XdmValue</c>).</returns>
446
447
		/**public**/ 
448
		XdmValue Call(XdmValue[] arguments);
449
    }
450
451
    internal class WrappedExtensionFunction : JExtensionFunction
452
    {
453
        ExtensionFunction definition;
454
455
        public WrappedExtensionFunction(ExtensionFunction definition)
456
        {
457
            this.definition = definition;
458
        }
459
460
        public net.sf.saxon.s9api.XdmValue call(net.sf.saxon.s9api.XdmValue[] xvarr)
461
        {
462
            XdmValue[] values = new XdmValue[xvarr.Length];
463
            int len = xvarr.Length;
464
            for (int i = 0; i < len; i++) {
465
                values[i] = XdmValue.Wrap(xvarr[i].getUnderlyingValue());
466
            }
467
            try {
468
                XdmValue result = definition.Call(values);
469
                return XdmValue.FromGroundedValueToJXdmValue(result.value);
470
            }
471
            catch (Exception ex) {
472
                throw new DynamicError(ex.Message);
473
            }
474
            
475
            }
476
477
        public JXdmSequenceType[] getArgumentTypes()
478
        {
479
            XdmSequenceType [] types = definition.GetArgumentTypes();
480
            JXdmSequenceType[] results = new JXdmSequenceType[types.Length];
481
            for (int i = 0; i < types.Length; i++) {
482
                results[i] = types[i].ToJXdmSequenceType();
483
            }
484
            return results;
485
        }
486
487
        public net.sf.saxon.s9api.QName getName()
488
        {
489
            return definition.GetName().UnderlyingQName();
490
        }
491
492
        public JXdmSequenceType getResultType()
493
        {
494
            JXdmSequenceType declaredResult = definition.GetResultType().ToJXdmSequenceType();
495
            return declaredResult;
496
        }
497
    }
498
499
        internal class WrappedExtensionFunctionDefinition : JExtensionFunctionDefinition
500
    {
501
        ExtensionFunctionDefinition definition;
502
503
        public WrappedExtensionFunctionDefinition(ExtensionFunctionDefinition definition)
504
        {
505
            this.definition = definition;
506
        }
507
508
        public override JStructuredQName getFunctionQName()
509
        {
510
            return definition.FunctionName.ToStructuredQName();
511
        }
512
513
        public override int getMinimumNumberOfArguments()
514
        {
515
            return definition.MinimumNumberOfArguments;
516
        }
517
518
        public override int getMaximumNumberOfArguments()
519
        {
520
            return definition.MaximumNumberOfArguments;
521
        }
522
523
        public override JSequenceType[] getArgumentTypes()
524
        {
525
            XdmSequenceType[] dt = definition.ArgumentTypes;
526
            JSequenceType[] jt = new JSequenceType[dt.Length];
527
            for (int i = 0; i < dt.Length; i++)
528
            {
529
                jt[i] = dt[i].ToSequenceType();
530
            }
531
            return jt;
532
        }
533
534
        public override JSequenceType getResultType(JSequenceType[] argumentTypes)
535
        {
536
            XdmSequenceType[] dt = new XdmSequenceType[argumentTypes.Length];
537
            for (int i = 0; i < dt.Length; i++)
538
            {
539
                dt[i] = XdmSequenceType.FromSequenceType(argumentTypes[i]);
540
            }
541
542
            XdmSequenceType rt = definition.ResultType(dt);
543
            return rt.ToSequenceType();
544
        }
545
546
        public override Boolean trustResultType()
547
        {
548
            return definition.TrustResultType;
549
        }
550
551
        public override Boolean dependsOnFocus()
552
        {
553
            return definition.DependsOnFocus;
554
        }
555
556
        public override Boolean hasSideEffects()
557
        {
558
            return definition.HasSideEffects;
559
        }
560
561
        public override JExtensionFunctionCall makeCallExpression()
562
        {
563
            return new WrappedExtensionFunctionCall(definition.MakeFunctionCall());
564
        }
565
566
    }
567
568
    internal class Mapper : net.sf.saxon.dotnet.DotNetIterator.Mapper
569
    {
570
        public object convert(object obj)
571
        {
572
            XdmItem i = (XdmItem)obj;
573
            return (JItem)i.Unwrap();
574
        }
575
    }
576
577
    internal class WrappedExtensionFunctionCall : JExtensionFunctionCall {
578
579
        ExtensionFunctionCall functionCall;
580
581
        public WrappedExtensionFunctionCall(ExtensionFunctionCall call)
582
        {
583
            this.functionCall = call;
584
        }
585
        
586
        public override void supplyStaticContext(JStaticContext context, int locationId, JExpression[] arguments)
587
        {
588
            StaticContext sc = new StaticContext(context);
589
            functionCall.SupplyStaticContext(sc);
590
        }
591
592
        public override void copyLocalData(JExtensionFunctionCall destination)
593
        {
594
            functionCall.CopyLocalData(((WrappedExtensionFunctionCall)destination).functionCall);
595
        }
596
597
        public override JSequence call(JXPathContext context, JSequence [] argument)
598
        {
599
            SequenceEnumerator<XdmItem>[] na = new SequenceEnumerator<XdmItem>[argument.Length];
600
            for (int i = 0; i < na.Length; i++)
601
            {
602
                na[i] = new SequenceEnumerator<XdmItem>((JXdmSequenceIterator)XdmValue.FromGroundedValueToJXdmValue(argument[i].materialize()).iterator());
603
            }
604
            DynamicContext dc = new DynamicContext(context);
605
            IEnumerator<XdmItem> result = functionCall.Call(na, dc);
606
            return new net.sf.saxon.om.LazySequence(new net.sf.saxon.om.IteratorWrapper(new net.sf.saxon.dotnet.DotNetIterator(result, new Mapper())));
607
        }
608
    }
609
}
610
611
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
612
// Copyright (c) 2020 Saxonica Limited.
613
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
614
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
615
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
616
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////