Project

Profile

Help

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

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

1
using System;
2
using System.IO;
3
using System.Xml;
4
using System.Collections;
5
using JConfiguration = net.sf.saxon.Configuration;
6
using JReceiver = net.sf.saxon.@event.Receiver;
7
using JProperties = java.util.Properties;
8
using JOutputStream = java.io.OutputStream;
9
using JWriter = java.io.Writer;
10
using JFileOutputStream = java.io.FileOutputStream;
11
using JXPathException = net.sf.saxon.trans.XPathException;
12
using JResult = javax.xml.transform.Result;
13
using JStreamResult = javax.xml.transform.stream.StreamResult;
14
using JTinyBuilder = net.sf.saxon.tinytree.TinyBuilder;
15
using net.sf.saxon.@event;
16
using net.sf.saxon.om;
17
using net.sf.saxon.value;
18
using net.sf.saxon.query;
19
using net.sf.saxon.dotnet;
20

    
21

    
22
namespace Saxon.Api
23
{
24

    
25

    
26

    
27
    /// <summary>
28
    /// An abstract destination for the results of a query or transformation
29
    /// </summary>
30
    /// <remarks>
31
    /// <para>Note to implementors: To implement a new kind of destination, you need
32
    /// to supply a method <c>getResult</c> which returns an implementation of
33
    /// the JAXP <c>Result</c> interface. Optionally, if the destination
34
    /// performs serialization, you can also implement <c>getOutputProperties</c>,
35
    /// which returns the properties used for serialization.
36
    /// </para>
37
    /// </remarks>
38

    
39

    
40
    public abstract class XmlDestination
41
    {
42

    
43
        /// <summary>
44
        /// Get a <c>Result</c> to which the XML document can be sent as a series
45
        /// of events.
46
        /// </summary>
47
        /// <remarks>
48
        /// This must be an implementation of the JAXP <c>Result</c> interface that is
49
        /// recognized by Saxon.
50
        /// </remarks>
51

    
52
        public abstract JResult GetResult();
53

    
54
        /// <summary>
55
        /// Get a set of <c>Properties</c> representing the parameters to the serializer.
56
        /// The default implementation returns an empty set of properties.
57
        /// </summary>
58

    
59
        public virtual JProperties GetOutputProperties()
60
        {
61
            return new JProperties();
62
        }
63

    
64
        /// <summary>
65
        /// Close the Destination, releasing any resources that need to be released.
66
        /// </summary>
67
        /// <remarks>
68
        /// This method is called by the system on completion of a query or transformation.
69
        /// Some kinds of Destination may need to close an output stream, others might
70
        /// not need to do anything. The default implementation does nothing.
71
        /// </remarks>
72

    
73
        public virtual void Close()
74
        {
75
        }
76

    
77

    
78
    }
79

    
80
    /// <summary>
81
    /// A <c>Serializer</c> takes a tree representation of XML and turns
82
    /// it into lexical XML markup.
83
    /// </summary>
84
    /// <remarks>
85
    /// Note that this is serialization in the sense of the W3C XSLT and XQuery specifications.
86
    /// Unlike the class <c>System.Xml.Serialization.XmlSerializer</c>, this object does not
87
    /// serialize arbitrary CLI objects.
88
    /// </remarks>
89

    
90
    public class Serializer : XmlDestination
91
    {
92

    
93
        private JProperties props = new JProperties();
94
        private JOutputStream outputStream = null;
95
        private JWriter writer = null;
96
        private bool mustClose = true;
97

    
98

    
99
        /// <summary>QName identifying the serialization parameter "method". If the method
100
        /// is a user-defined method, then it is given as a QName in Clark notation, that is
101
        /// "{uri}local".</summary>
102

    
103
        public static readonly QName METHOD =
104
            new QName("", "method");
105

    
106
        /// <summary>QName identifying the serialization parameter "byte-order-mark"</summary>
107

    
108
        public static readonly QName BYTE_ORDER_MARK =
109
            new QName("", "byte-order-mark");
110

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

    
115
        public static readonly QName CDATA_SECTION_ELEMENTS =
116
            new QName("", "cdata-section-elements");
117

    
118
        /// <summary>QName identifying the serialization parameter "doctype-public"</summary>
119

    
120
        public static readonly QName DOCTYPE_PUBLIC =
121
            new QName("", "doctype-public");
122

    
123
        /// <summary>QName identifying the serialization parameter "doctype-system"</summary>
124

    
125
        public static readonly QName DOCTYPE_SYSTEM =
126
            new QName("", "doctype-system");
127

    
128
        /// <summary>QName identifying the serialization parameter "encoding"</summary>
129

    
130
        public static readonly QName ENCODING =
131
            new QName("", "encoding");
132

    
133
        /// <summary>QName identifying the serialization parameter "escape-uri-attributes".
134
        /// The value is the string "yes" or "no".</summary>
135

    
136
        public static readonly QName ESCAPE_URI_ATTRIBUTES =
137
            new QName("", "escape-uri-attributes");
138

    
139
        /// <summary>QName identifying the serialization parameter "include-content-type".
140
        /// The value is the string "yes" or "no".</summary>
141

    
142
        public static readonly QName INCLUDE_CONTENT_TYPE =
143
            new QName("", "include-content-type");
144

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

    
148
        public static readonly QName INDENT =
149
            new QName("", "indent");
150

    
151
        /// <summary>QName identifying the serialization parameter "media-type".</summary>
152

    
153
        public static readonly QName MEDIA_TYPE =
154
            new QName("", "media-type");
155

    
156
        /// <summary>QName identifying the serialization parameter "normalization-form"</summary>
157

    
158
        public static readonly QName NORMALIZATION_FORM =
159
            new QName("", "normalization-form");
160

    
161
        /// <summary>QName identifying the serialization parameter "omit-xml-declaration".
162
        /// The value is the string "yes" or "no".</summary>
163

    
164
        public static readonly QName OMIT_XML_DECLARATION =
165
            new QName("", "omit-xml-declaration");
166

    
167
        /// <summary>QName identifying the serialization parameter "standalone".
168
        /// The value is the string "yes" or "no" or "omit".</summary>
169

    
170
        public static readonly QName STANDALONE =
171
            new QName("", "standalone");
172

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

    
176
        public static readonly QName UNDECLARE_PREFIXES =
177
            new QName("", "undeclare-prefixes");
178

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

    
183
        public static readonly QName USE_CHARACTER_MAPS =
184
            new QName("", "use-character-maps");
185

    
186
        /// <summary>QName identifying the serialization parameter "version"</summary>
187

    
188
        public static readonly QName VERSION =
189
            new QName("", "version");
190

    
191
        private const String SAXON = NamespaceConstant.SAXON;
192

    
193

    
194
        /// <summary>QName identifying the serialization parameter "saxon:character-representation"</summary>
195

    
196

    
197
        public static readonly QName SAXON_CHARACTER_REPRESENTATION =
198
            new QName(SAXON, "saxon:character-representation");
199

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

    
204
        public static readonly QName SAXON_INDENT_SPACES =
205
            new QName(SAXON, "saxon:indent-spaces");
206

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

    
212
        public static readonly QName SAXON_DOUBLE_SPACE =
213
            new QName(SAXON, "saxon:double-space");
214

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

    
220
        public static readonly QName SAXON_SUPPRESS_INDENTATION =
221
            new QName(SAXON, "saxon:suppress-indentation");
222

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

    
227
        public static readonly QName NEXT_IN_CHAIN =
228
            new QName(SAXON, "saxon:next-in-chain");
229

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

    
236
        public static readonly QName SAXON_REQUIRE_WELL_FORMED =
237
            new QName(SAXON, "saxon:require-well-formed");
238

    
239

    
240
        /// <summary>Create a Serializer</summary>
241

    
242
        public Serializer()
243
        {
244
        }
245

    
246
        /// <summary>Set a serialization property</summary>
247
        /// <remarks>In the case of XSLT, properties set within the serializer override
248
        /// any properties set in <c>xsl:output</c> declarations in the stylesheet.
249
        /// Similarly, with XQuery, they override any properties set in the Query
250
        /// prolog using <c>declare option saxon:output</c>.</remarks>
251
        /// <example>
252
        ///   <code>
253
        ///     Serializer qout = new Serializer();
254
        ///     qout.SetOutputProperty(Serializer.METHOD, "xml");
255
        ///     qout.SetOutputProperty(Serializer.INDENT, "yes");
256
        ///     qout.SetOutputProperty(Serializer.SAXON_INDENT_SPACES, "1");
257
        ///   </code>
258
        /// </example> 
259
        /// <param name="name">The name of the serialization property to be set</param>
260
        /// <param name="value">The value to be set for the serialization property. May be null
261
        /// to unset the property (that is, to set it back to the default value).</param>
262

    
263
        public void SetOutputProperty(QName name, String value)
264
        {
265
            props.setProperty(name.ClarkName, value);
266
        }
267

    
268
        /// <summary>Specify the destination of the serialized output, in the
269
        /// form of a file name</summary>
270
        /// <param name="filename">The name of the file to receive the serialized output</param>
271
        /// <exception>Throws a <c>DynamicError</c> if it is not possible to create an output
272
        /// stream to write to this file, for example, if the filename is in a directory
273
        /// that does not exist.</exception>
274

    
275
        public void SetOutputFile(String filename)
276
        {
277
            try
278
            {
279
                outputStream = new JFileOutputStream(filename);
280
                mustClose = true;
281
            }
282
            catch (java.io.IOException err)
283
            {
284
                JXPathException e = new JXPathException(err);
285
                throw new DynamicError(e);
286
            }
287
        }
288

    
289
        /// <summary>Specify the destination of the serialized output, in the
290
        /// form of a <c>Stream</c></summary>
291
        /// <remarks>Saxon will not close the stream on completion; this is the
292
        /// caller's responsibility.</remarks>
293
        /// <param name="stream">The stream to which the output will be written.
294
        /// This must be a stream that allows writing.</param>
295

    
296
        public void SetOutputStream(Stream stream)
297
        {
298
            outputStream = new DotNetOutputStream(stream);
299
            mustClose = false;
300
        }
301

    
302
        /// <summary>Specify the destination of the serialized output, in the
303
        /// form of a <c>TextWriter</c></summary>
304
        /// <remarks>Note that when writing to a <c>TextWriter</c>, character encoding is
305
        /// the responsibility of the <c>TextWriter</c>, not the <c>Serializer</c>. This
306
        /// means that the encoding requested in the output properties is ignored; it also
307
        /// means that characters that cannot be represented in the target encoding will
308
        /// use whatever fallback representation the <c>TextWriter</c> defines, rather than
309
        /// being represented as XML character references.</remarks>
310
        /// <param name="textWriter">The stream to which the output will be written.
311
        /// This must be a stream that allows writing. Saxon will not close the
312
        /// <c>textWriter</c> on completion; this is the caller's responsibility.</param>
313

    
314
        public void SetOutputWriter(TextWriter textWriter)
315
        {
316
            writer = new DotNetWriter(textWriter);
317
            mustClose = false;
318
        }
319

    
320
        internal JReceiver GetReceiver(JConfiguration config)
321
        {
322
            return config.getSerializerFactory().getReceiver(
323
                    GetResult(),
324
                    config.makePipelineConfiguration(),
325
                    GetOutputProperties());
326

    
327
        }
328

    
329

    
330
        /// <summary inherit="yes"/>
331

    
332
        public override JResult GetResult()
333
        {
334
            if (outputStream != null)
335
            {
336
                return new JStreamResult(outputStream);
337
            }
338
            else if (writer != null)
339
            {
340
                return new JStreamResult(writer);
341
            }
342
            else
343
            {
344
                return new JStreamResult(new DotNetWriter(Console.Out));
345
            }
346
        }
347

    
348
        /// <summary inherit="yes"/>
349

    
350
        public override JProperties GetOutputProperties()
351
        {
352
            return props;
353
        }
354

    
355
        /// <summary inherit="yes"/>
356

    
357
        public override void Close()
358
        {
359
            if (mustClose)
360
            {
361
                if (outputStream != null)
362
                {
363
                    outputStream.close();
364
                }
365
                if (writer != null)
366
                {
367
                    writer.close();
368
                }
369
            }
370
        }
371
    }
372

    
373
    /// <summary>
374
    /// A <c>DomDestination</c> represents an XmlDocument that is constructed to hold the
375
    /// output of a query or transformation.
376
    /// </summary>
377
    /// <remarks>
378
    /// No data needs to be supplied to the <c>DomDestination</c> object. The query or transformation
379
    /// populates an <c>XmlDocument</c>, which may then be retrieved as the value of the <c>XmlDocument</c>
380
    /// property
381
    /// </remarks>
382

    
383
    public class DomDestination : XmlDestination
384
    {
385

    
386
        internal DotNetDomBuilder builder;
387

    
388
        /// <summary>Construct a <c>DomDestination</c></summary>
389
        /// <remarks>With this constructor, the system will create a new DOM Document
390
        /// to act as the destination of the query or transformation results. The document
391
        /// node of the new document may be retrieved via the XmlDocument property.</remarks>
392

    
393
        public DomDestination()
394
        {
395
            builder = new DotNetDomBuilder();
396
        }
397

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

    
404
        public DomDestination(XmlDocument attachmentPoint)
405
        {
406
            builder = new DotNetDomBuilder();
407
            builder.setAttachmentPoint(attachmentPoint);
408
        }
409

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

    
415
        public DomDestination(XmlDocumentFragment attachmentPoint)
416
        {
417
            builder = new DotNetDomBuilder();
418
            builder.setAttachmentPoint(attachmentPoint);
419
        }
420

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

    
426
        public DomDestination(XmlElement attachmentPoint)
427
        {
428
            builder = new DotNetDomBuilder();
429
            builder.setAttachmentPoint(attachmentPoint);
430
        }
431

    
432
        /// <summary>After construction, retrieve the constructed document node</summary>
433
        /// <remarks>If the zero-argument constructor was used, this will be a newly
434
        /// constructed document node. If the constructor supplied a document node, the
435
        /// same document node will be returned. If the constructor supplied a document fragment
436
        /// node or an element node, this method returns the <c>OwnerDocument</c> property of 
437
        /// that node.</remarks>
438

    
439
        public XmlDocument XmlDocument
440
        {
441
            get { return builder.getDocumentNode(); }
442
        }
443

    
444
        /// <summary inherit="yes"/>
445

    
446
        public override JResult GetResult()
447
        {
448
            return builder;
449
        }
450
    }
451

    
452
    /// <summary>
453
    /// A <c>NullDestination</c> is an XmlDestination that discards all its output.
454
    /// </summary>
455

    
456
    public class NullDestination : XmlDestination
457
    {
458
        /// <summary>Construct a <c>NullDestination</c></summary>
459

    
460
        public NullDestination()
461
        {}
462

    
463
        /// <summary inherit="yes"/>
464

    
465
        public override JResult GetResult()
466
        {
467
            return new net.sf.saxon.@event.Sink();
468
        }
469
    }
470

    
471
    /// <summary>
472
    /// A <c>TextWriterDestination</c> is an implementation of <c>XmlDestination</c> that wraps
473
    /// an instance of <c>XmlWriter</c>.
474
    /// </summary>
475
    /// <remarks>
476
    /// <para>The name <c>TextWriterDestination</c> is a misnomer; originally this class would
477
    /// only wrap an <c>XmlTextWriter</c>. It will now wrap any <c>XmlWriter</c>.</para>
478
    /// <para>Note that when a <c>TextWriterDestination</c> is used to process the output of a stylesheet
479
    /// or query, the output format depends only on the way the underlying <c>XmlWriter</c>
480
    /// is configured; serialization parameters present in the stylesheet or query are ignored.</para>
481
    /// </remarks>
482

    
483
    public class TextWriterDestination : XmlDestination
484
    {
485

    
486
        internal XmlWriter writer;
487

    
488
        /// <summary>Construct a TextWriterDestination</summary>
489
        /// <param name="writer">The <c>XmlWriter</c> that is to be notified of the events
490
        /// representing the XML document.</param>
491

    
492
        public TextWriterDestination(XmlWriter writer)
493
        {
494
            this.writer = writer;
495
        }
496

    
497
        /// <summary inherit="yes"/>
498

    
499
        public override JResult GetResult()
500
        {
501
            DotNetReceiver dnr = new DotNetReceiver(writer);
502
            return dnr;
503
            //net.sf.saxon.@event.TracingFilter filter = new net.sf.saxon.@event.TracingFilter();
504
            //filter.setUnderlyingReceiver(dnr);
505
            //return filter;
506
        }
507
    }
508

    
509

    
510
    /// <summary>
511
    /// An <c>XdmDestination</c> is an <c>XmlDestination</c> in which an <c>XdmNode</c> 
512
    /// is constructed to hold the output of a query or transformation: 
513
    /// that is, a tree using Saxon's implementation of the XDM data model
514
    /// </summary>
515
    /// <remarks>
516
    /// <para>No data needs to be supplied to the <c>XdmDestination</c> object. The query or transformation
517
    /// populates an <c>XmlNode</c>, which may then be retrieved as the value of the <c>XmlNode</c>
518
    /// property.</para>
519
    /// <para>An <c>XdmDestination</c> can be reused to hold the results of a second transformation only
520
    /// if the <c>reset</c> method is first called to reset its state.</para>
521
    /// </remarks>
522

    
523
    public class XdmDestination : XmlDestination
524
    {
525

    
526
        internal JTinyBuilder builder;
527

    
528
        /// <summary>Construct an <c>XdmDestination</c></summary>
529

    
530
        public XdmDestination()
531
        {
532
            builder = new JTinyBuilder();
533
        }
534

    
535
        /// <summary>This property determines the base URI of the constructed XdmNode. 
536
        /// If the baseURI property of the XdmDestination is set before the destination is written to,
537
        /// then the constructed XdmNode will have this base URI. Setting this property after constructing the node
538
        /// has no effect.
539
        /// </summary>
540

    
541
        public Uri BaseUri
542
        {
543
            get { return new Uri(builder.getBaseURI()); }
544
            set { builder.setBaseURI(value.ToString()); }
545
        }
546

    
547

    
548
        /// <summary>Reset the state of the <c>XdmDestination</c> so that it can be used to hold
549
        /// the result of another transformation.</summary>
550

    
551
        public void Reset()
552
        {
553
            builder = new JTinyBuilder();
554
        }
555

    
556
        /// <summary>After construction, retrieve the constructed document node</summary>
557
        /// <remarks>
558
        /// <para>The value of the property will be null if no data has been written to the
559
        /// XdmDestination, either because the process that writes to the destination has not
560
        /// yet been run, or because the process produced no output.</para>
561
        /// </remarks>
562

    
563
        public XdmNode XdmNode
564
        {
565
            get
566
            {
567
                NodeInfo node = builder.getCurrentRoot();
568
                return (node == null ? null : (XdmNode)XdmValue.Wrap(builder.getCurrentRoot()));
569
            }
570
        }
571

    
572
        /// <summary inherit="yes"/>
573

    
574
        public override JResult GetResult()
575
        {
576
            return builder;
577
        }
578
    }
579

    
580

    
581
}
582

    
583
//
584
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
585
// you may not use this file except in compliance with the License. You may obtain a copy of the
586
// License at http://www.mozilla.org/MPL/
587
//
588
// Software distributed under the License is distributed on an "AS IS" basis,
589
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
590
// See the License for the specific language governing rights and limitations under the License.
591
//
592
// The Original Code is: all this file.
593
//
594
// The Initial Developer of the Original Code is Michael H. Kay.
595
//
596
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
597
//
598
// Contributor(s): none.
599
//
(2-2/8)