Project

Profile

Help

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

he / tags / 9.6.0.7 / hen / csource / api / Saxon.Api / Destination.cs @ aa733b18

1
using System;
2
using System.IO;
3
using System.Xml;
4
using System.Collections;
5
using JConfiguration = net.sf.saxon.Configuration;
6
using JPipelineConfiguration = net.sf.saxon.@event.PipelineConfiguration;
7
using JReceiver = net.sf.saxon.@event.Receiver;
8
using JSink = net.sf.saxon.@event.Sink;
9
using JProperties = java.util.Properties;
10
using JOutputStream = java.io.OutputStream;
11
using JWriter = java.io.Writer;
12
using JCharSequence = java.lang.CharSequence;
13
using JFileOutputStream = java.io.FileOutputStream;
14
using JXPathException = net.sf.saxon.trans.XPathException;
15
using JResult = javax.xml.transform.Result;
16
using JStreamResult = javax.xml.transform.stream.StreamResult;
17
using JCharacterMapIndex = net.sf.saxon.serialize.CharacterMapIndex;
18
using JBuilder = net.sf.saxon.@event.Builder;
19
using JTinyBuilder = net.sf.saxon.tree.tiny.TinyBuilder;
20
using JLinkedTreeBuilder = net.sf.saxon.tree.linked.LinkedTreeBuilder;
21
using JSchemaType = net.sf.saxon.type.SchemaType;
22
using net.sf.saxon.@event;
23
using net.sf.saxon.lib;
24
using net.sf.saxon.om;
25
using net.sf.saxon.value;
26
using net.sf.saxon.query;
27
using net.sf.saxon.dotnet;
28

    
29

    
30
namespace Saxon.Api
31
{
32

    
33

    
34

    
35
    /// <summary>
36
    /// An abstract destination for the results of a query or transformation
37
    /// </summary>
38
    /// <remarks>
39
    /// <para>Note to implementors: To implement a new kind of destination, you need
40
    /// to supply a method <c>getResult</c> which returns an implementation of
41
    /// the JAXP <c>Result</c> interface. Optionally, if the destination
42
    /// performs serialization, you can also implement <c>getOutputProperties</c>,
43
    /// which returns the properties used for serialization.
44
    /// </para>
45
    /// </remarks>
46

    
47

    
48
    public abstract class XmlDestination
49
    {
50

    
51
        /// <summary>
52
        /// Get a <c>Result</c> to which the XML document can be sent as a series
53
        /// of events. This method is intended primarily for internal use.
54
        /// </summary>
55
        /// <remarks>
56
        /// The returned value must be an implementation of the JAXP <c>Result</c> interface that is
57
        /// recognized by Saxon.
58
        /// </remarks>
59
        /// <param name="pipe">Configuration information for use by the implementation</param>
60

    
61
        public abstract JReceiver GetReceiver(JPipelineConfiguration pipe);
62

    
63
        /// <summary>
64
        /// Get a set of <c>Properties</c> representing the parameters to the serializer.
65
        /// The default implementation returns an empty set of properties.
66
        /// </summary>
67

    
68
        public virtual JProperties GetOutputProperties()
69
        {
70
            return new JProperties();
71
        }
72

    
73
        /// <summary>
74
        /// Close the Destination, releasing any resources that need to be released.
75
        /// </summary>
76
        /// <remarks>
77
        /// This method is called by the system on completion of a query or transformation.
78
        /// Some kinds of Destination may need to close an output stream, others might
79
        /// not need to do anything. The default implementation does nothing.
80
        /// </remarks>
81

    
82
        public virtual void Close()
83
        {
84
        }
85

    
86

    
87
    }
88

    
89
    /// <summary>
90
    /// A <c>Serializer</c> takes a tree representation of XML and turns
91
    /// it into lexical XML markup.
92
    /// </summary>
93
    /// <remarks>
94
    /// Note that this is serialization in the sense of the W3C XSLT and XQuery specifications.
95
    /// Unlike the class <c>System.Xml.Serialization.XmlSerializer</c>, this object does not
96
    /// serialize arbitrary CLI objects.
97
    /// </remarks>
98

    
99
    public class Serializer : XmlDestination
100
    {
101

    
102
        private JProperties props = new JProperties();
103
		private JCharacterMapIndex characterMap;
104
		private JProperties defaultOutputProperties = null;
105
        private JOutputStream outputStream = null;
106
		private String filename = null;
107
        private JWriter writer = null;
108
        private bool mustClose = true;
109
        private JConfiguration config = null; // Beware: this will often be null
110

    
111
        /// <summary>QName identifying the serialization parameter "method". If the method
112
        /// is a user-defined method, then it is given as a QName in Clark notation, that is
113
        /// "{uri}local".</summary>
114

    
115
        public static readonly QName METHOD =
116
            new QName("", "method");
117

    
118
        /// <summary>QName identifying the serialization parameter "byte-order-mark"</summary>
119

    
120
        public static readonly QName BYTE_ORDER_MARK =
121
            new QName("", "byte-order-mark");
122

    
123
        /// <summary>QName identifying the serialization parameter "cdata-section-elements".
124
        /// The value of this parameter is given as a space-separated list of expanded QNames in
125
        /// Clark notation, that is "{uri}local".</summary>
126

    
127
        public static readonly QName CDATA_SECTION_ELEMENTS =
128
            new QName("", "cdata-section-elements");
129

    
130
        /// <summary>QName identifying the serialization parameter "doctype-public"</summary>
131

    
132
        public static readonly QName DOCTYPE_PUBLIC =
133
            new QName("", "doctype-public");
134

    
135
        /// <summary>QName identifying the serialization parameter "doctype-system"</summary>
136

    
137
        public static readonly QName DOCTYPE_SYSTEM =
138
            new QName("", "doctype-system");
139

    
140
        /// <summary>QName identifying the serialization parameter "encoding"</summary>
141

    
142
        public static readonly QName ENCODING =
143
            new QName("", "encoding");
144

    
145
        /// <summary>QName identifying the serialization parameter "escape-uri-attributes".
146
        /// The value is the string "yes" or "no".</summary>
147

    
148
        public static readonly QName ESCAPE_URI_ATTRIBUTES =
149
            new QName("", "escape-uri-attributes");
150

    
151
        /// <summary>QName identifying the serialization parameter "include-content-type".
152
        /// The value is the string "yes" or "no".</summary>
153

    
154
        public static readonly QName INCLUDE_CONTENT_TYPE =
155
            new QName("", "include-content-type");
156

    
157
        /// <summary>QName identifying the serialization parameter "indent".
158
        /// The value is the string "yes" or "no".</summary>
159

    
160
        public static readonly QName INDENT =
161
            new QName("", "indent");
162

    
163
        /// <summary>QName identifying the serialization parameter "media-type".</summary>
164

    
165
        public static readonly QName MEDIA_TYPE =
166
            new QName("", "media-type");
167

    
168
        /// <summary>QName identifying the serialization parameter "normalization-form"</summary>
169

    
170
        public static readonly QName NORMALIZATION_FORM =
171
            new QName("", "normalization-form");
172

    
173
        /// <summary>QName identifying the serialization parameter "omit-xml-declaration".
174
        /// The value is the string "yes" or "no".</summary>
175

    
176
        public static readonly QName OMIT_XML_DECLARATION =
177
            new QName("", "omit-xml-declaration");
178

    
179
        /// <summary>QName identifying the serialization parameter "standalone".
180
        /// The value is the string "yes" or "no" or "omit".</summary>
181

    
182
        public static readonly QName STANDALONE =
183
            new QName("", "standalone");
184

    
185
        /// <summary>QName identifying the serialization parameter "suppress-indentation"
186
        /// (introduced in XSLT/XQuery 3.0). Previously available as "saxon:suppress-indentation"
187
        /// The value is the string "yes" or "no" or "omit".</summary>
188

    
189
        public static readonly QName SUPPRESS_INDENTATION =
190
            new QName("", "suppress-indentation");
191

    
192
        /// <summary>QName identifying the serialization parameter "undeclare-prefixes".
193
        /// The value is the string "yes" or "no".</summary>
194

    
195
        public static readonly QName UNDECLARE_PREFIXES =
196
            new QName("", "undeclare-prefixes");
197

    
198
        /// <summary>QName identifying the serialization parameter "use-character-maps".
199
        /// This is available only with XSLT. The value of the parameter is a list of expanded QNames
200
        /// in Clark notation giving the names of character maps defined in the XSLT stylesheet.</summary>
201

    
202
        public static readonly QName USE_CHARACTER_MAPS =
203
            new QName("", "use-character-maps");
204

    
205
        /// <summary>QName identifying the serialization parameter "version"</summary>
206

    
207
        public static readonly QName VERSION =
208
            new QName("", "version");
209

    
210
        private static readonly String SAXON = NamespaceConstant.SAXON;
211

    
212

    
213
        /// <summary>QName identifying the serialization parameter "saxon:character-representation"</summary>
214

    
215

    
216
        public static readonly QName SAXON_CHARACTER_REPRESENTATION =
217
            new QName(SAXON, "saxon:character-representation");
218

    
219
        /// <summary>QName identifying the serialization parameter "saxon:indent-spaces". The value
220
        /// is an integer (represented as a string) indicating the amount of indentation required.
221
        /// If specified, this parameter overrides indent="no".</summary>
222

    
223
        public static readonly QName SAXON_INDENT_SPACES =
224
            new QName(SAXON, "saxon:indent-spaces");
225

    
226
        /// <summary>QName identifying the serialization parameter "saxon:double-space". The value of this 
227
        /// parameter is given as a space-separated list of expanded QNames in Clark notation, that is 
228
        /// "{uri}local"; each QName identifies an element that should be preceded by an extra blank line within
229
        /// indented output.</summary>
230

    
231
        public static readonly QName SAXON_DOUBLE_SPACE =
232
            new QName(SAXON, "saxon:double-space");
233

    
234
        /// <summary>QName identifying the serialization parameter "saxon:double-space". The value of this 
235
        /// parameter is given as a space-separated list of expanded QNames in Clark notation, that is 
236
        /// "{uri}local"; each QName identifies an element whose content should not be indented even when
237
        /// indent=yes is specified.</summary>
238

    
239
        public static readonly QName SAXON_SUPPRESS_INDENTATION =
240
            new QName(SAXON, "saxon:suppress-indentation");
241

    
242
        /// <summary>QName identifying the serialization parameter "saxon:next-in-chain". This
243
        /// is available only with XSLT, and identifies the URI of a stylesheet that is to be used to
244
        /// process the results before passing them to their final destination.</summary>
245

    
246
        public static readonly QName NEXT_IN_CHAIN =
247
            new QName(SAXON, "saxon:next-in-chain");
248

    
249
        /// <summary>QName identifying the serialization parameter "saxon:require-well-formed". The
250
        /// value is the string "yes" or "no". If set to "yes", the output must be a well-formed
251
        /// document, or an error will be reported. ("Well-formed" here means that the document node
252
        /// must have exactly one element child, and no text node children other than whitespace-only
253
        /// text nodes).</summary>
254

    
255
        public static readonly QName SAXON_REQUIRE_WELL_FORMED =
256
            new QName(SAXON, "saxon:require-well-formed");
257

    
258

    
259
        /// <summary>Create a Serializer</summary>
260

    
261
        public Serializer()
262
        {
263
        }
264

    
265
        /// <summary>Set a serialization property</summary>
266
        /// <remarks>In the case of XSLT, properties set within the serializer override
267
        /// any properties set in <c>xsl:output</c> declarations in the stylesheet.
268
        /// Similarly, with XQuery, they override any properties set in the Query
269
        /// prolog using <c>declare option saxon:output</c>.</remarks>
270
        /// <example>
271
        ///   <code>
272
        ///     Serializer qout = new Serializer();
273
        ///     qout.SetOutputProperty(Serializer.METHOD, "xml");
274
        ///     qout.SetOutputProperty(Serializer.INDENT, "yes");
275
        ///     qout.SetOutputProperty(Serializer.SAXON_INDENT_SPACES, "1");
276
        ///   </code>
277
        /// </example> 
278
        /// <param name="name">The name of the serialization property to be set</param>
279
        /// <param name="value">The value to be set for the serialization property. May be null
280
        /// to unset the property (that is, to set it back to the default value).</param>
281

    
282
        public void SetOutputProperty(QName name, String value)
283
        {
284
            props.setProperty(name.ClarkName, value);
285
        }
286

    
287

    
288
		public void SetDefaultOutputProperties(JProperties props)
289
		{
290
			this.defaultOutputProperties = props;
291
		}
292

    
293
		public void SetCharacterMap(JCharacterMapIndex charMap)
294
		{
295
			this.characterMap = charMap;
296
		}
297
			
298

    
299
        /// <summary>Specify the destination of the serialized output, in the
300
        /// form of a file name</summary>
301
        /// <param name="filename">The name of the file to receive the serialized output</param>
302
        /// <exception>Throws a <c>DynamicError</c> if it is not possible to create an output
303
        /// stream to write to this file, for example, if the filename is in a directory
304
        /// that does not exist.</exception>
305

    
306
        public void SetOutputFile(String filename)
307
        {
308
            try
309
            {
310
                outputStream = new JFileOutputStream(filename);
311
				this.filename = filename;
312
                mustClose = true;
313
            }
314
            catch (java.io.IOException err)
315
            {
316
                JXPathException e = new JXPathException(err);
317
                throw new DynamicError(e);
318
            }
319
        }
320

    
321
		internal String GetFilename(){
322
			return filename;
323
		}
324

    
325
        /// <summary>Specify the destination of the serialized output, in the
326
        /// form of a <c>Stream</c></summary>
327
        /// <remarks>Saxon will not close the stream on completion; this is the
328
        /// caller's responsibility.</remarks>
329
        /// <param name="stream">The stream to which the output will be written.
330
        /// This must be a stream that allows writing.</param>
331

    
332
        public void SetOutputStream(Stream stream)
333
        {
334
            outputStream = new DotNetOutputStream(stream);
335
            mustClose = false;
336
        }
337
			
338
    	// <summary>Get the current output destination.</summary> 
339
		// <returns>JOutputStream</returns>
340
		public JOutputStream GetOutputDestination(){
341
			return outputStream;		
342
		}
343

    
344

    
345
        /**
346
         * <summary>Set the Processor associated with this Serializer. This will be called automatically if the
347
         * serializer is created using one of the <c>Processor.NewSerializer()</c> methods.</summary>
348
         *
349
         * <param name="processor"> processor the associated Processor</param>
350
         */
351
        public void SetProcessor(Processor processor)
352
        {
353
            this.config = processor.Implementation;
354
        }
355

    
356
        /// <summary>Specify the destination of the serialized output, in the
357
        /// form of a <c>TextWriter</c></summary>
358
        /// <remarks>Note that when writing to a <c>TextWriter</c>, character encoding is
359
        /// the responsibility of the <c>TextWriter</c>, not the <c>Serializer</c>. This
360
        /// means that the encoding requested in the output properties is ignored; it also
361
        /// means that characters that cannot be represented in the target encoding will
362
        /// use whatever fallback representation the <c>TextWriter</c> defines, rather than
363
        /// being represented as XML character references.</remarks>
364
        /// <param name="textWriter">The stream to which the output will be written.
365
        /// This must be a stream that allows writing. Saxon will not close the
366
        /// <c>textWriter</c> on completion; this is the caller's responsibility.</param>
367

    
368
        public void SetOutputWriter(TextWriter textWriter)
369
        {
370
            writer = new DotNetWriter(textWriter);
371
            mustClose = false;
372
        }
373

    
374
        internal JReceiver GetReceiver(JConfiguration config)
375
        {
376
            JPipelineConfiguration pipe = config.makePipelineConfiguration();
377
            return config.getSerializerFactory().getReceiver(
378
                    GetResult(pipe),
379
                    pipe,
380
				GetOutputProperties(), characterMap);
381

    
382
        }
383

    
384
		public override JReceiver GetReceiver(JPipelineConfiguration pipe){
385
			return GetReceiver (pipe.getConfiguration());
386
		}
387

    
388

    
389
        /// <summary inherit="yes"/>
390

    
391
        internal JResult GetResult(JPipelineConfiguration pipe)
392
        {
393
            if (outputStream != null)
394
            {
395
                return new JStreamResult(outputStream);
396
            }
397
            else if (writer != null)
398
            {
399
                return new JStreamResult(writer);
400
            }
401
            else
402
            {
403
                return new JStreamResult(new DotNetWriter(Console.Out));
404
            }
405
        }
406

    
407
        /// <summary inherit="yes"/>
408

    
409
        public override JProperties GetOutputProperties()
410
        {
411
			JProperties properties = (defaultOutputProperties == null ? new JProperties () : new JProperties (defaultOutputProperties));
412
			java.util.Enumeration propsEnum =  props.keys();
413
			while (propsEnum.hasMoreElements()) {
414
				object obj = propsEnum.nextElement();
415
				String value = (String)(props.get((String)obj));
416
				properties.setProperty ((String)obj, value);
417
			}
418
			return properties;
419
        }
420

    
421
        /// <summary inherit="yes"/>
422

    
423
        public override void Close()
424
        {
425
            if (mustClose)
426
            {
427
                if (outputStream != null)
428
                {
429
                    outputStream.close();
430
                }
431
                if (writer != null)
432
                {
433
                    writer.close();
434
                }
435
            }
436
        }
437
    }
438

    
439
    /// <summary>
440
    /// A <c>DomDestination</c> represents an XmlDocument that is constructed to hold the
441
    /// output of a query or transformation.
442
    /// </summary>
443
    /// <remarks>
444
    /// No data needs to be supplied to the <c>DomDestination</c> object. The query or transformation
445
    /// populates an <c>XmlDocument</c>, which may then be retrieved as the value of the <c>XmlDocument</c>
446
    /// property
447
    /// </remarks>
448

    
449
    public class DomDestination : XmlDestination
450
    {
451

    
452
        internal DotNetDomBuilder builder;
453

    
454
        /// <summary>Construct a <c>DomDestination</c></summary>
455
        /// <remarks>With this constructor, the system will create a new DOM Document
456
        /// to act as the destination of the query or transformation results. The document
457
        /// node of the new document may be retrieved via the XmlDocument property.</remarks>
458

    
459
        public DomDestination()
460
        {
461
            builder = new DotNetDomBuilder();
462
        }
463

    
464
        /// <summary>Construct a <c>DomDestination</c> based on an existing Document node.</summary>
465
        /// <remarks>The new data will be added as a child of the supplied node.</remarks>
466
        /// <param name="attachmentPoint">The document node to which new contents will
467
        /// be attached. To ensure that the new document is well-formed, this document node
468
        /// should have no existing children.</param>
469

    
470
        public DomDestination(XmlDocument attachmentPoint)
471
        {
472
            builder = new DotNetDomBuilder();
473
            builder.setAttachmentPoint(attachmentPoint);
474
        }
475

    
476
        /// <summary>Construct a <c>DomDestination</c> based on an existing DocumentFragment node.</summary>
477
        /// <remarks>The new data will be added as a child of the supplied node.</remarks>
478
        /// <param name="attachmentPoint">The document fragment node to which new contents will
479
        /// be attached. The new contents will be added after any existing children.</param>
480

    
481
        public DomDestination(XmlDocumentFragment attachmentPoint)
482
        {
483
            builder = new DotNetDomBuilder();
484
            builder.setAttachmentPoint(attachmentPoint);
485
        }
486

    
487
        /// <summary>Construct a <c>DomDestination</c> based on an existing Element node.</summary>
488
        /// <remarks>The new data will be added as a child of the supplied element node.</remarks>
489
        /// <param name="attachmentPoint">The element node to which new contents will
490
        /// be attached. The new contents will be added after any existing children.</param>
491

    
492
        public DomDestination(XmlElement attachmentPoint)
493
        {
494
            builder = new DotNetDomBuilder();
495
            builder.setAttachmentPoint(attachmentPoint);
496
        }
497

    
498
        /// <summary>After construction, retrieve the constructed document node</summary>
499
        /// <remarks>If the zero-argument constructor was used, this will be a newly
500
        /// constructed document node. If the constructor supplied a document node, the
501
        /// same document node will be returned. If the constructor supplied a document fragment
502
        /// node or an element node, this method returns the <c>OwnerDocument</c> property of 
503
        /// that node.</remarks>
504

    
505
        public XmlDocument XmlDocument
506
        {
507
            get { return builder.getDocumentNode(); }
508
        }
509

    
510
		/// <summary inherit="yes"/>
511
		/// eturn a Receiver. Saxon calls this method to obtain a Receiver, to which it then sends
512
		/// a sequence of events representing the content of an XML document.
513
        /// </summary>
514
		/// <param name="pipe">Pipe. The Saxon pipeline configuration. This is supplied so that the destination can
515
		/// use information from the <code>PipelineConfiguration</code> (for example, a reference to the name pool)
516
		/// to construct or configure the returned Receiver.</param>
517
		/// <returns>The receiver.</returns>
518

    
519
        public override JReceiver GetReceiver(JPipelineConfiguration pipe)
520
        {
521
			builder.setPipelineConfiguration (pipe);
522
            return builder;
523
        }
524

    
525
		/// <summary>
526
		/// Gets the receiver.
527
		/// </summary>
528
		/// <param name="config">Config.The Saxon configuration. This is supplied so that the destination can
529
		/// use information from the <code>Configuration</code> (for example, a reference to the name pool)
530
		/// to construct or configure the returned Receiver.</param>
531
		/// <returns>The receiver.</returns>
532
		public JReceiver GetReceiver(JConfiguration config)
533
		{
534
			builder.setPipelineConfiguration (config.makePipelineConfiguration());
535
			return builder;
536
		}
537
    }
538

    
539
    /// <summary>
540
    /// A <c>NullDestination</c> is an XmlDestination that discards all its output.
541
    /// </summary>
542

    
543
    public class NullDestination : XmlDestination
544
    {
545
        /// <summary>Construct a <c>NullDestination</c></summary>
546

    
547
        public NullDestination()
548
        { }
549

    
550
       
551
		/// <summary inherit="yes"/>
552
		/// Gets the receiver.
553
		/// </summary>
554
		/// <returns>The receiver.</returns>
555
		/// <param name="pipe">Pipe. The PipelineConfiguration</param>
556
		public override JReceiver GetReceiver(JPipelineConfiguration pipe)
557
        {
558
            return new JSink(pipe);
559
        }
560

    
561
    }
562

    
563
    /// <summary>
564
    /// A <c>TextWriterDestination</c> is an implementation of <c>XmlDestination</c> that wraps
565
    /// an instance of <c>XmlWriter</c>.
566
    /// </summary>
567
    /// <remarks>
568
    /// <para>The name <c>TextWriterDestination</c> is a misnomer; originally this class would
569
    /// only wrap an <c>XmlTextWriter</c>. It will now wrap any <c>XmlWriter</c>.</para>
570
    /// <para>Note that when a <c>TextWriterDestination</c> is used to process the output of a stylesheet
571
    /// or query, the output format depends only on the way the underlying <c>XmlWriter</c>
572
    /// is configured; serialization parameters present in the stylesheet or query are ignored.
573
    /// The XSLT <c>disable-output-escaping</c> option is also ignored. If serialization
574
    /// is to be controlled from the stylesheet or query, use a <c>Serializer</c> as the
575
    /// <c>Destination</c>.</para>
576
    /// </remarks>
577

    
578
    public class TextWriterDestination : XmlDestination
579
    {
580

    
581
        internal XmlWriter writer;
582
        internal bool closeAfterUse = true;
583

    
584
        /// <summary>Construct a TextWriterDestination</summary>
585
        /// <param name="writer">The <c>XmlWriter</c> that is to be notified of the events
586
        /// representing the XML document.</param>
587

    
588
        public TextWriterDestination(XmlWriter writer)
589
        {
590
            this.writer = writer;
591
        }
592

    
593
        /// <summary>
594
        /// The <c>CloseAfterUse</c> property indicates whether the underlying <c>XmlWriter</c> is closed
595
        /// (by calling its <c>Close()</c> method) when Saxon has finished writing to it. The default
596
        /// value is true, in which case <c>Close()</c> is called. If the property is set to <c>false</c>,
597
        /// Saxon will refrain from calling the <c>Close()</c> method, and merely call <c>Flush()</c>,
598
        /// which can be useful if further output is to be written to the <c>XmlWriter</c> by the application.
599
        /// </summary>
600

    
601
        public bool CloseAfterUse
602
        {
603
            get { return closeAfterUse; }
604
            set { closeAfterUse = value; }
605
        }
606

    
607
        
608
		/// <summary inherit="yes"/>
609
		/// Return a Receiver. Saxon calls this method to obtain a Java Receiver, to which it then sends
610
		/// a sequence of events representing the content of an XML document. The method is intended
611
		/// primarily for internal use, and may give poor diagnostics if used incorrectly.
612
		/// </summary>
613
		/// <returns>The receiver.</returns>
614
		/// <param name="pipe">JPipelineConfiguration. The Saxon configuration. This is supplied so that the destination can
615
		/// use information from the configuration (for example, a reference to the name pool)
616
		/// to construct or configure the returned Receiver.</param>
617
		public override JReceiver GetReceiver(JPipelineConfiguration pipe)
618
        {
619
            DotNetReceiver dnr = new DotNetReceiver(writer);
620
			dnr.setPipelineConfiguration (pipe);
621
            dnr.setCloseAfterUse(closeAfterUse);
622
            return dnr;
623
            //net.sf.saxon.@event.TracingFilter filter = new net.sf.saxon.@event.TracingFilter();
624
            //filter.setUnderlyingReceiver(dnr);
625
            //return filter;
626
        }
627

    
628
    }
629

    
630

    
631
    /// <summary>
632
    /// An <c>XdmDestination</c> is an <c>XmlDestination</c> in which an <c>XdmNode</c> 
633
    /// is constructed to hold the output of a query or transformation: 
634
    /// that is, a tree using Saxon's implementation of the XDM data model
635
    /// </summary>
636
    /// <remarks>
637
    /// <para>No data needs to be supplied to the <c>XdmDestination</c> object. The query or transformation
638
    /// populates an <c>XmlNode</c>, which may then be retrieved as the value of the <c>XmlNode</c>
639
    /// property.</para>
640
    /// <para>An <c>XdmDestination</c> can be reused to hold the results of a second transformation only
641
    /// if the <c>reset</c> method is first called to reset its state.</para>
642
    /// </remarks>
643

    
644
    public class XdmDestination : XmlDestination
645
    {
646
        internal TreeModel treeModel;
647
        internal Uri baseUri;
648
        internal JBuilder builder;
649

    
650
        /// <summary>Construct an <c>XdmDestination</c></summary>
651

    
652
        public XdmDestination()
653
        {
654
            //builder = new JTinyBuilder();
655
        }
656

    
657
        ///<summary>
658
        /// The Tree Model implementation to be used for the constructed document. By default
659
        /// the TinyTree is used. The main reason for using the LinkedTree alternative is if
660
        /// updating is required (the TinyTree is not updateable)
661
        ///</summary>
662

    
663
        public TreeModel TreeModel
664
        {
665
            get
666
            {
667
                return treeModel;
668
            }
669
            set
670
            {
671
                treeModel = value;
672
            }
673
        }
674

    
675
        /// <summary>This property determines the base URI of the constructed XdmNode. 
676
        /// If the baseURI property of the XdmDestination is set before the destination is written to,
677
        /// then the constructed XdmNode will have this base URI. Setting this property after constructing the node
678
        /// has no effect.
679
        /// </summary>
680

    
681
        public Uri BaseUri
682
        {
683
            get { return baseUri; }
684
            set { baseUri = value; }
685
        }
686

    
687

    
688
        /// <summary>Reset the state of the <c>XdmDestination</c> so that it can be used to hold
689
        /// the result of another query or transformation.</summary>
690

    
691
        public void Reset()
692
        {
693
            builder = null;
694
        }
695

    
696
        /// <summary>After construction, retrieve the constructed document node</summary>
697
        /// <remarks>
698
        /// <para>The value of the property will be null if no data has been written to the
699
        /// XdmDestination, either because the process that writes to the destination has not
700
        /// yet been run, or because the process produced no output.</para>
701
        /// </remarks>
702

    
703
        public XdmNode XdmNode
704
        {
705
            get
706
            {
707
                NodeInfo node = builder.getCurrentRoot();
708
                return (node == null ? null : (XdmNode)XdmValue.Wrap(builder.getCurrentRoot()));
709
            }
710
        }
711

    
712
		/// <summary inherit="yes"/>
713
		/// Return a Receiver. Saxon calls this method to obtain a Receiver, to which it then sends
714
		/// a sequence of events representing the content of an XML document.
715
        /// </summary>
716
        /// <returns>The receiver to which events are to be sent</returns>
717
		/// <param name="pipe">Pipe. The Saxon configuration. This is supplied so that the destination can
718
		/// use information from the configuration (for example, a reference to the name pool)
719
		/// to construct or configure the returned Receiver.</param>
720

    
721
		public override JReceiver GetReceiver(JPipelineConfiguration pipe)
722
        {
723
            builder = (treeModel == TreeModel.TinyTree ? (JBuilder)new JTinyBuilder(pipe) : (JBuilder)new JLinkedTreeBuilder(pipe));
724
            if (baseUri != null)
725
            {
726
                builder.setBaseURI(baseUri.ToString());
727
            }
728

    
729
            return new TreeProtector(builder);
730
        }
731

    
732
        /**
733
 * TreeProtector is a filter that ensures that the events reaching the Builder constitute a single
734
 * tree rooted at an element or document node (because anything else will crash the builder)
735
 */
736

    
737
        public class TreeProtector : ProxyReceiver
738
        {
739

    
740
            private int level = 0;
741
            private bool ended = false;
742

    
743
            public TreeProtector(Receiver next)
744
                : base(next)
745
            {
746

    
747
            }
748

    
749
            public override void startDocument(int properties)
750
            {
751
                if (ended)
752
                {
753
                    JXPathException e = new JXPathException("Only a single document can be written to an XdmDestination");
754
                    throw new DynamicError(e);
755
                }
756
                base.startDocument(properties);
757
                level++;
758
            }
759

    
760
            public override void endDocument()
761
            {
762
                base.endDocument();
763
                level--;
764
                if (level == 0)
765
                {
766
                    ended = true;
767
                }
768
            }
769

    
770
            public override void startElement(NodeName nameCode, JSchemaType typeCode, int locationId, int properties)
771
            {
772
                if (ended)
773
                {
774
                    JXPathException e = new JXPathException("Only a single root node can be written to an XdmDestination");
775
                    throw new DynamicError(e);
776
                }
777
                base.startElement(nameCode, typeCode, locationId, properties);
778
                level++;
779
            }
780

    
781
            public override void endElement()
782
            {
783
                base.endElement();
784
                level--;
785
                if (level == 0)
786
                {
787
                    ended = true;
788
                }
789
            }
790

    
791
            public override void characters(JCharSequence chars, int locationId, int properties)
792
            {
793
                if (level == 0)
794
                {
795
                    JXPathException e = new JXPathException("When writing to an XdmDestination, text nodes are only allowed within a document or element node");
796
                    throw new DynamicError(e);
797
                }
798
                base.characters(chars, locationId, properties);
799
            }
800

    
801

    
802
            public override void processingInstruction(String target, JCharSequence data, int locationId, int properties)
803
            {
804
                if (level == 0)
805
                {
806
                    JXPathException e = new JXPathException("When writing to an XdmDestination, processing instructions are only allowed within a document or element node");
807
                    throw new DynamicError(e);
808
                }
809
                base.processingInstruction(target, data, locationId, properties);
810
            }
811

    
812

    
813
            public override void comment(JCharSequence chars, int locationId, int properties)
814
            {
815
                if (level == 0)
816
                {
817
                    JXPathException e = new JXPathException("When writing to an XdmDestination, comment nodes are only allowed within a document or element node");
818
                }
819
                base.comment(chars, locationId, properties);
820
            }
821

    
822

    
823
            public override void append(Item item, int locationId, int copyNamespaces)
824
            {
825
                if (level == 0)
826
                {
827
                    JXPathException e = new JXPathException("When writing to an XdmDestination, atomic values are only allowed within a document or element node");
828
                }
829
                base.append(item, locationId, copyNamespaces);
830
            }
831

    
832
        }
833
    }
834

    
835

    
836
}
837

    
838
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
839
// Copyright (c) 2013 Saxonica Limited.
840
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
841
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
842
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
843
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
(2-2/13)