Project

Profile

Help

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

he / src / test / nunit / SaxonNUnit / SaxonNUnit / TestIntegratedExtensionFunctionXslt.cs @ 3df04590

1
using System;
2
using System.IO;
3
using System.Xml;
4
using System.Collections.Generic;
5
using System.Linq;
6
using System.Text;
7
using Saxon.Api;
8
using NUnit.Framework;
9
using System.Collections;
10

    
11
namespace SaxonNUnit
12
{
13
    class TestIntegratedExtensionFunctionXslt
14
    {
15

    
16
        /**
17
        * Test integrated extension function in XSLT
18
        */
19
        [Test]
20
        public void TestIntegratedExtensionFunctionXslt1()
21
        {
22
            try
23
            {
24
                Processor proc = new Processor(false);
25
                proc.RegisterExtensionFunction(new ZeroArgFunction());
26
                proc.RegisterExtensionFunction(new Sqrt());
27
                proc.RegisterExtensionFunction(new InscopePrefixFunction());
28
                XsltCompiler comp = proc.NewXsltCompiler();
29
                StringReader sr = new StringReader(
30
                        "<xsl:stylesheet version='2.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform' xmlns:f='http://math.com/'>" +
31
                        "<xsl:template name='go'><a sqrt2='{f:sqrt(2)}' insn=\"{f:insn('xsl')}\" zag=\"{f:zag()}\"/></xsl:template>" +
32
                        "</xsl:stylesheet>");
33
                XsltExecutable exec = comp.Compile(sr);
34
                XsltTransformer xsl = exec.Load();
35
                xsl.InitialTemplate = new QName("go");
36
                StringWriter sw = new StringWriter();
37
                Serializer out1 = proc.NewSerializer();
38
                out1.SetOutputWriter(sw);
39
                xsl.Run(out1);
40

    
41
                //"sqrt "
42
                Assert.IsTrue(sw.ToString().Contains("1.414213"));
43
                //"zag "
44
                Assert.IsTrue(sw.ToString().Contains("123.4"));
45
                //"inscope "
46
                Assert.IsTrue(sw.ToString().Contains("1999/XSL/Transform"));
47
            }
48
            catch (javax.xml.transform.TransformerException e)
49
            {
50
                Assert.Fail(e.Message);
51
            }
52
        }
53

    
54

    
55

    
56

    
57
        /**
58
         * An IntegratedFunction that takes zero arguments
59
         */
60

    
61

    
62
        public class ZeroArgFunction : ExtensionFunctionDefinition
63
        {
64

    
65

    
66
            public override QName FunctionName
67
            {
68
                get { return new QName("", "http://math.com/", "zag"); }
69
            }
70

    
71

    
72
            /**
73
             * Return the minimum number of arguments required by the function
74
             * @return the minimum number of arguments that must be supplied in a call to this function
75
             */
76

    
77
            public override int MinimumNumberOfArguments
78
            {
79
                get { return 0; }
80
            }
81

    
82
            /**
83
             * Return the maximum number of arguments allowed by the function
84
             * @return the maximum number of arguments that may be supplied in a call to this function
85
             */
86

    
87
            public override int MaximumNumberOfArguments
88
            {
89
                get { return 0; }
90
            }
91

    
92
            /**
93
             * Get the required types for the arguments of this function, counting from zero
94
             * @return the required types of the argument, as defined by the function signature. Normally
95
             *         this should be an array of size {@link #getMaximumNumberOfArguments()}; however for functions
96
             *         that allow a variable number of arguments, the array can be smaller than this, with the last
97
             *         entry in the array providing the required type for all the remaining arguments.
98
             */
99
            public override XdmSequenceType[] ArgumentTypes
100
            {
101
                get
102
                {
103
                    return new XdmSequenceType[] {
104
                            new XdmSequenceType(XdmAtomicType.BuiltInAtomicType(QName.XS_DOUBLE), '?')
105

    
106
                        };
107
                }
108
            }
109

    
110

    
111
            /**
112
             * Get the type of the result of the function
113
             * @param suppliedArgumentTypes the static types of the arguments to the function.
114
             *    This is provided so that a more precise result type can be returned in the common
115
             *    case where the type of the result depends on the type of the first argument. The value
116
             *    will be null if the function call has no arguments.
117
             * @return the return type of the function, as defined by its function signature
118
             */
119

    
120
            public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
121
            {
122
                return new XdmSequenceType(XdmAtomicType.BuiltInAtomicType(QName.XS_DOUBLE), '?');
123
            }
124

    
125

    
126
            /**
127
             * Ask whether the result actually returned by the function should be checked against
128
             * the declared type.
129
             * @return true if the function implementation warrants that the value it returns will
130
             *         be an instance of the declared result type. The default value is false, in which case
131
             *         the result will be checked at run-time to ensure that it conforms to the declared type.
132
             *         If the value true is returned, but the function returns a value of the wrong type, the
133
             *         consequences are unpredictable.
134
             */
135

    
136
            public bool trustResultType()
137
            {
138
                return true;
139
            }
140

    
141
            /**
142
         * Create a call on this function. This method is called by the compiler when it identifies
143
             * a function call that calls this function.
144
             */
145

    
146
            public override ExtensionFunctionCall MakeFunctionCall()
147
            {
148
                return new ZeroArgFunctionCall();
149
            }
150
        }
151

    
152
        public class ZeroArgFunctionCall : ExtensionFunctionCall
153
        {
154

    
155
            /**
156
             * Evaluate this function call at run-time
157
             *
158
             *
159
     * @param context   The XPath dynamic evaluation context
160
             * @param arguments The values of the arguments to the function call. Each argument value (which is in general
161
             *                  a sequence) is supplied in the form of an iterator over the items in the sequence. If required, the
162
             *                  supplied sequence can be materialized by calling, for example, <code>new SequenceExtent(arguments[i])</code>.
163
             *                  If the argument is always a singleton, then the single item may be obtained by calling
164
             *                  <code>arguments[i].next()</code>.
165
             * @return an iterator over the results of the function. If the result is a single item, it can be
166
             *         returned in the form of a {@link net.sf.saxon.tree.iter.SingletonIterator}.
167
             * @throws net.sf.saxon.trans.XPathException
168
             *          if a dynamic error occurs during evaluation of the function.
169
             */
170

    
171
            public override IEnumerator<XdmItem> Call(IEnumerator<XdmItem>[] arguments, DynamicContext context)
172
            {
173
                double val = 123.4e0;
174
                Saxon.Api.XdmAtomicValue result = new Saxon.Api.XdmAtomicValue(val);
175
                return result.GetEnumerator();
176
            }
177
        }
178

    
179
        public class Sqrt : ExtensionFunctionDefinition
180
        {
181

    
182
            public override QName FunctionName
183
            {
184
                get { return new QName("http://math.com/", "sqrt"); }
185
            }
186

    
187
            public override int MinimumNumberOfArguments
188
            {
189
                get { return 1; }
190
            }
191

    
192
            public override int MaximumNumberOfArguments
193
            {
194
                get { return 1; }
195
            }
196

    
197
            public override XdmSequenceType[] ArgumentTypes
198
            {
199
                get
200
                {
201
                    return new XdmSequenceType[] {
202
                            new XdmSequenceType(XdmAtomicType.BuiltInAtomicType(QName.XS_DOUBLE), '?')
203
                          };
204
                }
205
            }
206

    
207
            public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
208
            {
209
                return new XdmSequenceType(XdmAtomicType.BuiltInAtomicType(QName.XS_DOUBLE), '?');
210
            }
211

    
212
            public override bool TrustResultType
213
            {
214
                get { return true; }
215
            }
216

    
217
            public override ExtensionFunctionCall MakeFunctionCall()
218
            {
219
                return new SqrtCall();
220
            }
221
        }
222

    
223
        public class SqrtCall : ExtensionFunctionCall
224
        {
225

    
226
            public override IEnumerator<XdmItem> Call(IEnumerator<XdmItem>[] arguments, DynamicContext context)
227
            {
228
                Boolean exists = arguments[0].MoveNext();
229
                if (exists)
230
                {
231
                    XdmAtomicValue arg = (XdmAtomicValue)arguments[0].Current;
232
                    double val = (double)arg.Value;
233
                    double sqrt = System.Math.Sqrt(val);
234
                    XdmAtomicValue result = new XdmAtomicValue(sqrt);
235
                    return result.GetEnumerator();
236
                }
237
                else
238
                {
239
                    return (IEnumerator<XdmItem>)EmptyEnumerator<XdmItem>.INSTANCE;
240
                }
241
            }
242
        }
243

    
244

    
245

    
246

    
247
        /**
248
           * An integrated extension function whose task is to find the namespace URI corresponding to a given
249
           * prefix in the static namespace context
250
           */
251

    
252

    
253
        public class InscopePrefixFunction : ExtensionFunctionDefinition
254
        {
255

    
256

    
257
            public override QName FunctionName
258
            {
259
                get { return new QName("", "http://math.com/", "insn"); }
260
            }
261

    
262

    
263
            /**
264
             * Return the minimum number of arguments required by the function
265
             * @return the minimum number of arguments that must be supplied in a call to this function
266
             */
267

    
268
            public override int MinimumNumberOfArguments
269
            {
270
                get { return 1; }
271
            }
272

    
273
            /**
274
             * Return the maximum number of arguments allowed by the function
275
             * @return the maximum number of arguments that may be supplied in a call to this function
276
             */
277

    
278
            public override int MaximumNumberOfArguments
279
            {
280
                get { return 1; }
281
            }
282

    
283
            /**
284
             * Get the required types for the arguments of this function, counting from zero
285
             * @return the required types of the argument, as defined by the function signature. Normally
286
             *         this should be an array of size {@link #getMaximumNumberOfArguments()}; however for functions
287
             *         that allow a variable number of arguments, the array can be smaller than this, with the last
288
             *         entry in the array providing the required type for all the remaining arguments.
289
             */
290
            public override XdmSequenceType[] ArgumentTypes
291
            {
292
                get
293
                {
294
                    return new XdmSequenceType[] {
295
                            new XdmSequenceType(XdmAtomicType.BuiltInAtomicType(QName.XS_STRING), '?')
296

    
297
                        };
298
                }
299
            }
300

    
301

    
302
            /**
303
             * Get the type of the result of the function
304
             * @param suppliedArgumentTypes the static types of the arguments to the function.
305
             *    This is provided so that a more precise result type can be returned in the common
306
             *    case where the type of the result depends on the type of the first argument. The value
307
             *    will be null if the function call has no arguments.
308
             * @return the return type of the function, as defined by its function signature
309
             */
310

    
311
            public override XdmSequenceType ResultType(XdmSequenceType[] ArgumentTypes)
312
            {
313
                return new XdmSequenceType(XdmAtomicType.BuiltInAtomicType(QName.XS_STRING), '?');
314
            }
315

    
316

    
317
            /**
318
             * Ask whether the result actually returned by the function should be checked against
319
             * the declared type.
320
             * @return true if the function implementation warrants that the value it returns will
321
             *         be an instance of the declared result type. The default value is false, in which case
322
             *         the result will be checked at run-time to ensure that it conforms to the declared type.
323
             *         If the value true is returned, but the function returns a value of the wrong type, the
324
             *         consequences are unpredictable.
325
             */
326

    
327
            public bool trustResultType()
328
            {
329
                return true;
330
            }
331

    
332
            /**
333
         * Create a call on this function. This method is called by the compiler when it identifies
334
             * a function call that calls this function.
335
             */
336

    
337
            public override ExtensionFunctionCall MakeFunctionCall()
338
            {
339
                return new InscopePrefixFunctionCall();
340
            }
341
        }
342

    
343
        public class InscopePrefixFunctionCall : ExtensionFunctionCall
344
        {
345

    
346
            private XmlResolver nsContext;
347
            private StaticContext context;
348

    
349
            /**
350
              * Supply static context information.
351
              * <p>This method is called during compilation to provide information about the static context in which
352
              * the function call appears. If the implementation of the function needs information from the static context,
353
              * then it should save it now, as it will not be available later at run-time.</p>
354
              * <p>The implementation also has the opportunity to examine the expressions that appear in the
355
              * arguments to the function call at this stage. These might already have been modified from the original
356
              * expressions as written by the user. The implementation should not modify any of these expressions.</p>
357
              * <p>The default implementation of this method does nothing.</p>
358
              * @param context   The static context in which the function call appears. The method must not modify
359
              *                  the static context.
360
              * @param locationId
361
              *@param arguments The XPath expressions supplied in the call to this function. The method must not
362
              *                  modify this array, or any of the expressions contained in the array. @throws net.sf.saxon.trans.XPathException
363
              *          if the implementation is able to detect a static error in the way the
364
              *          function is being called (for example it might require that the types of the arguments are
365
              *          consistent with each other).
366
              */
367

    
368
            public override void SupplyStaticContext(StaticContext context)
369
            {
370
                this.context = context;
371
            }
372

    
373
            /**
374
             * Copy local data from one copy of the function to another. This method must be implemented
375
             * in any subclass that maintains local data retained from the static context; the job of the
376
             * method is to copy this local data to the supplied destination function.
377
             * @param destination the function to which the local data must be copied. This will always
378
             *                    be an instance of the same function class as the source function.
379
             */
380

    
381
            public override void CopyLocalData(ExtensionFunctionCall destination)
382
            {
383
                ((InscopePrefixFunctionCall)destination).nsContext = nsContext;
384
            }
385

    
386
            public override IEnumerator<XdmItem> Call(IEnumerator<XdmItem>[] arguments, DynamicContext context)
387
            {
388
                String val = null;
389
                if (arguments[0].MoveNext())
390
                {
391
                    val = arguments[0].Current.ToString();
392
                }
393

    
394
                if (val == null)
395
                {
396
                    return  (IEnumerator<XdmAtomicValue>)Enumerable.Empty<XdmAtomicValue>().GetEnumerator();
397
                }
398
                String ns = this.context.GetNamespaceForPrefix(val.ToString());
399
                if (ns == null)
400
                {
401
                    return (IEnumerator<XdmAtomicValue>)Enumerable.Empty<XdmAtomicValue>().GetEnumerator();
402
                }
403
                XdmAtomicValue result = new XdmAtomicValue(ns);
404
                return result.GetEnumerator();
405
            }
406
        }
407

    
408
    }
409
}
(10-10/19)