Project

Profile

Help

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

he / latest9.9 / hen / csource / api / Saxon.Api / Extensibility.cs @ a2e6e9df

1
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 System.Collections.Generic;
17

    
18
namespace Saxon.Api
19
{
20

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

    
25
    public class StaticContext {
26

    
27
        private JStaticContext env;
28

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

    
33

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

    
44

    
45
        /// <summary>
46
        /// The static base URI of the expression. Often the same as the URI of the containing module,
47
        /// but not necessarily so, for example in a stylesheet that uses external XML entities or the
48
		/// <c>xml:base</c> attribute
49
        /// </summary>
50
        
51
		public Uri BaseUri {
52
            get {
53
				return new Uri(env.getStaticBaseURI());
54
            }
55
        }
56

    
57
        /// <summary>
58
        /// Resolve an in-scope namespace prefix to obtain the corresponding namespace URI. If the prefix
59
        /// is a zero-length string, the default namespace for elements and types is returned.
60
        /// </summary>
61
        /// <param name="Prefix">The namespace prefix</param>
62
        /// <returns>The corresponding namespace URI if there is one, or null otherwise</returns>
63
        
64
		public String GetNamespaceForPrefix(string Prefix) {
65
            if (Prefix == "") {
66
                return env.getDefaultElementNamespace();
67
            }
68
            try {
69
				return env.getNamespaceResolver().getURIForPrefix(Prefix, false);
70
            } catch (JXPathException) {
71
                return null;
72
            }
73
        }
74

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

    
88
        public Processor Processor
89
        {
90
            get
91
            {
92
                JConfiguration config = env.getConfiguration();
93
                Object p = config.getProcessor();
94
                if (p is Processor)
95
                {
96
                    return (Processor)p;
97
                }
98
                else
99
                {
100
                    return null;
101
                }
102

    
103
            }
104
        }
105

    
106
        /// <summary>
107
        /// The underlying object in the Saxon implementation, an instance of class
108
		/// <code>net.sf.saxon.expr.StaticContext</code>
109
        /// </summary>
110
        /// <remarks>
111
        /// <para>This property provides access to internal methods in the Saxon engine that are
112
        /// not specifically exposed in the .NET API. In general these methods should be
113
        /// considered to be less stable than the classes in the Saxon.Api namespace.</para> 
114
        /// <para>The internal methods follow
115
        /// Java naming conventions rather than .NET conventions.</para>
116
        /// <para>Information about the returned object (and the objects it provides access to)
117
		/// is included in the Saxon JavaDoc documentation, see <see cref="net.sf.saxon.expr.StaticContext"/>.
118
        /// </para>
119
        /// </remarks>
120

    
121
        public JStaticContext Implementation
122
        {
123
            get { return env; }
124
        }
125
    }
126

    
127
    /// <summary>
128
    /// The class <c>DynamicContext</c> provides information about the dynamic context of an expression
129
    /// </summary>
130
    
131
	public class DynamicContext {
132

    
133
        internal JXPathContext context;
134

    
135
        internal DynamicContext(JXPathContext context) {
136
            this.context = context;
137
        }
138

    
139
        /// <summary>
140
        /// The context item. May be null if no context item is defined
141
        /// </summary>
142
        
143
		public XdmItem ContextItem {
144
            get {
145
                return context.getContextItem()== null ? null : (XdmItem)XdmItem.Wrap(context.getContextItem());
146
            }
147
        }
148

    
149
        /// <summary>
150
		/// The context position (equivalent to the XPath <c>position()</c> function).
151
        /// </summary>
152
        /// <remarks>Calling this method throws an exception if the context item is undefined.</remarks>
153
        
154
		public int ContextPosition {
155
            get {
156
                return context.getCurrentIterator().position();
157
            }
158
        }
159

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

    
171
        /// <summary>
172
        /// The underlying object in the Saxon implementation, an instance of class
173
		/// <code>net.sf.saxon.expr.XPathContext</code>
174
        /// </summary>
175
        /// <remarks>
176
        /// <para>This property provides access to internal methods in the Saxon engine that are
177
        /// not specifically exposed in the .NET API. In general these methods should be
178
        /// considered to be less stable than the classes in the Saxon.Api namespace.</para> 
179
        /// <para>The internal methods follow
180
        /// Java naming conventions rather than .NET conventions.</para>
181
        /// <para>Information about the returned object (and the objects it provides access to)
182
		/// is included in the Saxon JavaDoc documentation, see <see cref="net.sf.saxon.expr.XPathContext"/>
183
        /// </para>
184
        /// </remarks>
185

    
186
        public JXPathContext Implementation
187
        {
188
            get { return context; }
189
        }        
190

    
191
    }
192

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

    
214
    public abstract class ExtensionFunctionDefinition
215
    {
216
        /// <summary>
217
		/// Read-only property returning the name of the extension function, as a <c>QName</c>.
218
        /// </summary>
219
        /// <remarks>
220
        /// A getter for this property must be implemented in every subclass.
221
        /// </remarks>
222

    
223
        public abstract QName FunctionName {get;}
224

    
225
        /// <summary>
226
        /// Read-only property giving the minimum number of arguments in a call to this extension function.
227
        /// </summary>
228
        /// <remarks>
229
        /// A getter for this property must be implemented in every subclass.
230
        /// </remarks>
231

    
232
        public abstract int MinimumNumberOfArguments {get;}
233

    
234
        /// <summary>
235
        /// Read-only property giving the maximum number of arguments in a call to this extension function.
236
        /// </summary>
237
        /// <remarks>
238
        /// A getter for this property must be implemented in every subclass.
239
        /// </remarks>
240
        
241
        public abstract int MaximumNumberOfArguments {get;}
242

    
243
        /// <summary>
244
        /// Read-only property giving the required types of the arguments to this extension function. 
245
        /// If the number of items in the array is less than the maximum number of arguments, 
246
		/// then the last entry in the returned <c>ArgumentTypes</c> is assumed to apply to all the rest; 
247
        /// if the returned array is empty, then all arguments are assumed to be of type <c>item()*</c>
248
        /// </summary>
249
        /// <remarks>
250
        /// A getter for this property must be implemented in every subclass.
251
		/// </remarks>
252
		/// <returns>
253
		/// An array of <c>XdmSequenceType</c> objects representing the required types of the arguments 
254
		/// to the extension function.
255
		/// </returns>
256

    
257
        public abstract XdmSequenceType[] ArgumentTypes {get;}
258

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

    
275
        public abstract XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes);
276

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

    
289
        public virtual Boolean TrustResultType {
290
            get{return false;}
291
        }
292

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

    
305
        public virtual Boolean DependsOnFocus {
306
            get{return false;}
307
        }
308

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

    
320
        public virtual Boolean HasSideEffects {
321
            get{return false;}
322
        }
323

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

    
337
        public abstract ExtensionFunctionCall MakeFunctionCall();
338
    }
339

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

    
348
    public abstract class ExtensionFunctionCall
349
    {
350

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

    
363
        public virtual void SupplyStaticContext(StaticContext context)
364
        {
365
            // default: no action
366
        }
367

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

    
377
        public virtual void CopyLocalData(ExtensionFunctionCall destination) { }
378

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

    
393
        public abstract IEnumerator<XdmItem> Call(IEnumerator<XdmItem>[] arguments, DynamicContext context);
394
    }
395

    
396
    /// <summary>
397
    /// This is an interface for simple external/extension functions.
398
    /// Users can implement this interface and register the implementation with the <see cref="Saxon.Api.Processor"/>;
399
    /// the function will then be available for calling from all queries, stylesheets, and XPath expressions compiled
400
    /// under this Processor.
401
    /// </summary>
402
    /// <remarks>
403
    /// <para>Extension functions implemented using this interface are expected to be free of side-effects,
404
    /// and to have no dependencies on the static or dynamic context. A richer interface for extension
405
    /// functions is provided via the <see cref="Saxon.Api.ExtensionFunctionDefinition"/> class.</para>
406
    /// </remarks>
407

    
408
    public interface ExtensionFunction
409
    {
410

    
411
        /// <summary>
412
        /// Return the name of the external function
413
        /// </summary>
414
        /// <returns>the name of the function, as a <c>QName</c></returns>
415

    
416
		/**public**/ 
417
		QName GetName();
418

    
419

    
420
        /// <summary>
421
        /// Declare the result type of the external function
422
        /// </summary>
423
        /// <returns>the result type of the external function</returns>
424

    
425
		/**public**/ 
426
		XdmSequenceType GetResultType();
427

    
428
        /// <summary>
429
        /// Declare the type of the arguments
430
        /// </summary>
431
        /// <returns>an array of <c>XdmSequenceType</c> objects, one for each argument to the function,
432
        /// representing the expected types of the arguments</returns>
433

    
434
		/**public**/ 
435
		XdmSequenceType[] GetArgumentTypes();
436

    
437

    
438
        /// <summary>
439
        /// Method called at run time to evaluate the function.
440
        /// </summary>
441
        /// <param name="arguments">The values of the arguments supplied in the XPath function call.</param>
442
        /// <returns>An <c>XdmValue</c>, representing the result of the extension function. 
443
        /// (Note: in many cases it will be convenient to return an <c>XdmAtomicValue</c> or <c>XdmNode</c>, 
444
        /// both of which are instances of <c>XdmValue</c>).</returns>
445

    
446
		/**public**/ 
447
		XdmValue Call(XdmValue[] arguments);
448
    }
449

    
450
    internal class WrappedExtensionFunction : JExtensionFunction
451
    {
452
        ExtensionFunction definition;
453

    
454
        public WrappedExtensionFunction(ExtensionFunction definition)
455
        {
456
            this.definition = definition;
457
        }
458

    
459
        public net.sf.saxon.s9api.XdmValue call(net.sf.saxon.s9api.XdmValue[] xvarr)
460
        {
461
            XdmValue[] values = new XdmValue[xvarr.Length];
462
            int len = xvarr.Length;
463
            for (int i = 0; i < len; i++) {
464
                values[i] = XdmValue.Wrap(xvarr[i].getUnderlyingValue());
465
            }
466
            try {
467
                XdmValue result = definition.Call(values);
468
                return XdmValue.FromGroundedValueToJXdmValue(result.value);
469
            }
470
            catch (Exception ex) {
471
                throw new DynamicError(ex.Message);
472
            }
473
            
474
            }
475

    
476
        public JXdmSequenceType[] getArgumentTypes()
477
        {
478
            XdmSequenceType [] types = definition.GetArgumentTypes();
479
            JXdmSequenceType[] results = new JXdmSequenceType[types.Length];
480
            for (int i = 0; i < types.Length; i++) {
481
                results[i] = types[i].ToJXdmSequenceType();
482
            }
483
            return results;
484
        }
485

    
486
        public net.sf.saxon.s9api.QName getName()
487
        {
488
            return definition.GetName().UnderlyingQName();
489
        }
490

    
491
        public JXdmSequenceType getResultType()
492
        {
493
            JXdmSequenceType declaredResult = definition.GetResultType().ToJXdmSequenceType();
494
            return declaredResult;
495
        }
496
    }
497

    
498
        internal class WrappedExtensionFunctionDefinition : JExtensionFunctionDefinition
499
    {
500
        ExtensionFunctionDefinition definition;
501

    
502
        public WrappedExtensionFunctionDefinition(ExtensionFunctionDefinition definition)
503
        {
504
            this.definition = definition;
505
        }
506

    
507
        public override JStructuredQName getFunctionQName()
508
        {
509
            return definition.FunctionName.ToStructuredQName();
510
        }
511

    
512
        public override int getMinimumNumberOfArguments()
513
        {
514
            return definition.MinimumNumberOfArguments;
515
        }
516

    
517
        public override int getMaximumNumberOfArguments()
518
        {
519
            return definition.MaximumNumberOfArguments;
520
        }
521

    
522
        public override JSequenceType[] getArgumentTypes()
523
        {
524
            XdmSequenceType[] dt = definition.ArgumentTypes;
525
            JSequenceType[] jt = new JSequenceType[dt.Length];
526
            for (int i = 0; i < dt.Length; i++)
527
            {
528
                jt[i] = dt[i].ToSequenceType();
529
            }
530
            return jt;
531
        }
532

    
533
        public override JSequenceType getResultType(JSequenceType[] argumentTypes)
534
        {
535
            XdmSequenceType[] dt = new XdmSequenceType[argumentTypes.Length];
536
            for (int i = 0; i < dt.Length; i++)
537
            {
538
                dt[i] = XdmSequenceType.FromSequenceType(argumentTypes[i]);
539
            }
540

    
541
            XdmSequenceType rt = definition.ResultType(dt);
542
            return rt.ToSequenceType();
543
        }
544

    
545
        public override Boolean trustResultType()
546
        {
547
            return definition.TrustResultType;
548
        }
549

    
550
        public override Boolean dependsOnFocus()
551
        {
552
            return definition.DependsOnFocus;
553
        }
554

    
555
        public override Boolean hasSideEffects()
556
        {
557
            return definition.HasSideEffects;
558
        }
559

    
560
        public override JExtensionFunctionCall makeCallExpression()
561
        {
562
            return new WrappedExtensionFunctionCall(definition.MakeFunctionCall());
563
        }
564

    
565
    }
566

    
567
    internal class WrappedExtensionFunctionCall : JExtensionFunctionCall {
568

    
569
        ExtensionFunctionCall functionCall;
570

    
571
        public WrappedExtensionFunctionCall(ExtensionFunctionCall call)
572
        {
573
            this.functionCall = call;
574
        }
575
        
576
        public override void supplyStaticContext(JStaticContext context, int locationId, JExpression[] arguments)
577
        {
578
            StaticContext sc = new StaticContext(context);
579
            functionCall.SupplyStaticContext(sc);
580
        }
581

    
582
        public override void copyLocalData(JExtensionFunctionCall destination)
583
        {
584
            functionCall.CopyLocalData(((WrappedExtensionFunctionCall)destination).functionCall);
585
        }
586

    
587
        public override JSequence call(JXPathContext context, JSequence [] argument)
588
        {
589
            SequenceEnumerator<XdmItem>[] na = new SequenceEnumerator<XdmItem>[argument.Length];
590
            for (int i = 0; i < na.Length; i++)
591
            {
592
                na[i] = new SequenceEnumerator<XdmItem>((JXdmSequenceIterator)XdmValue.FromGroundedValueToJXdmValue(argument[i].materialize()).iterator());
593
            }
594
            DynamicContext dc = new DynamicContext(context);
595
            IEnumerator<XdmItem> result = functionCall.Call(na, dc);
596
            return new net.sf.saxon.om.LazySequence(new DotNetSequenceIterator(result));
597
        }
598
    }
599
}
600

    
601
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
602
// Copyright (c) 2018 Saxonica Limited.
603
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
604
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
605
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
606
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
(4-4/13)