Project

Profile

Help

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

he / latest9.1 / bn / csource / api / Saxon.Api / Xslt.cs @ e090dcb1

1
using System;
2
using System.IO;
3
using System.Xml;
4
using System.Collections;
5
using JStreamSource = javax.xml.transform.stream.StreamSource;
6
using JResult = javax.xml.transform.Result;
7
using JTransformerException = javax.xml.transform.TransformerException;
8
using JOutputURIResolver = net.sf.saxon.OutputURIResolver;
9
using JAugmentedSource = net.sf.saxon.AugmentedSource;
10
using JConfiguration = net.sf.saxon.Configuration;
11
using JLocationProvider = net.sf.saxon.@event.LocationProvider;
12
using JPipelineConfiguration = net.sf.saxon.@event.PipelineConfiguration;
13
using JSequenceWriter = net.sf.saxon.@event.SequenceWriter;
14
using JReceiverOptions = net.sf.saxon.@event.ReceiverOptions;
15
using JCompilerInfo = net.sf.saxon.trans.CompilerInfo;
16
using net.sf.saxon;
17
using JItem = net.sf.saxon.om.Item;
18
using JNodeInfo = net.sf.saxon.om.NodeInfo;
19
using JDocumentInfo = net.sf.saxon.om.DocumentInfo;
20
using JPullProvider = net.sf.saxon.pull.PullProvider;
21
using JPullSource = net.sf.saxon.pull.PullSource;
22
using JProcInstParser = net.sf.saxon.om.ProcInstParser;
23
using net.sf.saxon.dotnet;
24
using CharSequence = java.lang.CharSequence;
25

    
26

    
27
namespace Saxon.Api
28
{
29

    
30
    /// <summary>
31
    /// An <c>XsltCompiler</c> object allows XSLT 2.0 stylesheets to be compiled.
32
    /// The compiler holds information that represents the static context
33
    /// for the compilation.
34
    /// </summary>
35
    /// <remarks>
36
    /// <para>To construct an <c>XsltCompiler</c>, use the factory method
37
    /// <c>NewXsltCompiler</c> on the <c>Processor</c> object.</para>
38
    /// <para>An <c>XsltCompiler</c> may be used repeatedly to compile multiple
39
    /// queries. Any changes made to the <c>XsltCompiler</c> (that is, to the
40
    /// static context) do not affect queries that have already been compiled.
41
    /// An <c>XsltCompiler</c> may be used concurrently in multiple threads, but
42
    /// it should not then be modified once initialized.</para>
43
    /// </remarks>
44

    
45
    [Serializable]
46
    public class XsltCompiler
47
    {
48

    
49
        private TransformerFactoryImpl factory;
50
        private JConfiguration config;
51
        private JCompilerInfo info;
52
        private Uri baseUri;
53
        private IList errorList = null;
54

    
55
        // internal constructor: the public interface is a factory method
56
        // on the Processor object
57

    
58
        internal XsltCompiler(JConfiguration config)
59
        {
60
            this.factory = new TransformerFactoryImpl(config);
61
            this.config = config;
62
            this.info = new JCompilerInfo();
63
            info.setURIResolver(config.getURIResolver());
64
            info.setErrorListener(config.getErrorListener());
65
        }
66

    
67
        /// <summary>
68
        /// The base URI of the stylesheet, which forms part of the static context
69
        /// of the stylesheet. This is used for resolving any relative URIs appearing
70
        /// within the stylesheet, for example in <c>xsl:include</c> and <c>xsl:import</c>
71
        /// declarations, in schema locations defined to <c>xsl:import-schema</c>, 
72
        /// or as an argument to the <c>document()</c> or <c>doc()</c> function.
73
        /// </summary>
74
        /// <remarks>
75
        /// This base URI is used only if the input supplied to the <c>Compile</c> method
76
        /// does not provide its own base URI. It is therefore used on the version of the
77
        /// method that supplies input from a <c>Stream</c>. On the version that supplies
78
        /// input from an <c>XmlReader</c>, this base URI is used only if the <c>XmlReader</c>
79
        /// does not have its own base URI.
80
        /// </remarks>
81

    
82

    
83
        public Uri BaseUri
84
        {
85
            get { return baseUri; }
86
            set { baseUri = value; }
87
        }
88

    
89
        /// <summary>
90
        /// An XmlResolver, which will be used to resolve URI references while compiling
91
        /// a stylesheet
92
        /// </summary>
93
        /// <remarks>
94
        /// If no <c>XmlResolver</c> is set for the <c>XsltCompiler</c>, the <c>XmlResolver</c>
95
        /// is used that was set on the <c>Processor</c> at the time <c>NewXsltCompiler</c>
96
        /// was called.
97
        /// </remarks>
98

    
99
        public XmlResolver XmlResolver
100
        {
101
            get
102
            {
103
                return ((DotNetURIResolver)info.getURIResolver()).getXmlResolver();
104
            }
105
            set
106
            {
107
                info.setURIResolver(new DotNetURIResolver(value));
108
            }
109
        }
110

    
111
        /// <summary>
112
        /// List of errors. The caller should supply an empty list before calling Compile;
113
        /// the processor will then populate the list with error information obtained during
114
        /// the compilation. Each error will be included as an object of type StaticError.
115
        /// If no error list is supplied by the caller, error information will be written to
116
        /// the standard error stream.
117
        /// </summary>
118
        /// <remarks>
119
        /// By supplying a custom List with a user-written add() method, it is possible to
120
        /// intercept error conditions as they occur.
121
        /// </remarks>
122

    
123
        public IList ErrorList
124
        {
125
            set
126
            {
127
                errorList = value;
128
                info.setErrorListener(new ErrorGatherer(value));
129
            }
130
            get
131
            {
132
                return errorList;
133
            }
134
        }
135

    
136
        /// <summary>
137
        /// Compile a stylesheet supplied as a Stream.
138
        /// </summary>
139
        /// <example>
140
        /// <code>
141
        /// Stream source = new FileStream("input.xsl", FileMode.Open, FileAccess.Read);
142
        /// XsltExecutable q = compiler.Compile(source);
143
        /// source.Close();
144
        /// </code>
145
        /// </example>
146
        /// <param name="input">A stream containing the source text of the stylesheet</param>
147
        /// <returns>An <c>XsltExecutable</c> which represents the compiled stylesheet object.
148
        /// The XsltExecutable may be loaded as many times as required, in the same or a different
149
        /// thread. The <c>XsltExecutable</c> is not affected by any changes made to the <c>XsltCompiler</c>
150
        /// once it has been compiled.</returns>
151
        /// <remarks>
152
        /// <para>If the stylesheet contains any <c>xsl:include</c> or <c>xsl:import</c> declarations,
153
        /// then the <c>BaseURI</c> property must be set to allow these to be resolved.</para>
154
        /// <para>The stylesheet is contained in the part of the input stream between its current
155
        /// position and the end of the stream. It is the caller's responsibility to close the input 
156
        /// stream after use. If the compilation succeeded, then on exit the stream will be 
157
        /// exhausted; if compilation failed, the current position of the stream on exit is
158
        /// undefined.</para>
159
        /// </remarks>
160

    
161
        public XsltExecutable Compile(Stream input)
162
        {
163
            JStreamSource ss = new JStreamSource(new DotNetInputStream(input));
164
            if (baseUri != null)
165
            {
166
                ss.setSystemId(baseUri.ToString());
167
            }
168
            PreparedStylesheet pss = (PreparedStylesheet)factory.newTemplates(ss, info);
169
            return new XsltExecutable(pss);
170
        }
171

    
172
        /// <summary>
173
        /// Compile a stylesheet supplied as a TextReader.
174
        /// </summary>
175
        /// <example>
176
        /// <code>
177
        /// String ss = "<![CDATA[<xsl:stylesheet version='2.0'>....</xsl:stylesheet>]]>";
178
        /// TextReader source = new StringReader(ss);
179
        /// XsltExecutable q = compiler.Compile(source);
180
        /// source.Close();
181
        /// </code>
182
        /// </example>
183
        /// <param name="input">A <c>TextReader</c> containing the source text of the stylesheet</param>
184
        /// <returns>An <c>XsltExecutable</c> which represents the compiled stylesheet object.
185
        /// The XsltExecutable may be loaded as many times as required, in the same or a different
186
        /// thread. The <c>XsltExecutable</c> is not affected by any changes made to the <c>XsltCompiler</c>
187
        /// once it has been compiled.</returns>
188
        /// <remarks>
189
        /// <para>If the stylesheet contains any <c>xsl:include</c> or <c>xsl:import</c> declarations,
190
        /// then the <c>BaseURI</c> property must be set to allow these to be resolved.</para>
191
        /// <para>The stylesheet is contained in the part of the input stream between its current
192
        /// position and the end of the stream. It is the caller's responsibility to close the 
193
        /// <c>TextReader</c> after use. If the compilation succeeded, then on exit the stream will be 
194
        /// exhausted; if compilation failed, the current position of the stream on exit is
195
        /// undefined.</para>
196
        /// </remarks>
197

    
198
        public XsltExecutable Compile(TextReader input)
199
        {
200
            JStreamSource ss = new JStreamSource(new DotNetReader(input));
201
            if (baseUri != null)
202
            {
203
                ss.setSystemId(baseUri.ToString());
204
            }
205
            PreparedStylesheet pss = (PreparedStylesheet)factory.newTemplates(ss, info);
206
            return new XsltExecutable(pss);
207
        }
208

    
209
        /// <summary>
210
        /// Compile a stylesheet, retrieving the source using a URI.
211
        /// </summary>
212
        /// <remarks>
213
        /// The document located via the URI is parsed using the <c>System.Xml</c> parser. This
214
        /// URI is used as the base URI of the stylesheet: the <c>BaseUri</c> property of the
215
        /// <c>Compiler</c> is ignored.
216
        /// </remarks>
217
        /// <param name="uri">The URI identifying the location where the stylesheet document can be
218
        /// found</param>
219
        /// <returns>An <c>XsltExecutable</c> which represents the compiled stylesheet object.
220
        /// The XsltExecutable may be run as many times as required, in the same or a different
221
        /// thread. The <c>XsltExecutable</c> is not affected by any changes made to the <c>XsltCompiler</c>
222
        /// once it has been compiled.</returns>
223

    
224
        public XsltExecutable Compile(Uri uri)
225
        {
226
            Object obj = XmlResolver.GetEntity(uri, "application/xml", Type.GetType("System.IO.Stream"));
227
            if (obj is Stream)
228
            {
229
                try
230
                {
231
                    XmlReader parser = new XmlTextReader(uri.ToString(), (Stream)obj);
232
                    ((XmlTextReader)parser).Normalization = true;
233
                    ((XmlTextReader)parser).WhitespaceHandling = WhitespaceHandling.All;
234
                    ((XmlTextReader)parser).XmlResolver = XmlResolver;
235
                    // Always need a validating parser, because that's the only way to get entity references expanded
236
                    parser = new XmlValidatingReader(parser);
237
                    ((XmlValidatingReader)parser).ValidationType = ValidationType.None;
238
                    JPullSource source = new JPullSource(new DotNetPullProvider(parser));
239
                    PreparedStylesheet pss = (PreparedStylesheet)factory.newTemplates(source, info);
240
                    return new XsltExecutable(pss);
241
                }
242
                finally
243
                {
244
                    ((Stream)obj).Close();
245
                }
246
            }
247
            else
248
            {
249
                throw new ArgumentException("Invalid type of result from XmlResolver.GetEntity: " + obj);
250
            }
251
        }
252

    
253
        /// <summary>
254
        /// Compile a stylesheet, delivered using an XmlReader.
255
        /// </summary>
256
        /// <remarks>
257
        /// The <c>XmlReader</c> is responsible for parsing the document; this method builds a tree
258
        /// representation of the document (in an internal Saxon format) and compiles it.
259
        /// If the <c>XmlReader</c> is an <c>XmlTextReader</c>, Saxon will set its <c>Normalization</c>
260
        /// property to true, and will wrap it in a (non-validating) <c>XmlValidatingReader</c> to ensure
261
        /// that entity references are expanded.
262
        /// </remarks>
263
        /// <remarks>
264
        /// If the <c>XmlReader</c> has a <c>BaseUri</c> property, then that property determines
265
        /// the base URI of the stylesheet module, which is used when resolving any <c>xsl:include</c>
266
        /// or <c>xsl:import</c> declarations. If the <c>XmlReader</c> has no <c>BaseUri</c>
267
        /// property, then the <c>BaseUri</c> property of the <c>Compiler</c> is used instead.
268
        /// An <c>ArgumentNullException</c> is thrown if this property has not been supplied.
269
        /// </remarks>
270
        /// <param name="reader">The XmlReader (that is, the XML parser) used to supply the document containing
271
        /// the principal stylesheet module.</param>
272
        /// <returns>An <c>XsltExecutable</c> which represents the compiled stylesheet object.
273
        /// The XsltExecutable may be run as many times as required, in the same or a different
274
        /// thread. The <c>XsltExecutable</c> is not affected by any changes made to the <c>XsltCompiler</c>
275
        /// once it has been compiled.</returns>
276

    
277

    
278
        public XsltExecutable Compile(XmlReader reader)
279
        {
280
            if (reader is XmlTextReader)
281
            {
282
                ((XmlTextReader)reader).Normalization = true;
283
                reader = new XmlValidatingReader(reader);
284
                ((XmlValidatingReader)reader).ValidationType = ValidationType.None;
285
            }
286
            DotNetPullProvider pp = new DotNetPullProvider(reader);
287
            JPipelineConfiguration pipe = config.makePipelineConfiguration();
288
            pipe.setLocationProvider(pp);
289
            pp.setPipelineConfiguration(pipe);
290
            // pp = new PullTracer(pp);  /* diagnostics */
291
            JPullSource source = new JPullSource(pp);
292
            String baseu = reader.BaseURI;
293
            if (baseu == null || baseu == String.Empty)
294
            {
295
                // if no baseURI is supplied by the XmlReader, use the one supplied to this Compiler
296
                if (baseUri == null)
297
                {
298
                    throw new ArgumentNullException("BaseUri");
299
                }
300
                baseu = baseUri.ToString();
301
                pp.setBaseURI(baseu);
302
            }
303
            source.setSystemId(baseu);
304
            PreparedStylesheet pss = (PreparedStylesheet)factory.newTemplates(source, info);
305
            return new XsltExecutable(pss);
306
        }
307

    
308
        /// <summary>
309
        /// Compile a stylesheet, located at an XdmNode. This may be a document node whose
310
        /// child is an <c>xsl:stylesheet</c> or <c>xsl:transform</c> element, or it may be
311
        /// the <c>xsl:stylesheet</c> or <c>xsl:transform</c> element itself.
312
        /// </summary>
313
        /// <param name="node">The document node or the outermost element node of the document
314
        /// containing the principal stylesheet module.</param>
315
        /// <returns>An <c>XsltExecutable</c> which represents the compiled stylesheet object.
316
        /// The XsltExecutable may be run as many times as required, in the same or a different
317
        /// thread. The <c>XsltExecutable</c> is not affected by any changes made to the <c>XsltCompiler</c>
318
        /// once it has been compiled.</returns>
319

    
320
        public XsltExecutable Compile(XdmNode node)
321
        {
322
            PreparedStylesheet pss = (PreparedStylesheet)factory.newTemplates((JNodeInfo)node.value, info);
323
            return new XsltExecutable(pss);
324
        }
325

    
326
        /// <summary>Locate and compile a stylesheet identified by an &lt;?xml-stylesheet?&gt;
327
        /// processing instruction within a source document.
328
        /// </summary>
329
        /// <param name="source">The document node of the source document containing the
330
        /// xml-stylesheet processing instruction.</param>
331
        /// <returns>An <c>XsltExecutable</c> which represents the compiled stylesheet object.</returns>
332
        /// <remarks>There are some limitations in the current implementation. The media type
333
        /// is ignored, as are the other parameters of the xml-stylesheet instruction. The
334
        /// href attribute must either reference an embedded stylesheet within the same
335
        /// document or a non-embedded external stylesheet.</remarks>
336

    
337
        public XsltExecutable CompileAssociatedStylesheet(XdmNode source)
338
        {
339
            // TODO: lift the restrictions
340
            if (source == null || source.NodeKind != XmlNodeType.Document)
341
            {
342
                throw new ArgumentException("Source must be a document node");
343
            }
344
            IEnumerator kids = source.EnumerateAxis(XdmAxis.Child);
345
            QName xmlstyle = new QName("", "xml-stylesheet");
346
            while (kids.MoveNext())
347
            {
348
                XdmNode n = (XdmNode)kids.Current;
349
                if (n.NodeKind == XmlNodeType.ProcessingInstruction &&
350
                    n.NodeName.Equals(xmlstyle))
351
                {
352
                    // TODO: check the media type
353
                    String href = JProcInstParser.getPseudoAttribute(n.StringValue, "href");
354
                    if (href == null)
355
                    {
356
                        throw new DynamicError("xml-stylesheet processing instruction has no href attribute");
357
                    }
358
                    String fragment = null;
359
                    int hash = href.LastIndexOf('#');
360
                    if (hash == 0)
361
                    {
362
                        if (href.Length == 1)
363
                        {
364
                            throw new DynamicError("Relative URI of '#' is invalid");
365
                        }
366
                        fragment = href.Substring(1);
367
                        JNodeInfo target = ((JDocumentInfo)source.value).selectID(fragment);
368
                        XdmNode targetWrapper = null;
369
                        if (target == null)
370
                        {
371
                            // There's a problem here because the Microsoft XML parser doesn't
372
                            // report id values, so selectID() will never work. We work around that
373
                            // by looking for an attribute named "id" appearing on an xsl:stylesheet
374
                            // or xsl:transform element
375
                            QName qid = new QName("", "id");
376
                            IEnumerator en = source.EnumerateAxis(XdmAxis.Descendant);
377
                            while (en.MoveNext())
378
                            {
379
                                XdmNode x = (XdmNode)en.Current;
380
                                if (x.NodeKind == XmlNodeType.Element &&
381
                                        x.NodeName.Uri == "http://www.w3.org/1999/XSL/Transform" &&
382
                                        (x.NodeName.LocalName == "stylesheet" || x.NodeName.LocalName == "transform" &&
383
                                        x.GetAttributeValue(qid) == fragment))
384
                                {
385
                                    targetWrapper = x;
386
                                }
387
                            }
388
                        }
389
                        else
390
                        {
391
                            targetWrapper = (XdmNode)XdmValue.Wrap(target);
392
                        }
393
                        if (targetWrapper == null)
394
                        {
395
                            throw new DynamicError("No element with id='" + fragment + "' found");
396
                        }
397
                        return Compile(targetWrapper);
398
                    }
399
                    else if (hash > 0)
400
                    {
401
                        throw new NotImplementedException("href cannot identify an embedded stylesheet in a different document");
402
                    }
403
                    else
404
                    {
405
                        Uri uri = new Uri(n.BaseUri, href);
406
                        return Compile(uri);
407
                    }
408
                }
409
            }
410
            throw new DynamicError("xml-stylesheet processing instruction not found");
411
        }
412
    }
413

    
414
    /// <summary>
415
    /// An <c>XsltExecutable</c> represents the compiled form of a stylesheet. To execute the stylesheet,
416
    /// it must first be loaded to form an <c>XsltTransformer</c>.
417
    /// </summary>
418
    /// <remarks>
419
    /// <para>An <c>XsltExecutable</c> is immutable, and therefore thread-safe. It is simplest to
420
    /// load a new <c>XsltEvaluator</c> each time the stylesheet is to be run. However, the 
421
    /// <c>XsltEvaluator</c> is serially reusable within a single thread.</para>
422
    /// <para>An <c>XsltExecutable</c> is created by using one of the <c>Compile</c>
423
    /// methods on the <c>XsltCompiler</c> class.</para>
424
    /// </remarks>    
425

    
426
    [Serializable]
427
    public class XsltExecutable
428
    {
429

    
430
        private PreparedStylesheet pss;
431

    
432
        // internal constructor
433

    
434
        internal XsltExecutable(PreparedStylesheet pss)
435
        {
436
            this.pss = pss;
437
        }
438

    
439
        /// <summary>
440
        /// Load the stylesheet to prepare it for execution.
441
        /// </summary>
442
        /// <returns>
443
        /// An <c>XsltTransformer</c>. The returned <c>XsltTransformer</c> can be used to
444
        /// set up the dynamic context for stylesheet evaluation, and to run the stylesheet.
445
        /// </returns>
446

    
447
        public XsltTransformer Load()
448
        {
449
            Controller c = (Controller)pss.newTransformer();
450
            return new XsltTransformer(c);
451
        }
452

    
453
    }
454

    
455
    /// <summary inherits="IEnumerable">
456
    /// An <c>XsltTransformer</c> represents a compiled and loaded stylesheet ready for execution.
457
    /// The <c>XsltTransformer</c> holds details of the dynamic evaluation context for the stylesheet.
458
    /// </summary>
459
    /// <remarks>
460
    /// <para>An <c>XsltTransformer</c> should not be used concurrently in multiple threads. It is safe,
461
    /// however, to reuse the object within a single thread to run the same stylesheet several times.
462
    /// Running the stylesheet does not change the context that has been established.</para>
463
    /// <para>An <c>XsltTransformer</c> is always constructed by running the <c>Load</c> method of
464
    /// an <c>XsltExecutable</c>.</para>
465
    /// </remarks>     
466

    
467
    [Serializable]
468
    public class XsltTransformer
469
    {
470

    
471
        private Controller controller;
472
        private JNodeInfo initialContextNode;
473
        private IResultDocumentHandler resultDocumentHandler;
474
        private IMessageListener messageListener;
475
        private Stream traceFunctionDestination;
476
        
477

    
478
        // internal constructor
479

    
480
        internal XsltTransformer(Controller controller)
481
        {
482
            this.controller = controller;
483
        }
484

    
485
        /// <summary>
486
        /// The initial context item for the stylesheet.
487
        /// </summary>
488
        /// <remarks> This may be either a node or an atomic
489
        /// value. Most commonly it will be a document node, which might be constructed
490
        /// using the <c>Build</c> method of the <c>DocumentBuilder</c> object.
491
        /// </remarks>
492

    
493
        public XdmNode InitialContextNode
494
        {
495
            get { return (initialContextNode == null ? null : (XdmNode)XdmValue.Wrap(initialContextNode)); }
496
            set { initialContextNode = (value == null ? null : (JNodeInfo)value.Unwrap()); }
497
        }
498

    
499
        /// <summary>
500
        /// The initial mode for the stylesheet. This is either a QName, for a 
501
        /// named mode, or null, for the unnamed (default) mode.
502
        /// </summary>
503

    
504
        public QName InitialMode
505
        {
506
            get
507
            {
508
                String mode = controller.getInitialMode();
509
                if (mode == null)
510
                {
511
                    return null;
512
                }
513
                return QName.FromClarkName(mode);
514
            }
515
            set
516
            {
517
                controller.setInitialMode(value.ClarkName);
518
            }
519
        }
520

    
521
        /// <summary>
522
        /// The initial template for the stylesheet. This is either a QName, for a 
523
        /// named template, or null, if no initial template has been set.
524
        /// </summary>
525
        /// <exception cref="DynamicError">Setting this property to the name of a template
526
        /// that does not exist in the stylesheet throws a DynamicError with error 
527
        /// code XTDE0040. Setting it to the name of a template that has template
528
        /// parameters throws a DynamicError with error code XTDE0060.</exception>
529

    
530
        public QName InitialTemplate
531
        {
532
            get
533
            {
534
                String name = controller.getInitialTemplate();
535
                if (name == null)
536
                {
537
                    return null;
538
                }
539
                return QName.FromClarkName(name);
540
            }
541
            set
542
            {
543
                try
544
                {
545
                    controller.setInitialTemplate(value.ClarkName);
546
                }
547
                catch (javax.xml.transform.TransformerException err)
548
                {
549
                    throw new DynamicError(err);
550
                }
551
            }
552
        }
553

    
554
        /// <summary>
555
        /// The base output URI, which acts as the base URI for resolving the <c>href</c>
556
        /// attribute of <c>xsl:result-document</c>.
557
        /// </summary>
558

    
559
        public Uri BaseOutputUri
560
        {
561
            get
562
            {
563
                return new Uri(controller.getBaseOutputURI());
564
            }
565
            set
566
            {
567
                controller.setBaseOutputURI(value.ToString());
568
            }
569
        }
570

    
571
        public RecoveryPolicy RecoveryPolicy
572
        {
573
            get
574
            {
575
                switch (controller.getRecoveryPolicy())
576
                {
577
                    case Configuration.RECOVER_SILENTLY:
578
                        return RecoveryPolicy.RecoverSilently;
579
                    case Configuration.RECOVER_WITH_WARNINGS:
580
                        return RecoveryPolicy.RecoverWithWarnings;
581
                    default: return RecoveryPolicy.DoNotRecover;
582
                }
583
            }
584
            set
585
            {
586
                controller.setRecoveryPolicy(
587
                    value == RecoveryPolicy.RecoverSilently ? Configuration.RECOVER_SILENTLY :
588
                    value == RecoveryPolicy.RecoverWithWarnings ? Configuration.RECOVER_WITH_WARNINGS :
589
                    Configuration.DO_NOT_RECOVER);
590
            }
591
        }
592

    
593

    
594
        /// <summary>
595
        /// The <c>XmlResolver</c> to be used at run-time to resolve and dereference URIs
596
        /// supplied to the <c>doc()</c> and <c>document()</c> functions.
597
        /// </summary>
598

    
599
        public XmlResolver InputXmlResolver
600
        {
601
            get
602
            {
603
                return ((DotNetURIResolver)controller.getURIResolver()).getXmlResolver();
604
            }
605
            set
606
            {
607
                controller.setURIResolver(new DotNetURIResolver(value));
608
            }
609
        }
610

    
611
        /// <summary>
612
        /// The <c>IResultDocumentHandler</c> to be used at run-time to process the output
613
        /// produced by any <c>xsl:result-document</c> instruction with an <c>href</c>
614
        /// attribute.
615
        /// </summary>
616
        /// <remarks>
617
        /// In the absence of a user-supplied result document handler, the <c>href</c>
618
        /// attribute of the <c>xsl:result-document</c> instruction must be a valid relative
619
        /// URI, which is resolved against the value of the <c>BaseOutputUri</c> property,
620
        /// and the resulting absolute URI must identify a writable resource (typically
621
        /// a file in filestore, using the <c>file:</c> URI scheme).
622
        /// </remarks>
623

    
624
        public IResultDocumentHandler ResultDocumentHandler
625
        {
626
            get
627
            {
628
                return resultDocumentHandler;
629
            }
630
            set
631
            {
632
                resultDocumentHandler = value;
633
                controller.setOutputURIResolver(new ResultDocumentHandlerWrapper(value));
634
            }
635
        }
636

    
637
        /// <summary>
638
        /// Listener for messages output using &lt;xsl:message&gt;. 
639
        /// <para>The caller may supply a message listener before calling <c>Run</c>;
640
        /// the processor will then invoke the listener once for each message generated during
641
        /// the transformation. Each message will be output as an object of type <c>XdmNode</c>
642
        /// representing a document node.</para>
643
        /// <para>If no message listener is supplied by the caller, message information will be written to
644
        /// the standard error stream.</para>
645
        /// </summary>
646
        /// <remarks>
647
        /// <para>Each message is presented as an XML document node. Calling <c>ToString()</c>
648
        /// on the message object will usually generate an acceptable representation of the
649
        /// message.</para>
650
        /// <para>When the &lt;xsl:message&gt; instruction specifies <c>terminate="yes"</c>,
651
        /// the message is first notified using this interface, and then an exception is thrown
652
        /// which terminates the transformation.</para>
653
        /// </remarks>
654

    
655
        public IMessageListener MessageListener
656
        {
657
            set
658
            {
659
                messageListener = value;
660
                controller.setMessageEmitter(new MessageListenerProxy(value));
661
            }
662
            get
663
            {
664
                return messageListener;
665
            }
666
        }
667

    
668
        /// <summary>
669
        /// Destination for output of messages using &lt;trace()&gt;. 
670
        /// <para>If no message listener is supplied by the caller, message information will be written to
671
        /// the standard error stream.</para>
672
        /// </summary>
673
        /// <remarks>
674
        /// <para>The supplied destination is ignored if a <c>TraceListener</c> is in use.</para>
675
        /// </remarks>
676

    
677
        public Stream TraceFunctionDestination
678
        {
679
            set
680
            {
681
                traceFunctionDestination = value;
682
                controller.setTraceFunctionDestination(
683
                    new java.io.PrintStream(new DotNetOutputStream(value)));
684
            }
685
            get
686
            {
687
                return traceFunctionDestination;
688
            }
689
        }
690

    
691

    
692

    
693
        /// <summary>
694
        /// Set the value of a stylesheet parameter.
695
        /// </summary>
696
        /// <param name="name">The name of the parameter, expressed
697
        /// as a QName. If a parameter of this name has been declared in the
698
        /// stylesheet, the given value will be assigned to the variable. If the
699
        /// variable has not been declared, calling this method has no effect (it is
700
        /// not an error).</param>
701
        /// <param name="value">The value to be given to the parameter.
702
        /// If the parameter declaration defines a required type for the variable, then
703
        /// this value will be converted in the same way as arguments to function calls
704
        /// (for example, numeric promotion is applied).</param>
705

    
706
        public void SetParameter(QName name, XdmValue value)
707
        {
708
            controller.setParameter(name.ClarkName, value.Unwrap());
709
        }
710

    
711
        /// <summary>
712
        /// Run the transformation, sending the result to a specified destination.
713
        /// </summary>
714
        /// <param name="destination">
715
        /// The destination for the results of the stylesheet. The class <c>XmlDestination</c>
716
        /// is an abstraction that allows a number of different kinds of destination
717
        /// to be specified.
718
        /// </param>
719
        /// <exception cref="DynamicError">Throws a DynamicError if the transformation
720
        /// fails.</exception>
721

    
722
        public void Run(XmlDestination destination)
723
        {
724
            // TODO: This isn't an ideal way of running the stylesheet if it invokes xsl:strip-space: it's better to do the
725
            // whitespace stripping while building the tree.
726
            try
727
            {
728
                controller.setOutputProperties(destination.GetOutputProperties());
729
                if (initialContextNode != null)
730
                {
731
                    JDocumentInfo doc = initialContextNode.getDocumentRoot();
732
                    controller.registerDocument(doc, doc.getBaseURI());
733
                }
734
                controller.transform(initialContextNode, destination.GetResult());
735
                destination.Close();
736
            }
737
            catch (javax.xml.transform.TransformerException err)
738
            {
739
                throw new DynamicError(err);
740
            }
741
        }
742

    
743
        /// <summary>
744
        /// Escape hatch to the underlying Java implementation
745
        /// </summary>
746

    
747
        public Controller Implementation
748
        {
749
            get { return controller; }
750
        }
751

    
752

    
753
    }
754

    
755
    /// <summary>
756
    /// RecoveryPolicy is an enumeration of the different actions that can be taken when a "recoverable error" occurs
757
    /// </summary>
758

    
759
    public enum RecoveryPolicy
760
    {
761
        /// <summary>
762
        /// Ignore the error, take the recovery action, do not produce any message
763
        /// </summary>
764
        RecoverSilently,
765

    
766
        /// <summary>
767
        /// Take the recovery action after outputting a warning message
768
        /// </summary>
769
        RecoverWithWarnings,
770

    
771
        /// <summary>
772
        /// Treat the error as fatal
773
        /// </summary>
774
        DoNotRecover
775

    
776
    }
777

    
778

    
779

    
780
    ///<summary>An <c>IResultDocumentHandler</c> can be nominated to handle output
781
    /// produced by the <c>xsl:result-document</c> instruction in an XSLT stylesheet.
782
    ///</summary>
783
    ///<remarks>
784
    ///<para>This interface affects any <c>xsl:result-document</c> instruction
785
    /// executed by the stylesheet, provided that it has an <c>href</c> attribute.</para> 
786
    ///<para>If no <c>IResultDocumentHandler</c> is nominated (in the
787
    /// <c>IResultDocumentHandler</c> property of the <c>XsltTransformer</c>, the output
788
    /// of <code>xsl:result-document</code> is serialized, and is written to the file
789
    /// or other resource identified by the URI in the <c>href</c> attribute, resolved
790
    /// (if it is relative> against the URI supplied in the <c>BaseOutputUri</c> property
791
    /// of the <c>XsltTransformer</c>.</para>
792
    ///<para>If an <c>IResultDocumentHandler</c> is nominated, however, its
793
    /// <c>HandleResultDocument</c> method will be called whenever an <c>xsl:result-document</c>
794
    /// instruction with an <c>href</c> attribute is evaluated, and the generated result tree
795
    /// will be passed to the <c>XmlDestination</c> returned by that method.</para> 
796
    ///</remarks>
797

    
798
    public interface IResultDocumentHandler
799
    {
800

    
801
        /// <summary> Handle output produced by the <c>xsl:result-document</c>
802
        /// instruction in an XSLT stylesheet. This method is called by the XSLT processor
803
        /// when an <c>xsl:result-document</c> with an <c>href</c> attribute is evaluated.
804
        /// </summary>
805
        /// <param name="href">An absolute or relative URI. This will be the effective value of the 
806
        /// <c>href</c> attribute of the <c>xsl:result-document</c> in the stylesheet.</param>
807
        /// <param name="baseUri">The base URI that should be used for resolving the value of
808
        /// <c>href</c> if it is relative. This will always be the value of the <c>BaseOutputUri</c>
809
        /// property of the <c>XsltTransformer</c>.</param>
810
        /// <returns>An <c>XmlDestination</c> to handle the result tree produced by the
811
        /// <c>xsl:result-document</c> instruction. The <c>Close</c> method of the returned
812
        /// <c>XmlDestination</c> will be called when the output is complete.</returns>
813
        /// <remarks>
814
        /// <para>The XSLT processor will ensure that the stylesheet cannot create
815
        /// two distinct result documents which are sent to the same URI. It is the responsibility
816
        /// of the <c>IResultDocumentHandler</c> to ensure that two distinct result documents are
817
        /// not set to the same <c>XmlDestination</c>. Failure to observe this rule can result
818
        /// in output streams being incorrectly closed.
819
        /// </para>
820
        /// <para>Note that more than one result document can be open at the same time,
821
        /// and that the order of opening, writing, and closing result documents chosen
822
        /// by the processor does not necessarily bear any direct resemblance to the way
823
        /// that the XSLT source code is written.</para></remarks>
824

    
825
        XmlDestination HandleResultDocument(string href, Uri baseUri);
826

    
827
    }
828

    
829
    internal class ResultDocumentHandlerWrapper : JOutputURIResolver
830
    {
831

    
832
        private IResultDocumentHandler handler;
833
        private ArrayList resultList = new ArrayList();
834
        private ArrayList destinationList = new ArrayList();
835

    
836
        public ResultDocumentHandlerWrapper(IResultDocumentHandler handler)
837
        {
838
            this.handler = handler;
839
        }
840

    
841
        public JResult resolve(String href, String baseString)
842
        {
843
            Uri baseUri;
844
            try
845
            {
846
                baseUri = new Uri(baseString);
847
            }
848
            catch (System.UriFormatException err)
849
            {
850
                throw new JTransformerException("Invalid base output URI " + baseString, err);
851
            }
852
            XmlDestination destination = handler.HandleResultDocument(href, baseUri);
853
            JResult result = destination.GetResult();
854
            resultList.Add(result);
855
            destinationList.Add(destination);
856
            return result;
857
        }
858

    
859
        public void close(JResult result)
860
        {
861
            for (int i = 0; i < resultList.Count; i++)
862
            {
863
                if (Object.ReferenceEquals(resultList[i], result))
864
                {
865
                    ((XmlDestination)destinationList[i]).Close();
866
                    resultList.RemoveAt(i);
867
                    destinationList.RemoveAt(i);
868
                    return;
869
                }
870
            }
871
        }
872
    }
873

    
874
    ///<summary>An <c>IMessageListener</c> can be nominated to handle output
875
    /// produced by the <c>xsl:message</c> instruction in an XSLT stylesheet.
876
    ///</summary>
877
    ///<remarks>
878
    ///<para>This interface affects any <c>xsl:message</c> instruction
879
    /// executed by the stylesheet.</para> 
880
    ///<para>If no <c>IMessageListener</c> is nominated (in the
881
    /// <c>MessageListener</c> property of the <c>XsltTransformer</c>), the output
882
    /// of <code>xsl:message</code> is serialized, and is written to standard error
883
    /// output stream.</para>
884
    ///<para>If an <c>IMessageListener</c> is nominated, however, its
885
    /// <c>Message</c> method will be called whenever an <c>xsl:message</c>
886
    /// instruction is evaluated.</para> 
887
    ///</remarks>
888

    
889

    
890
    public interface IMessageListener
891
    {
892

    
893
        ///<summary>Handle the output of an <c>xsl:message</c> instruction
894
        ///in the stylesheet
895
        ///</summary>
896
        ///
897

    
898
        void Message(XdmNode content, bool terminate, IXmlLocation location);
899

    
900
    }
901

    
902
    /// <summary>
903
    /// An <c>IXmlLocation</c> represents the location of a node within an XML document.
904
    /// It is in two parts: the base URI (or system ID) of the external entity (which will usually
905
    /// be the XML document entity itself), and the line number of a node relative
906
    /// to the base URI of the containing external entity.
907
    /// </summary>
908
    /// 
909

    
910
    public interface IXmlLocation
911
    {
912

    
913
        /// <summary>
914
        /// The base URI (system ID) of an external entity within an XML document.
915
        /// Set to null if the base URI is not known (for example, for an XML document
916
        /// created programmatically where no base URI has been set up).
917
        /// </summary>
918

    
919
        Uri BaseUri { get; set; }
920

    
921
        /// <summary>
922
        /// The line number of a node relative to the start of the external entity.
923
        /// The value -1 indicates that the line number is not known or not applicable.
924
        /// </summary>
925

    
926
        int LineNumber { get; set; }
927
    }
928

    
929
    internal class XmlLocation : IXmlLocation
930
    {
931
        private Uri baseUri;
932
        private int lineNumber;
933
        public Uri BaseUri
934
        {
935
            get { return baseUri; }
936
            set { baseUri = value; }
937
        }
938
        public int LineNumber
939
        {
940
            get { return lineNumber; }
941
            set { lineNumber = value; }
942
        }
943
    }
944

    
945

    
946
    [Serializable]
947
    internal class MessageListenerProxy : JSequenceWriter
948
    {
949

    
950
        public IMessageListener listener;
951
        public bool terminate;
952
        public int locationId;
953

    
954
        public MessageListenerProxy(IMessageListener ml)
955
        {
956
            listener = ml;
957
        }
958

    
959
        public override void startDocument(int properties)
960
        {
961
            terminate = (properties & JReceiverOptions.TERMINATE) != 0;
962
            locationId = -1;
963
            base.startDocument(properties);
964
        }
965

    
966
        public override void startElement(int nameCode, int typeCode, int locationId, int properties)
967
        {
968
            if (this.locationId == -1)
969
            {
970
                this.locationId = locationId;
971
            }
972
            base.startElement(nameCode, typeCode, locationId, properties);
973
        }
974

    
975
        public override void characters(CharSequence s, int locationId, int properties)
976
        {
977
            if (this.locationId == -1)
978
            {
979
                this.locationId = locationId;
980
            }
981
            base.characters(s, locationId, properties);
982
        }
983

    
984
        public override void append(JItem item, int locationId, int copyNamespaces)
985
        {
986
            if (this.locationId == -1)
987
            {
988
                this.locationId = locationId;
989
            }
990
            base.append(item, locationId, copyNamespaces);
991
        }
992

    
993
        public override void write(JItem item)
994
        {
995
            XmlLocation loc = new XmlLocation();
996
            if (locationId != -1)
997
            {
998
                JLocationProvider provider = getPipelineConfiguration().getLocationProvider();
999
                loc.BaseUri = new Uri(provider.getSystemId(locationId));
1000
                loc.LineNumber = provider.getLineNumber(locationId);
1001
            }
1002
            listener.Message((XdmNode)XdmItem.Wrap(item), terminate, loc);
1003
        }
1004
    }
1005

    
1006

    
1007
}
1008

    
1009
//
1010
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
1011
// you may not use this file except in compliance with the License. You may obtain a copy of the
1012
// License at http://www.mozilla.org/MPL/
1013
//
1014
// Software distributed under the License is distributed on an "AS IS" basis,
1015
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
1016
// See the License for the specific language governing rights and limitations under the License.
1017
//
1018
// The Original Code is: all this file.
1019
//
1020
// The Initial Developer of the Original Code is Michael H. Kay.
1021
//
1022
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
1023
//
1024
// Contributor(s): none.
1025
//
(8-8/8)