Project

Profile

Help

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

he / latest9.5 / hen / csource / api / Saxon.Api / Xslt.cs @ f0ec7777

1
using System;
2
using System.IO;
3
using System.Xml;
4
using System.Collections;
5
using System.Globalization;
6
using JStreamSource = javax.xml.transform.stream.StreamSource;
7
using JResult = javax.xml.transform.Result;
8
using JTransformerException = javax.xml.transform.TransformerException;
9
using JOutputURIResolver = net.sf.saxon.lib.OutputURIResolver;
10
using JAugmentedSource = net.sf.saxon.lib.AugmentedSource;
11
using JConfiguration = net.sf.saxon.Configuration;
12
using JLocationProvider = net.sf.saxon.@event.LocationProvider;
13
using JPipelineConfiguration = net.sf.saxon.@event.PipelineConfiguration;
14
using JStructuredQName = net.sf.saxon.om.StructuredQName;
15
using JProperties = java.util.Properties;
16
using JSequenceWriter = net.sf.saxon.@event.SequenceWriter;
17
using JReceiver = net.sf.saxon.@event.Receiver;
18
using JReceiverOptions = net.sf.saxon.@event.ReceiverOptions;
19
using JCompilerInfo = net.sf.saxon.trans.CompilerInfo;
20
using JExpressionPresenter = net.sf.saxon.trace.ExpressionPresenter;
21
using JValidation = net.sf.saxon.lib.Validation;
22
using JDocumentURI = net.sf.saxon.om.DocumentURI;
23
using JDecimalValue = net.sf.saxon.value.DecimalValue;
24
using JIndependentContext = net.sf.saxon.sxpath.IndependentContext;
25
using net.sf.saxon;
26
using JItem = net.sf.saxon.om.Item;
27
using JNodeInfo = net.sf.saxon.om.NodeInfo;
28
using JNodeName = net.sf.saxon.om.NodeName;
29
using JSchemaType = net.sf.saxon.type.SchemaType;
30
using JDocumentInfo = net.sf.saxon.om.DocumentInfo;
31
using JPullProvider = net.sf.saxon.pull.PullProvider;
32
using JPullSource = net.sf.saxon.pull.PullSource;
33
using JProcInstParser = net.sf.saxon.tree.util.ProcInstParser;
34
using net.sf.saxon.dotnet;
35
using CharSequence = java.lang.CharSequence;
36
using JBoolean = java.lang.Boolean;
37

    
38

    
39
namespace Saxon.Api
40
{
41

    
42
    /// <summary>
43
    /// An <c>XsltCompiler</c> object allows XSLT 2.0 stylesheets to be compiled.
44
    /// The compiler holds information that represents the static context
45
    /// for the compilation.
46
    /// </summary>
47
    /// <remarks>
48
    /// <para>To construct an <c>XsltCompiler</c>, use the factory method
49
    /// <c>NewXsltCompiler</c> on the <c>Processor</c> object.</para>
50
    /// <para>An <c>XsltCompiler</c> may be used repeatedly to compile multiple
51
    /// queries. Any changes made to the <c>XsltCompiler</c> (that is, to the
52
    /// static context) do not affect queries that have already been compiled.
53
    /// An <c>XsltCompiler</c> may be used concurrently in multiple threads, but
54
    /// it should not then be modified once initialized.</para>
55
    /// </remarks>
56

    
57
    [Serializable]
58
    public class XsltCompiler
59
    {
60

    
61
        private TransformerFactoryImpl factory;
62
        private Processor processor;
63
        private JConfiguration config;
64
        private JCompilerInfo info;
65
        private JIndependentContext env;
66
        private Uri baseUri;
67
        private IList errorList = null;
68
        private Hashtable variableList = new Hashtable();
69

    
70
        // internal constructor: the public interface is a factory method
71
        // on the Processor object
72

    
73
        internal XsltCompiler(Processor processor)
74
        {
75
            this.processor = processor;
76
            this.config = processor.config;
77
            this.factory = new TransformerFactoryImpl(config);
78
            this.info = new JCompilerInfo(config.getDefaultXsltCompilerInfo());
79
            info.setURIResolver(config.getURIResolver());
80
            info.setErrorListener(config.getErrorListener());
81
            this.env = new JIndependentContext(config);
82
        }
83

    
84
        /// <summary>
85
        /// The base URI of the stylesheet, which forms part of the static context
86
        /// of the stylesheet. This is used for resolving any relative URIs appearing
87
        /// within the stylesheet, for example in <c>xsl:include</c> and <c>xsl:import</c>
88
        /// declarations, in schema locations defined to <c>xsl:import-schema</c>, 
89
        /// or as an argument to the <c>document()</c> or <c>doc()</c> function.
90
        /// </summary>
91
        /// <remarks>
92
        /// This base URI is used only if the input supplied to the <c>Compile</c> method
93
        /// does not provide its own base URI. It is therefore used on the version of the
94
        /// method that supplies input from a <c>Stream</c>. On the version that supplies
95
        /// input from an <c>XmlReader</c>, this base URI is used only if the <c>XmlReader</c>
96
        /// does not have its own base URI.
97
        /// </remarks>
98

    
99

    
100
        public Uri BaseUri
101
        {
102
            get { return baseUri; }
103
            set { baseUri = value; }
104
        }
105

    
106
        /// <summary>
107
        /// Create a collation based on a given <c>CompareInfo</c> and <c>CompareOptions</c>    
108
        /// </summary>
109
        /// <param name="uri">The collation URI to be used within the XPath expression to refer to this collation</param>
110
        /// <param name="compareInfo">The <c>CompareInfo</c>, which determines the language-specific
111
        /// collation rules to be used</param>
112
        /// <param name="options">Options to be used in performing comparisons, for example
113
        /// whether they are to be case-blind and/or accent-blind</param>
114
        /// <param name="isDefault">If true, this collation will be used as the default collation</param>
115

    
116
        public void DeclareCollation(Uri uri, CompareInfo compareInfo, CompareOptions options, Boolean isDefault)
117
        {
118
            DotNetComparator comparator = new DotNetComparator(compareInfo, options);
119
            env.declareCollation(uri.ToString(), comparator, isDefault);
120
        }
121

    
122
        /// <summary>
123
        /// Get the Processor from which this XsltCompiler was constructed
124
        /// </summary>
125
        public Processor Processor
126
        {
127
            get { return processor; }
128
            set { processor = value; }
129
        }
130

    
131
        /// <summary>
132
        /// An <c>XmlResolver</c>, which will be used to resolve URI references while compiling
133
        /// a stylesheet
134
        /// </summary>
135
        /// <remarks>
136
        /// If no <c>XmlResolver</c> is set for the <c>XsltCompiler</c>, the <c>XmlResolver</c>
137
        /// is used that was set on the <c>Processor</c> at the time <c>NewXsltCompiler</c>
138
        /// was called.
139
        /// </remarks>
140

    
141
        public XmlResolver XmlResolver
142
        {
143
            get
144
            {
145
                return ((DotNetURIResolver)info.getURIResolver()).getXmlResolver();
146
            }
147
            set
148
            {
149
                info.setURIResolver(new DotNetURIResolver(value));
150
            }
151
        }
152

    
153
        /// <summary>
154
        /// The <c>SchemaAware</c> property determines whether the stylesheet is schema-aware. By default, a stylesheet
155
        /// is schema-aware if it contains one or more <code>xsl:import-schema</code> declarations. This option allows
156
        /// a stylesheet to be marked as schema-aware even if it does not contain such a declaration.
157
        /// </summary>
158
        /// <remarks>
159
        /// <para>If the stylesheet is not schema-aware, then schema-validated input documents will be rejected.</para>
160
        /// <para>The reason for this option is that it is expensive to generate code that can handle typed input
161
        /// documents when they will never arise in practice.</para>
162
        /// <para>The initial setting of this property is false, regardless of whether or not the <c>Processor</c>
163
        /// is schema-aware. Setting this property to true if the processor is not schema-aware will cause an Exception.</para>
164
        /// </remarks>
165

    
166
        public bool SchemaAware
167
        {
168
            get
169
            {
170
                return info.isSchemaAware();
171
            }
172
            set
173
            {
174
                info.setSchemaAware(value);
175
            }
176
        }
177

    
178
        /// <summary>
179
        /// The <c>XsltLanguageVersion</c> property determines whether the version of the XSLT language specification
180
        /// implemented by the compiler. The values 2.0 and 3.0 refer to the XSLT 2.0 and XSLT 3.0 (formerly XSLT 2.1) specifications.
181
        /// The value 0.0 (which is the initial default) indicates that the value is to be taken from the <c>version</c>
182
        /// attribute of the <c>xsl:stylesheet</c> element.
183
        /// </summary>
184
        /// <remarks>
185
        /// <para>Values that are not numerically equal to one of the above values are rejected.</para>
186
        /// <para>A warning is output (unless suppressed) when the XSLT language version supported by the processor
187
        /// is different from the value of the <c>version</c> attribute of the <c>xsl:stylesheet</c> element.</para>
188
        /// <para>XSLT 3.0 features are supported only in Saxon-PE and Saxon-EE. Setting the value to 3.0 under 
189
        /// Saxon-HE will cause an error if (and only if) the stylesheet actually uses XSLT 3.0 constructs.</para>
190
        /// </remarks>
191

    
192
        public string XsltLanguageVersion
193
        {
194
            get
195
            {
196
                return info.getXsltVersion().toString();
197
            }
198
            set
199
            {
200
                info.setXsltVersion((JDecimalValue)JDecimalValue.makeDecimalValue(value.ToString(), true));
201
            }
202
        }
203

    
204
        /// <summary>
205
        /// List of errors. The caller should supply an empty list before calling Compile;
206
        /// the processor will then populate the list with error information obtained during
207
        /// the compilation. Each error will be included as an object of type StaticError.
208
        /// If no error list is supplied by the caller, error information will be written to
209
        /// the standard error stream.
210
        /// </summary>
211
        /// <remarks>
212
        /// By supplying a custom List with a user-written add() method, it is possible to
213
        /// intercept error conditions as they occur.
214
        /// </remarks>
215

    
216
        public IList ErrorList
217
        {
218
            set
219
            {
220
                errorList = value;
221
                info.setErrorListener(new ErrorGatherer(value));
222
            }
223
            get
224
            {
225
                return errorList;
226
            }
227
        }
228

    
229
        /// <summary>
230
        /// Compile a stylesheet supplied as a Stream.
231
        /// </summary>
232
        /// <example>
233
        /// <code>
234
        /// Stream source = new FileStream("input.xsl", FileMode.Open, FileAccess.Read);
235
        /// XsltExecutable q = compiler.Compile(source);
236
        /// source.Close();
237
        /// </code>
238
        /// </example>
239
        /// <param name="input">A stream containing the source text of the stylesheet</param>
240
        /// <returns>An <c>XsltExecutable</c> which represents the compiled stylesheet object.
241
        /// The XsltExecutable may be loaded as many times as required, in the same or a different
242
        /// thread. The <c>XsltExecutable</c> is not affected by any changes made to the <c>XsltCompiler</c>
243
        /// once it has been compiled.</returns>
244
        /// <remarks>
245
        /// <para>If the stylesheet contains any <c>xsl:include</c> or <c>xsl:import</c> declarations,
246
        /// then the <c>BaseURI</c> property must be set to allow these to be resolved.</para>
247
        /// <para>The stylesheet is contained in the part of the input stream between its current
248
        /// position and the end of the stream. It is the caller's responsibility to close the input 
249
        /// stream after use. If the compilation succeeded, then on exit the stream will be 
250
        /// exhausted; if compilation failed, the current position of the stream on exit is
251
        /// undefined.</para>
252
        /// </remarks>
253

    
254
        public XsltExecutable Compile(Stream input)
255
        {
256
            try
257
            {
258
                JStreamSource ss = new JStreamSource(new DotNetInputStream(input));
259
                if (baseUri != null)
260
                {
261
                    ss.setSystemId(baseUri.ToString());
262
                }
263
                PreparedStylesheet pss = (PreparedStylesheet)factory.newTemplates(ss, info);
264
                return new XsltExecutable(pss);
265
            }
266
            catch (JTransformerException err)
267
            {
268
                throw new StaticError(err);
269
            }
270
        }
271

    
272

    
273
        ///<summary>  
274
        ///  Get the underlying CompilerInfo object, which provides more detailed (but less stable) control
275
        ///  over some compilation options
276
        ///  </summary>
277
        /// <returns> the underlying CompilerInfo object, which holds compilation-time options. The methods on
278
        /// this object are not guaranteed stable from release to release.
279
        /// </returns>
280

    
281
        public JCompilerInfo GetUnderlyingCompilerInfo()
282
        {
283
            return info;
284
        }
285

    
286

    
287
        /// <summary>
288
        /// Externally set the value of a static parameter (new facility in XSLT 3.0) 
289
        /// </summary>
290
        /// <param name="name">The name of the parameter, expressed
291
        /// as a QName. If a parameter of this name has been declared in the
292
        /// stylesheet, the given value will be assigned to the variable. If the
293
        /// variable has not been declared, calling this method has no effect (it is
294
        /// not an error).</param>
295
        /// <param name="value">The value to be given to the parameter.
296
        /// If the parameter declaration defines a required type for the variable, then
297
        /// this value will be converted in the same way as arguments to function calls
298
        /// (for example, numeric promotion is applied).</param>
299
        public void SetParameter(QName name, XdmValue value)
300
        {
301
            variableList.Add(name, value);
302
            info.setParameter(name.ToStructuredQName(), value.Unwrap());
303
        }
304

    
305
        /// <summary>
306
        /// Compile a stylesheet supplied as a TextReader.
307
        /// </summary>
308
        /// <example>
309
        /// <code>
310
        /// String ss = "<![CDATA[<xsl:stylesheet version='2.0'>....</xsl:stylesheet>]]>";
311
        /// TextReader source = new StringReader(ss);
312
        /// XsltExecutable q = compiler.Compile(source);
313
        /// source.Close();
314
        /// </code>
315
        /// </example>
316
        /// <param name="input">A <c>TextReader</c> containing the source text of the stylesheet</param>
317
        /// <returns>An <c>XsltExecutable</c> which represents the compiled stylesheet object.
318
        /// The XsltExecutable may be loaded as many times as required, in the same or a different
319
        /// thread. The <c>XsltExecutable</c> is not affected by any changes made to the <c>XsltCompiler</c>
320
        /// once it has been compiled.</returns>
321
        /// <remarks>
322
        /// <para>If the stylesheet contains any <c>xsl:include</c> or <c>xsl:import</c> declarations,
323
        /// then the <c>BaseURI</c> property must be set to allow these to be resolved.</para>
324
        /// <para>The stylesheet is contained in the part of the input stream between its current
325
        /// position and the end of the stream. It is the caller's responsibility to close the 
326
        /// <c>TextReader</c> after use. If the compilation succeeded, then on exit the stream will be 
327
        /// exhausted; if compilation failed, the current position of the stream on exit is
328
        /// undefined.</para>
329
        /// </remarks>
330

    
331
        public XsltExecutable Compile(TextReader input)
332
        {
333
            JStreamSource ss = new JStreamSource(new DotNetReader(input));
334
            if (baseUri != null)
335
            {
336
                ss.setSystemId(baseUri.ToString());
337
            }
338
            PreparedStylesheet pss = (PreparedStylesheet)factory.newTemplates(ss, info);
339
            return new XsltExecutable(pss);
340
        }
341

    
342
        /// <summary>
343
        /// Compile a stylesheet, retrieving the source using a URI.
344
        /// </summary>
345
        /// <remarks>
346
        /// The document located via the URI is parsed using the <c>System.Xml</c> parser. This
347
        /// URI is used as the base URI of the stylesheet: the <c>BaseUri</c> property of the
348
        /// <c>Compiler</c> is ignored.
349
        /// </remarks>
350
        /// <param name="uri">The URI identifying the location where the stylesheet document can be
351
        /// found</param>
352
        /// <returns>An <c>XsltExecutable</c> which represents the compiled stylesheet object.
353
        /// The XsltExecutable may be run as many times as required, in the same or a different
354
        /// thread. The <c>XsltExecutable</c> is not affected by any changes made to the <c>XsltCompiler</c>
355
        /// once it has been compiled.</returns>
356

    
357
        public XsltExecutable Compile(Uri uri)
358
        {
359
            Object obj = XmlResolver.GetEntity(uri, "application/xml", Type.GetType("System.IO.Stream"));
360
            if (obj is Stream)
361
            {
362
                try
363
                {
364
                    XmlReaderSettings settings = new XmlReaderSettings();
365
                    settings.ProhibitDtd = false;   // must expand entity references
366
                    settings.XmlResolver = XmlResolver;
367
                    settings.IgnoreWhitespace = false;
368
                    settings.ValidationType = ValidationType.None;
369
                    XmlReader parser = XmlReader.Create((Stream)obj, settings, uri.ToString());
370
                    //XmlReader parser = new XmlTextReader(uri.ToString(), (Stream)obj);
371
                    //((XmlTextReader)parser).Normalization = true;
372
                    //((XmlTextReader)parser).WhitespaceHandling = WhitespaceHandling.All;
373
                    //((XmlTextReader)parser).XmlResolver = XmlResolver;
374
                    // Always need a validating parser, because that's the only way to get entity references expanded
375
                    //parser = new XmlValidatingReader(parser);
376
                    //((XmlValidatingReader)parser).ValidationType = ValidationType.None;
377
                    JPullSource source = new JPullSource(new DotNetPullProvider(parser));
378
                    PreparedStylesheet pss = (PreparedStylesheet)factory.newTemplates(source, info);
379
                    return new XsltExecutable(pss);
380
                }
381
                finally
382
                {
383
                    ((Stream)obj).Close();
384
                }
385
            }
386
            else
387
            {
388
                throw new ArgumentException("Invalid type of result from XmlResolver.GetEntity: " + obj);
389
            }
390
        }
391

    
392
        /// <summary>
393
        /// Compile a stylesheet, delivered using an XmlReader.
394
        /// </summary>
395
        /// <remarks>
396
        /// The <c>XmlReader</c> is responsible for parsing the document; this method builds a tree
397
        /// representation of the document (in an internal Saxon format) and compiles it.
398
        /// The <c>XmlReader</c> will be used as supplied; it is the caller's responsibility to
399
        /// ensure that the settings of the <c>XmlReader</c> are consistent with the requirements
400
        /// of the XSLT specification (for example, that entity references are expanded and whitespace
401
        /// is preserved).
402
        /// </remarks>
403
        /// <remarks>
404
        /// If the <c>XmlReader</c> has a <c>BaseUri</c> property, then that property determines
405
        /// the base URI of the stylesheet module, which is used when resolving any <c>xsl:include</c>
406
        /// or <c>xsl:import</c> declarations. If the <c>XmlReader</c> has no <c>BaseUri</c>
407
        /// property, then the <c>BaseUri</c> property of the <c>Compiler</c> is used instead.
408
        /// An <c>ArgumentNullException</c> is thrown if this property has not been supplied.
409
        /// </remarks>
410
        /// <param name="reader">The XmlReader (that is, the XML parser) used to supply the document containing
411
        /// the principal stylesheet module.</param>
412
        /// <returns>An <c>XsltExecutable</c> which represents the compiled stylesheet object.
413
        /// The XsltExecutable may be run as many times as required, in the same or a different
414
        /// thread. The <c>XsltExecutable</c> is not affected by any changes made to the <c>XsltCompiler</c>
415
        /// once it has been compiled.</returns>
416

    
417

    
418
        public XsltExecutable Compile(XmlReader reader)
419
        {
420
            DotNetPullProvider pp = new DotNetPullProvider(reader);
421
            JPipelineConfiguration pipe = config.makePipelineConfiguration();
422
            pipe.setLocationProvider(pp);
423
            pp.setPipelineConfiguration(pipe);
424
            // pp = new PullTracer(pp);  /* diagnostics */
425
            JPullSource source = new JPullSource(pp);
426
            String baseu = reader.BaseURI;
427
            if (baseu == null || baseu == String.Empty)
428
            {
429
                // if no baseURI is supplied by the XmlReader, use the one supplied to this Compiler
430
                if (baseUri == null)
431
                {
432
                    throw new ArgumentNullException("BaseUri");
433
                }
434
                baseu = baseUri.ToString();
435
                pp.setBaseURI(baseu);
436
            }
437
            source.setSystemId(baseu);
438
            PreparedStylesheet pss = (PreparedStylesheet)factory.newTemplates(source, info);
439
            return new XsltExecutable(pss);
440
        }
441

    
442
        /// <summary>
443
        /// Compile a stylesheet, located at an XdmNode. This may be a document node whose
444
        /// child is an <c>xsl:stylesheet</c> or <c>xsl:transform</c> element, or it may be
445
        /// the <c>xsl:stylesheet</c> or <c>xsl:transform</c> element itself.
446
        /// </summary>
447
        /// <param name="node">The document node or the outermost element node of the document
448
        /// containing the principal stylesheet module.</param>
449
        /// <returns>An <c>XsltExecutable</c> which represents the compiled stylesheet object.
450
        /// The XsltExecutable may be run as many times as required, in the same or a different
451
        /// thread. The <c>XsltExecutable</c> is not affected by any changes made to the <c>XsltCompiler</c>
452
        /// once it has been compiled.</returns>
453

    
454
        public XsltExecutable Compile(XdmNode node)
455
        {
456
            PreparedStylesheet pss = (PreparedStylesheet)factory.newTemplates((JNodeInfo)node.value, info);
457
            return new XsltExecutable(pss);
458
        }
459

    
460
        /// <summary>Locate and compile a stylesheet identified by an &lt;?xml-stylesheet?&gt;
461
        /// processing instruction within a source document.
462
        /// </summary>
463
        /// <param name="source">The document node of the source document containing the
464
        /// xml-stylesheet processing instruction.</param>
465
        /// <returns>An <c>XsltExecutable</c> which represents the compiled stylesheet object.</returns>
466
        /// <remarks>There are some limitations in the current implementation. The media type
467
        /// is ignored, as are the other parameters of the xml-stylesheet instruction. The
468
        /// href attribute must either reference an embedded stylesheet within the same
469
        /// document or a non-embedded external stylesheet.</remarks>
470

    
471
        public XsltExecutable CompileAssociatedStylesheet(XdmNode source)
472
        {
473
            // TODO: lift the restrictions
474
            if (source == null || source.NodeKind != XmlNodeType.Document)
475
            {
476
                throw new ArgumentException("Source must be a document node");
477
            }
478
            IEnumerator kids = source.EnumerateAxis(XdmAxis.Child);
479
            QName xmlstyle = new QName("", "xml-stylesheet");
480
            while (kids.MoveNext())
481
            {
482
                XdmNode n = (XdmNode)kids.Current;
483
                if (n.NodeKind == XmlNodeType.ProcessingInstruction &&
484
                    n.NodeName.Equals(xmlstyle))
485
                {
486
                    // TODO: check the media type
487
                    String href = JProcInstParser.getPseudoAttribute(n.StringValue, "href");
488
                    if (href == null)
489
                    {
490
                        throw new DynamicError("xml-stylesheet processing instruction has no href attribute");
491
                    }
492
                    String fragment = null;
493
                    int hash = href.LastIndexOf('#');
494
                    if (hash == 0)
495
                    {
496
                        if (href.Length == 1)
497
                        {
498
                            throw new DynamicError("Relative URI of '#' is invalid");
499
                        }
500
                        fragment = href.Substring(1);
501
                        JNodeInfo target = ((JDocumentInfo)source.value).selectID(fragment, true);
502
                        XdmNode targetWrapper = null;
503
                        if (target == null)
504
                        {
505
                            // There's a problem here because the Microsoft XML parser doesn't
506
                            // report id values, so selectID() will never work. We work around that
507
                            // by looking for an attribute named "id" appearing on an xsl:stylesheet
508
                            // or xsl:transform element
509
                            QName qid = new QName("", "id");
510
                            IEnumerator en = source.EnumerateAxis(XdmAxis.Descendant);
511
                            while (en.MoveNext())
512
                            {
513
                                XdmNode x = (XdmNode)en.Current;
514
                                if (x.NodeKind == XmlNodeType.Element &&
515
                                        x.NodeName.Uri == "http://www.w3.org/1999/XSL/Transform" &&
516
                                        (x.NodeName.LocalName == "stylesheet" || x.NodeName.LocalName == "transform" &&
517
                                        x.GetAttributeValue(qid) == fragment))
518
                                {
519
                                    targetWrapper = x;
520
                                }
521
                            }
522
                        }
523
                        else
524
                        {
525
                            targetWrapper = (XdmNode)XdmValue.Wrap(target);
526
                        }
527
                        if (targetWrapper == null)
528
                        {
529
                            throw new DynamicError("No element with id='" + fragment + "' found");
530
                        }
531
                        return Compile(targetWrapper);
532
                    }
533
                    else if (hash > 0)
534
                    {
535
                        throw new NotImplementedException("href cannot identify an embedded stylesheet in a different document");
536
                    }
537
                    else
538
                    {
539
                        Uri uri = new Uri(n.BaseUri, href);
540
                        return Compile(uri);
541
                    }
542
                }
543
            }
544
            throw new DynamicError("xml-stylesheet processing instruction not found");
545
        }
546
    }
547

    
548
    /// <summary>
549
    /// An <c>XsltExecutable</c> represents the compiled form of a stylesheet. To execute the stylesheet,
550
    /// it must first be loaded to form an <c>XsltTransformer</c>.
551
    /// </summary>
552
    /// <remarks>
553
    /// <para>An <c>XsltExecutable</c> is immutable, and therefore thread-safe. It is simplest to
554
    /// load a new <c>XsltEvaluator</c> each time the stylesheet is to be run. However, the 
555
    /// <c>XsltEvaluator</c> is serially reusable within a single thread.</para>
556
    /// <para>An <c>XsltExecutable</c> is created by using one of the <c>Compile</c>
557
    /// methods on the <c>XsltCompiler</c> class.</para>
558
    /// </remarks>    
559

    
560
    [Serializable]
561
    public class XsltExecutable
562
    {
563

    
564
        private PreparedStylesheet pss;
565

    
566
        // internal constructor
567

    
568
        internal XsltExecutable(PreparedStylesheet pss)
569
        {
570
            this.pss = pss;
571
        }
572

    
573
        /// <summary>
574
        /// Load the stylesheet to prepare it for execution.
575
        /// </summary>
576
        /// <returns>
577
        /// An <c>XsltTransformer</c>. The returned <c>XsltTransformer</c> can be used to
578
        /// set up the dynamic context for stylesheet evaluation, and to run the stylesheet.
579
        /// </returns>
580

    
581
        public XsltTransformer Load()
582
        {
583
            Controller c = (Controller)pss.newTransformer();
584
            return new XsltTransformer(c);
585
        }
586

    
587
        /// <summary>
588
        /// Output an XML representation of the compiled code of the stylesheet, for purposes of 
589
        /// diagnostics and instrumentation
590
        /// </summary>
591
        /// <param name="destination">The destination for the diagnostic output</param>
592

    
593
        public void Explain(XmlDestination destination)
594
        {
595
            JConfiguration config = pss.getConfiguration();
596
            JResult result = destination.GetResult(config.makePipelineConfiguration());
597
            JProperties properties = new JProperties();
598
            properties.setProperty("indent", "yes");
599
            properties.setProperty("{http://saxon.sf.net/}indent-spaces", "2");
600
            JReceiver receiver = config.getSerializerFactory().getReceiver(
601
                result, config.makePipelineConfiguration(), properties);
602
            JExpressionPresenter presenter = new JExpressionPresenter(config, receiver);
603
            pss.explain(presenter);
604
        }
605

    
606
        /// <summary>
607
        /// Escape hatch to the underlying Java implementation object
608
        /// </summary>
609

    
610
        public PreparedStylesheet Implementation
611
        {
612
            get
613
            {
614
                return pss;
615
            }
616
        }
617

    
618

    
619
    }
620

    
621
    /// <summary inherits="IEnumerable">
622
    /// An <c>XsltTransformer</c> represents a compiled and loaded stylesheet ready for execution.
623
    /// The <c>XsltTransformer</c> holds details of the dynamic evaluation context for the stylesheet.
624
    /// </summary>
625
    /// <remarks>
626
    /// <para>An <c>XsltTransformer</c> should not be used concurrently in multiple threads. It is safe,
627
    /// however, to reuse the object within a single thread to run the same stylesheet several times.
628
    /// Running the stylesheet does not change the context that has been established.</para>
629
    /// <para>An <c>XsltTransformer</c> is always constructed by running the <c>Load</c> method of
630
    /// an <c>XsltExecutable</c>.</para>
631
    /// </remarks>     
632

    
633
    [Serializable]
634
    public class XsltTransformer
635
    {
636

    
637
        private Controller controller;
638
        private JNodeInfo initialContextNode;
639
        private IResultDocumentHandler resultDocumentHandler;
640
        private IMessageListener messageListener;
641
        private JStreamSource streamSource;
642
        private Stream traceFunctionDestination;
643

    
644

    
645
        // internal constructor
646

    
647
        internal XsltTransformer(Controller controller)
648
        {
649
            this.controller = controller;
650
        }
651

    
652
        /// <summary>
653
        /// The initial context item for the stylesheet.
654
        /// </summary>
655
        /// <remarks><para>This may be either a node or an atomic
656
        /// value. Most commonly it will be a document node, which might be constructed
657
        /// using the <c>Build</c> method of the <c>DocumentBuilder</c> object.</para>
658
        /// <para>Note that this can be inefficient if the stylesheet uses <c>xsl:strip-space</c>
659
        /// to strip whitespace, or <c>input-type-annotations="strip"</c> to remove type
660
        /// annotations, since this will result in the transformation operating on a virtual document
661
        /// implemented as a view or wrapper of the supplied document.</para>
662
        /// </remarks>
663

    
664
        public XdmNode InitialContextNode
665
        {
666
            get { return (initialContextNode == null ? null : (XdmNode)XdmValue.Wrap(initialContextNode)); }
667
            set { initialContextNode = (value == null ? null : (JNodeInfo)value.Unwrap()); }
668
        }
669

    
670
        /// <summary>
671
        /// Supply the principal input document for the transformation in the form of a stream.
672
        /// </summary>
673
        /// <remarks>
674
        /// <para>If this method is used, the <c>InitialContextNode</c> is ignored.</para>
675
        /// <para>The supplied stream will be consumed by the <c>Run()</c> method.
676
        /// Closing the input stream after use is the client's responsibility.</para>
677
        /// <para>A base URI must be supplied in all cases. It is used to resolve relative
678
        /// URI references appearing within the input document.</para>
679
        /// <para>Schema validation is applied to the input document according to the value of
680
        /// the <c>SchemaValidationMode</c> property.</para>
681
        /// <para>Whitespace stripping is applied according to the value of the
682
        /// <c>xsl:strip-space</c> and <c>xsl:preserve-space</c> declarations in the stylesheet.</para>
683
        /// </remarks>
684
        /// <param name="input">
685
        /// The stream containing the source code of the principal input document to the transformation. The document
686
        /// node at the root of this document will be the initial context node for the transformation.
687
        /// </param>
688
        /// <param name="baseUri">
689
        /// The base URI of the principal input document. This is used for example by the <c>document()</c>
690
        /// function if the document contains links to other documents in the form of relative URIs.</param>
691

    
692
        public void SetInputStream(Stream input, Uri baseUri)
693
        {
694
            streamSource = new JStreamSource(new DotNetInputStream(input), baseUri.ToString());
695
        }
696

    
697
        /// <summary>
698
        /// The initial mode for the stylesheet. This is either a QName, for a 
699
        /// named mode, or null, for the unnamed (default) mode.
700
        /// </summary>
701

    
702
        public QName InitialMode
703
        {
704
            get
705
            {
706
                JStructuredQName mode = controller.getInitialMode().getModeName();
707
                if (mode == null)
708
                {
709
                    return null;
710
                }
711
                return QName.FromClarkName(mode.getClarkName());
712
            }
713
            set
714
            {
715
                controller.setInitialMode(value.ClarkName);
716
            }
717
        }
718

    
719
        /// <summary>
720
        /// The initial template for the stylesheet. This is either a QName, for a 
721
        /// named template, or null, if no initial template has been set.
722
        /// </summary>
723
        /// <exception cref="DynamicError">Setting this property to the name of a template
724
        /// that does not exist in the stylesheet throws a DynamicError with error 
725
        /// code XTDE0040. Setting it to the name of a template that has template
726
        /// parameters throws a DynamicError with error code XTDE0060.</exception>
727

    
728
        public QName InitialTemplate
729
        {
730
            get
731
            {
732
                String name = controller.getInitialTemplate();
733
                if (name == null)
734
                {
735
                    return null;
736
                }
737
                return QName.FromClarkName(name);
738
            }
739
            set
740
            {
741
                try
742
                {
743
                    controller.setInitialTemplate(value.ClarkName);
744
                }
745
                catch (javax.xml.transform.TransformerException err)
746
                {
747
                    throw new DynamicError(err);
748
                }
749
            }
750
        }
751

    
752
        /// <summary>
753
        /// The base output URI, which acts as the base URI for resolving the <c>href</c>
754
        /// attribute of <c>xsl:result-document</c>.
755
        /// </summary>
756

    
757
        public Uri BaseOutputUri
758
        {
759
            get
760
            {
761
                return new Uri(controller.getBaseOutputURI());
762
            }
763
            set
764
            {
765
                controller.setBaseOutputURI(value.ToString());
766
            }
767
        }
768

    
769
        public RecoveryPolicy RecoveryPolicy
770
        {
771
            get
772
            {
773
                switch (controller.getRecoveryPolicy())
774
                {
775
                    case Configuration.RECOVER_SILENTLY:
776
                        return RecoveryPolicy.RecoverSilently;
777
                    case Configuration.RECOVER_WITH_WARNINGS:
778
                        return RecoveryPolicy.RecoverWithWarnings;
779
                    default: return RecoveryPolicy.DoNotRecover;
780
                }
781
            }
782
            set
783
            {
784
                controller.setRecoveryPolicy(
785
                    value == RecoveryPolicy.RecoverSilently ? Configuration.RECOVER_SILENTLY :
786
                    value == RecoveryPolicy.RecoverWithWarnings ? Configuration.RECOVER_WITH_WARNINGS :
787
                    Configuration.DO_NOT_RECOVER);
788
            }
789
        }
790

    
791
        /// <summary>
792
        /// The <c>SchemaValidationMode</c> to be used in this transformation, especially for documents
793
        /// loaded using the <c>doc()</c>, <c>document()</c>, or <c>collection()</c> functions.
794
        /// </summary>
795
        /// 
796

    
797
        public SchemaValidationMode SchemaValidationMode
798
        {
799
            get
800
            {
801
                switch (controller.getSchemaValidationMode())
802
                {
803
                    case JValidation.STRICT:
804
                        return SchemaValidationMode.Strict;
805
                    case JValidation.LAX:
806
                        return SchemaValidationMode.Lax;
807
                    case JValidation.STRIP:
808
                        return SchemaValidationMode.None;
809
                    case JValidation.PRESERVE:
810
                        return SchemaValidationMode.Preserve;
811
                    case JValidation.DEFAULT:
812
                    default:
813
                        return SchemaValidationMode.Unspecified;
814
                }
815
            }
816

    
817
            set
818
            {
819
                switch (value)
820
                {
821
                    case SchemaValidationMode.Strict:
822
                        controller.setSchemaValidationMode(JValidation.STRICT);
823
                        break;
824
                    case SchemaValidationMode.Lax:
825
                        controller.setSchemaValidationMode(JValidation.LAX);
826
                        break;
827
                    case SchemaValidationMode.None:
828
                        controller.setSchemaValidationMode(JValidation.STRIP);
829
                        break;
830
                    case SchemaValidationMode.Preserve:
831
                        controller.setSchemaValidationMode(JValidation.PRESERVE);
832
                        break;
833
                    case SchemaValidationMode.Unspecified:
834
                    default:
835
                        controller.setSchemaValidationMode(JValidation.DEFAULT);
836
                        break;
837
                }
838
            }
839
        }
840

    
841

    
842

    
843
        /// <summary>
844
        /// The <c>XmlResolver</c> to be used at run-time to resolve and dereference URIs
845
        /// supplied to the <c>doc()</c> and <c>document()</c> functions.
846
        /// </summary>
847

    
848
        public XmlResolver InputXmlResolver
849
        {
850
            get
851
            {
852
                return ((DotNetURIResolver)controller.getURIResolver()).getXmlResolver();
853
            }
854
            set
855
            {
856
                controller.setURIResolver(new DotNetURIResolver(value));
857
            }
858
        }
859

    
860
        /// <summary>
861
        /// The <c>IResultDocumentHandler</c> to be used at run-time to process the output
862
        /// produced by any <c>xsl:result-document</c> instruction with an <c>href</c>
863
        /// attribute.
864
        /// </summary>
865
        /// <remarks>
866
        /// In the absence of a user-supplied result document handler, the <c>href</c>
867
        /// attribute of the <c>xsl:result-document</c> instruction must be a valid relative
868
        /// URI, which is resolved against the value of the <c>BaseOutputUri</c> property,
869
        /// and the resulting absolute URI must identify a writable resource (typically
870
        /// a file in filestore, using the <c>file:</c> URI scheme).
871
        /// </remarks>
872

    
873
        public IResultDocumentHandler ResultDocumentHandler
874
        {
875
            get
876
            {
877
                return resultDocumentHandler;
878
            }
879
            set
880
            {
881
                resultDocumentHandler = value;
882
                controller.setOutputURIResolver(new ResultDocumentHandlerWrapper(value, controller.makePipelineConfiguration()));
883
            }
884
        }
885

    
886
        /// <summary>
887
        /// Listener for messages output using &lt;xsl:message&gt;. 
888
        /// <para>The caller may supply a message listener before calling <c>Run</c>;
889
        /// the processor will then invoke the listener once for each message generated during
890
        /// the transformation. Each message will be output as an object of type <c>XdmNode</c>
891
        /// representing a document node.</para>
892
        /// <para>If no message listener is supplied by the caller, message information will be written to
893
        /// the standard error stream.</para>
894
        /// </summary>
895
        /// <remarks>
896
        /// <para>Each message is presented as an XML document node. Calling <c>ToString()</c>
897
        /// on the message object will usually generate an acceptable representation of the
898
        /// message.</para>
899
        /// <para>When the &lt;xsl:message&gt; instruction specifies <c>terminate="yes"</c>,
900
        /// the message is first notified using this interface, and then an exception is thrown
901
        /// which terminates the transformation.</para>
902
        /// </remarks>
903

    
904
        public IMessageListener MessageListener
905
        {
906
            set
907
            {
908
                messageListener = value;
909
                JPipelineConfiguration pipe = controller.makePipelineConfiguration();
910
                controller.setMessageEmitter(new MessageListenerProxy(pipe, value));
911
            }
912
            get
913
            {
914
                return messageListener;
915
            }
916
        }
917

    
918
        /// <summary>
919
        /// Destination for output of messages using &lt;trace()&gt;. 
920
        /// <para>If no message listener is supplied by the caller, message information will be written to
921
        /// the standard error stream.</para>
922
        /// </summary>
923
        /// <remarks>
924
        /// <para>The supplied destination is ignored if a <c>TraceListener</c> is in use.</para>
925
        /// </remarks>
926

    
927
        public Stream TraceFunctionDestination
928
        {
929
            set
930
            {
931
                traceFunctionDestination = value;
932
                controller.setTraceFunctionDestination(
933
                    new java.io.PrintStream(new DotNetOutputStream(value)));
934
            }
935
            get
936
            {
937
                return traceFunctionDestination;
938
            }
939
        }
940

    
941

    
942

    
943
        /// <summary>
944
        /// Set the value of a stylesheet parameter.
945
        /// </summary>
946
        /// <param name="name">The name of the parameter, expressed
947
        /// as a QName. If a parameter of this name has been declared in the
948
        /// stylesheet, the given value will be assigned to the variable. If the
949
        /// variable has not been declared, calling this method has no effect (it is
950
        /// not an error).</param>
951
        /// <param name="value">The value to be given to the parameter.
952
        /// If the parameter declaration defines a required type for the variable, then
953
        /// this value will be converted in the same way as arguments to function calls
954
        /// (for example, numeric promotion is applied).</param>
955

    
956
        public void SetParameter(QName name, XdmValue value)
957
        {
958
            controller.setParameter(name.ClarkName, value.Unwrap());
959
        }
960

    
961
        /// <summary>
962
        /// Run the transformation, sending the result to a specified destination.
963
        /// </summary>
964
        /// <param name="destination">
965
        /// The destination for the results of the stylesheet. The class <c>XmlDestination</c>
966
        /// is an abstraction that allows a number of different kinds of destination
967
        /// to be specified.
968
        /// </param>
969
        /// <exception cref="DynamicError">Throws a DynamicError if the transformation
970
        /// fails.</exception>
971

    
972
        public void Run(XmlDestination destination)
973
        {
974
            try
975
            {
976
                controller.setOutputProperties(destination.GetOutputProperties());
977
                if (streamSource != null)
978
                {
979
                    controller.transform(streamSource, destination.GetResult(controller.makePipelineConfiguration()));
980
                }
981
                else if (initialContextNode != null)
982
                {
983
                    JDocumentInfo doc = initialContextNode.getDocumentRoot();
984
                    if (doc != null)
985
                    {
986
                        controller.registerDocument(doc, (doc.getBaseURI() == null ? null : new JDocumentURI(doc.getBaseURI())));
987
                    }
988
                    controller.transform(initialContextNode, destination.GetResult(controller.makePipelineConfiguration()));
989
                }
990
                else
991
                {
992
                    controller.transform(null, destination.GetResult(controller.makePipelineConfiguration()));
993
                }
994
                destination.Close();
995
            }
996
            catch (javax.xml.transform.TransformerException err)
997
            {
998
                throw new DynamicError(err);
999
            }
1000
        }
1001

    
1002
        /// <summary>
1003
        /// Escape hatch to the underlying Java implementation
1004
        /// </summary>
1005

    
1006
        public Controller Implementation
1007
        {
1008
            get { return controller; }
1009
        }
1010

    
1011

    
1012
    }
1013

    
1014
    /// <summary>
1015
    /// RecoveryPolicy is an enumeration of the different actions that can be taken when a "recoverable error" occurs
1016
    /// </summary>
1017

    
1018
    public enum RecoveryPolicy
1019
    {
1020
        /// <summary>
1021
        /// Ignore the error, take the recovery action, do not produce any message
1022
        /// </summary>
1023
        RecoverSilently,
1024

    
1025
        /// <summary>
1026
        /// Take the recovery action after outputting a warning message
1027
        /// </summary>
1028
        RecoverWithWarnings,
1029

    
1030
        /// <summary>
1031
        /// Treat the error as fatal
1032
        /// </summary>
1033
        DoNotRecover
1034

    
1035
    }
1036

    
1037

    
1038

    
1039
    ///<summary>An <c>IResultDocumentHandler</c> can be nominated to handle output
1040
    /// produced by the <c>xsl:result-document</c> instruction in an XSLT stylesheet.
1041
    ///</summary>
1042
    ///<remarks>
1043
    ///<para>This interface affects any <c>xsl:result-document</c> instruction
1044
    /// executed by the stylesheet, provided that it has an <c>href</c> attribute.</para> 
1045
    ///<para>If no <c>IResultDocumentHandler</c> is nominated (in the
1046
    /// <c>IResultDocumentHandler</c> property of the <c>XsltTransformer</c>), the output
1047
    /// of <code>xsl:result-document</code> is serialized, and is written to the file
1048
    /// or other resource identified by the URI in the <c>href</c> attribute, resolved
1049
    /// (if it is relative) against the URI supplied in the <c>BaseOutputUri</c> property
1050
    /// of the <c>XsltTransformer</c>.</para>
1051
    ///<para>If an <c>IResultDocumentHandler</c> is nominated, however, its
1052
    /// <c>HandleResultDocument</c> method will be called whenever an <c>xsl:result-document</c>
1053
    /// instruction with an <c>href</c> attribute is evaluated, and the generated result tree
1054
    /// will be passed to the <c>XmlDestination</c> returned by that method.</para> 
1055
    ///</remarks>
1056

    
1057
    public interface IResultDocumentHandler
1058
    {
1059

    
1060
        /// <summary> Handle output produced by the <c>xsl:result-document</c>
1061
        /// instruction in an XSLT stylesheet. This method is called by the XSLT processor
1062
        /// when an <c>xsl:result-document</c> with an <c>href</c> attribute is evaluated.
1063
        /// </summary>
1064
        /// <param name="href">An absolute or relative URI. This will be the effective value of the 
1065
        /// <c>href</c> attribute of the <c>xsl:result-document</c> in the stylesheet.</param>
1066
        /// <param name="baseUri">The base URI that should be used for resolving the value of
1067
        /// <c>href</c> if it is relative. This will always be the value of the <c>BaseOutputUri</c>
1068
        /// property of the <c>XsltTransformer</c>.</param>
1069
        /// <returns>An <c>XmlDestination</c> to handle the result tree produced by the
1070
        /// <c>xsl:result-document</c> instruction. The <c>Close</c> method of the returned
1071
        /// <c>XmlDestination</c> will be called when the output is complete.</returns>
1072
        /// <remarks>
1073
        /// <para>The XSLT processor will ensure that the stylesheet cannot create
1074
        /// two distinct result documents which are sent to the same URI. It is the responsibility
1075
        /// of the <c>IResultDocumentHandler</c> to ensure that two distinct result documents are
1076
        /// not sent to the same <c>XmlDestination</c>. Failure to observe this rule can result
1077
        /// in output streams being incorrectly closed.
1078
        /// </para>
1079
        /// <para>Note that more than one result document can be open at the same time,
1080
        /// and that the order of opening, writing, and closing result documents chosen
1081
        /// by the processor does not necessarily bear any direct resemblance to the way
1082
        /// that the XSLT source code is written.</para></remarks>
1083

    
1084
        /**public**/ XmlDestination HandleResultDocument(string href, Uri baseUri);
1085

    
1086
    }
1087

    
1088
    internal class ResultDocumentHandlerWrapper : JOutputURIResolver
1089
    {
1090

    
1091
        private IResultDocumentHandler handler;
1092
        private ArrayList resultList = new ArrayList();
1093
        private ArrayList destinationList = new ArrayList();
1094
        private JPipelineConfiguration pipe;
1095

    
1096
        public ResultDocumentHandlerWrapper(IResultDocumentHandler handler, JPipelineConfiguration pipe)
1097
        {
1098
            this.handler = handler;
1099
            this.pipe = pipe;
1100
        }
1101

    
1102
        public JOutputURIResolver newInstance()
1103
        {
1104
            return new ResultDocumentHandlerWrapper(handler, pipe);
1105
        }
1106

    
1107
        public JResult resolve(String href, String baseString)
1108
        {
1109
            Uri baseUri;
1110
            try
1111
            {
1112
                baseUri = new Uri(baseString);
1113
            }
1114
            catch (System.UriFormatException err)
1115
            {
1116
                throw new JTransformerException("Invalid base output URI " + baseString, err);
1117
            }
1118
            XmlDestination destination = handler.HandleResultDocument(href, baseUri);
1119
            JResult result = destination.GetResult(pipe);
1120
            resultList.Add(result);
1121
            destinationList.Add(destination);
1122
            return result;
1123
        }
1124

    
1125
        public void close(JResult result)
1126
        {
1127
            for (int i = 0; i < resultList.Count; i++)
1128
            {
1129
                if (Object.ReferenceEquals(resultList[i], result))
1130
                {
1131
                    ((XmlDestination)destinationList[i]).Close();
1132
                    resultList.RemoveAt(i);
1133
                    destinationList.RemoveAt(i);
1134
                    return;
1135
                }
1136
            }
1137
        }
1138
    }
1139

    
1140
    ///<summary>An <c>IMessageListener</c> can be nominated to handle output
1141
    /// produced by the <c>xsl:message</c> instruction in an XSLT stylesheet.
1142
    ///</summary>
1143
    ///<remarks>
1144
    ///<para>This interface affects any <c>xsl:message</c> instruction
1145
    /// executed by the stylesheet.</para> 
1146
    ///<para>If no <c>IMessageListener</c> is nominated (in the
1147
    /// <c>MessageListener</c> property of the <c>XsltTransformer</c>), the output
1148
    /// of <code>xsl:message</code> is serialized, and is written to standard error
1149
    /// output stream.</para>
1150
    ///<para>If an <c>IMessageListener</c> is nominated, however, its
1151
    /// <c>Message</c> method will be called whenever an <c>xsl:message</c>
1152
    /// instruction is evaluated.</para> 
1153
    ///</remarks>
1154

    
1155

    
1156
    public interface IMessageListener
1157
    {
1158

    
1159
        ///<summary>Handle the output of an <c>xsl:message</c> instruction
1160
        ///in the stylesheet
1161
        ///</summary>
1162
        ///
1163

    
1164
        /**public**/
1165
        void Message(XdmNode content, bool terminate, IXmlLocation location);
1166

    
1167
    }
1168

    
1169
    /// <summary>
1170
    /// An <c>IXmlLocation</c> represents the location of a node within an XML document.
1171
    /// It is in two parts: the base URI (or system ID) of the external entity (which will usually
1172
    /// be the XML document entity itself), and the line number of a node relative
1173
    /// to the base URI of the containing external entity.
1174
    /// </summary>
1175
    /// 
1176

    
1177
    public interface IXmlLocation
1178
    {
1179

    
1180
        /// <summary>
1181
        /// The base URI (system ID) of an external entity within an XML document.
1182
        /// Set to null if the base URI is not known (for example, for an XML document
1183
        /// created programmatically where no base URI has been set up).
1184
        /// </summary>
1185

    
1186
        /**public**/ Uri BaseUri { get; set; }
1187

    
1188
        /// <summary>
1189
        /// The line number of a node relative to the start of the external entity.
1190
        /// The value -1 indicates that the line number is not known or not applicable.
1191
        /// </summary>
1192

    
1193
        /**public**/ int LineNumber { get; set; }
1194
    }
1195

    
1196
    internal class XmlLocation : IXmlLocation
1197
    {
1198
        private Uri baseUri;
1199
        private int lineNumber;
1200
        public Uri BaseUri
1201
        {
1202
            get { return baseUri; }
1203
            set { baseUri = value; }
1204
        }
1205
        public int LineNumber
1206
        {
1207
            get { return lineNumber; }
1208
            set { lineNumber = value; }
1209
        }
1210
    }
1211

    
1212

    
1213
    [Serializable]
1214
    internal class MessageListenerProxy : JSequenceWriter
1215
    {
1216

    
1217
        public IMessageListener listener;
1218
        public bool terminate;
1219
        public int locationId;
1220

    
1221
        public MessageListenerProxy(JPipelineConfiguration pipe, IMessageListener ml)
1222
            : base(pipe)
1223
        {
1224
            listener = ml;
1225
            setTreeModel(TreeModel.LinkedTree);
1226
        }
1227

    
1228
        public override void startDocument(int properties)
1229
        {
1230
            terminate = (properties & JReceiverOptions.TERMINATE) != 0;
1231
            locationId = -1;
1232
            base.startDocument(properties);
1233
        }
1234

    
1235
        public override void startElement(JNodeName nameCode, JSchemaType typeCode, int locationId, int properties)
1236
        {
1237
            if (this.locationId == -1)
1238
            {
1239
                this.locationId = locationId;
1240
            }
1241
            base.startElement(nameCode, typeCode, locationId, properties);
1242
        }
1243

    
1244
        public override void characters(CharSequence s, int locationId, int properties)
1245
        {
1246
            if (this.locationId == -1)
1247
            {
1248
                this.locationId = locationId;
1249
            }
1250
            base.characters(s, locationId, properties);
1251
        }
1252

    
1253
        public override void append(JItem item, int locationId, int copyNamespaces)
1254
        {
1255
            if (this.locationId == -1)
1256
            {
1257
                this.locationId = locationId;
1258
            }
1259
            base.append(item, locationId, copyNamespaces);
1260
        }
1261

    
1262
        public override void write(JItem item)
1263
        {
1264
            XmlLocation loc = new XmlLocation();
1265
            if (locationId != -1)
1266
            {
1267
                JLocationProvider provider = getPipelineConfiguration().getLocationProvider();
1268
                loc.BaseUri = new Uri(provider.getSystemId(locationId));
1269
                loc.LineNumber = provider.getLineNumber(locationId);
1270
            }
1271
            listener.Message((XdmNode)XdmItem.Wrap(item), terminate, loc);
1272
        }
1273
    }
1274

    
1275

    
1276
}
1277

    
1278
//
1279
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
1280
// you may not use this file except in compliance with the License. You may obtain a copy of the
1281
// License at http://www.mozilla.org/MPL/
1282
//
1283
// Software distributed under the License is distributed on an "AS IS" basis,
1284
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
1285
// See the License for the specific language governing rights and limitations under the License.
1286
//
1287
// The Original Code is: all this file.
1288
//
1289
// The Initial Developer of the Original Code is Michael H. Kay.
1290
//
1291
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
1292
//
1293
// Contributor(s): none.
1294
//
(12-12/12)