aboutsummaryrefslogtreecommitdiff
path: root/src/com/sun/org/apache/xalan/internal/xsltc/runtime/AbstractTranslet.java
blob: 9eddf5ce423e508ecf61f5248e1a8e954350f4b6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
/*
 * reserved comment block
 * DO NOT REMOVE OR ALTER!
 */
/*
 * Copyright 2001-2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*
 * $Id: AbstractTranslet.java,v 1.6 2006/06/19 19:49:03 spericas Exp $
 */

package com.sun.org.apache.xalan.internal.xsltc.runtime;

import com.sun.org.apache.xalan.internal.XalanConstants;
import com.sun.org.apache.xalan.internal.utils.FactoryImpl;
import java.io.File;
import java.io.FileOutputStream;
import java.io.BufferedOutputStream;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Vector;
import javax.xml.transform.Templates;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.DOMImplementation;
import javax.xml.parsers.ParserConfigurationException;

import com.sun.org.apache.xml.internal.dtm.DTM;

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.DOMCache;
import com.sun.org.apache.xalan.internal.xsltc.DOMEnhancedForDTM;
import com.sun.org.apache.xalan.internal.xsltc.Translet;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.dom.DOMAdapter;
import com.sun.org.apache.xalan.internal.xsltc.dom.KeyIndex;
import com.sun.org.apache.xalan.internal.xsltc.runtime.output.TransletOutputHandlerFactory;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;

/**
 * @author Jacek Ambroziak
 * @author Santiago Pericas-Geertsen
 * @author Morten Jorgensen
 * @author G. Todd Miller
 * @author John Howard, JohnH@schemasoft.com
 */
public abstract class AbstractTranslet implements Translet {

    // These attributes are extracted from the xsl:output element. They also
    // appear as fields (with the same type, only public) in Output.java
    public String  _version = "1.0";
    public String  _method = null;
    public String  _encoding = "UTF-8";
    public boolean _omitHeader = false;
    public String  _standalone = null;
    //see OutputPropertiesFactory.ORACLE_IS_STANDALONE
    public boolean  _isStandalone = false;
    public String  _doctypePublic = null;
    public String  _doctypeSystem = null;
    public boolean _indent = false;
    public String  _mediaType = null;
    public Vector _cdata = null;
    public int _indentamount = -1;

    public static final int FIRST_TRANSLET_VERSION = 100;
    public static final int VER_SPLIT_NAMES_ARRAY = 101;
    public static final int CURRENT_TRANSLET_VERSION = VER_SPLIT_NAMES_ARRAY;

    // Initialize Translet version field to base value.  A class that extends
    // AbstractTranslet may override this value to a more recent translet
    // version; if it doesn't override the value (because it was compiled
    // before the notion of a translet version was introduced, it will get
    // this default value).
    protected int transletVersion = FIRST_TRANSLET_VERSION;

    // DOM/translet handshaking - the arrays are set by the compiled translet
    protected String[] namesArray;
    protected String[] urisArray;
    protected int[]    typesArray;
    protected String[] namespaceArray;

    // The Templates object that is used to create this Translet instance
    protected Templates _templates = null;

    // Boolean flag to indicate whether this translet has id functions.
    protected boolean _hasIdCall = false;

    // TODO - these should only be instanciated when needed
    protected StringValueHandler stringValueHandler = new StringValueHandler();

    // Use one empty string instead of constantly instanciating String("");
    private final static String EMPTYSTRING = "";

    // This is the name of the index used for ID attributes
    private final static String ID_INDEX_NAME = "##id";

    private boolean _useServicesMechanism;

    /**
     * protocols allowed for external references set by the stylesheet processing instruction, Document() function, Import and Include element.
     */
    private String _accessExternalStylesheet = XalanConstants.EXTERNAL_ACCESS_DEFAULT;

    /************************************************************************
     * Debugging
     ************************************************************************/
    public void printInternalState() {
        System.out.println("-------------------------------------");
        System.out.println("AbstractTranslet this = " + this);
        System.out.println("pbase = " + pbase);
        System.out.println("vframe = " + pframe);
        System.out.println("paramsStack.size() = " + paramsStack.size());
        System.out.println("namesArray.size = " + namesArray.length);
        System.out.println("namespaceArray.size = " + namespaceArray.length);
        System.out.println("");
        System.out.println("Total memory = " + Runtime.getRuntime().totalMemory());
    }

    /**
     * Wrap the initial input DOM in a dom adapter. This adapter is wrapped in
     * a DOM multiplexer if the document() function is used (handled by compiled
     * code in the translet - see compiler/Stylesheet.compileTransform()).
     */
    public final DOMAdapter makeDOMAdapter(DOM dom)
        throws TransletException {
        setRootForKeys(dom.getDocument());
        return new DOMAdapter(dom, namesArray, urisArray, typesArray, namespaceArray);
    }

    /************************************************************************
     * Parameter handling
     ************************************************************************/

    // Parameter's stack: <tt>pbase</tt> and <tt>pframe</tt> are used
    // to denote the current parameter frame.
    protected int pbase = 0, pframe = 0;
    protected ArrayList paramsStack = new ArrayList();

    /**
     * Push a new parameter frame.
     */
    public final void pushParamFrame() {
        paramsStack.add(pframe, new Integer(pbase));
        pbase = ++pframe;
    }

    /**
     * Pop the topmost parameter frame.
     */
    public final void popParamFrame() {
        if (pbase > 0) {
            final int oldpbase = ((Integer)paramsStack.get(--pbase)).intValue();
            for (int i = pframe - 1; i >= pbase; i--) {
                paramsStack.remove(i);
            }
            pframe = pbase; pbase = oldpbase;
        }
    }

    /**
     * Add a new global parameter if not already in the current frame.
     * To setParameters of the form {http://foo.bar}xyz
     * This needs to get mapped to an instance variable in the class
     * The mapping  created so that
     * the global variables in the generated class become
     * http$colon$$flash$$flash$foo$dot$bar$colon$xyz
     */
    public final Object addParameter(String name, Object value) {
        name = BasisLibrary.mapQNameToJavaName (name);
        return addParameter(name, value, false);
    }

    /**
     * Add a new global or local parameter if not already in the current frame.
     * The 'isDefault' parameter is set to true if the value passed is the
     * default value from the <xsl:parameter> element's select attribute or
     * element body.
     */
    public final Object addParameter(String name, Object value,
        boolean isDefault)
    {
        // Local parameters need to be re-evaluated for each iteration
        for (int i = pframe - 1; i >= pbase; i--) {
            final Parameter param = (Parameter) paramsStack.get(i);

            if (param._name.equals(name)) {
                // Only overwrite if current value is the default value and
                // the new value is _NOT_ the default value.
                if (param._isDefault || !isDefault) {
                    param._value = value;
                    param._isDefault = isDefault;
                    return value;
                }
                return param._value;
            }
        }

        // Add new parameter to parameter stack
        paramsStack.add(pframe++, new Parameter(name, value, isDefault));
        return value;
    }

    /**
     * Clears the parameter stack.
     */
    public void clearParameters() {
        pbase = pframe = 0;
        paramsStack.clear();
    }

    /**
     * Get the value of a parameter from the current frame or
     * <tt>null</tt> if undefined.
     */
    public final Object getParameter(String name) {

        name = BasisLibrary.mapQNameToJavaName (name);

        for (int i = pframe - 1; i >= pbase; i--) {
            final Parameter param = (Parameter)paramsStack.get(i);
            if (param._name.equals(name)) return param._value;
        }
        return null;
    }

    /************************************************************************
     * Message handling - implementation of <xsl:message>
     ************************************************************************/

    // Holds the translet's message handler - used for <xsl:message>.
    // The deault message handler dumps a string stdout, but anything can be
    // used, such as a dialog box for applets, etc.
    private MessageHandler _msgHandler = null;

    /**
     * Set the translet's message handler - must implement MessageHandler
     */
    public final void setMessageHandler(MessageHandler handler) {
        _msgHandler = handler;
    }

    /**
     * Pass a message to the message handler - used by Message class.
     */
    public final void displayMessage(String msg) {
        if (_msgHandler == null) {
            System.err.println(msg);
        }
        else {
            _msgHandler.displayMessage(msg);
        }
    }

    /************************************************************************
     * Decimal number format symbol handling
     ************************************************************************/

    // Contains decimal number formatting symbols used by FormatNumberCall
    public Hashtable _formatSymbols = null;

    /**
     * Adds a DecimalFormat object to the _formatSymbols hashtable.
     * The entry is created with the input DecimalFormatSymbols.
     */
    public void addDecimalFormat(String name, DecimalFormatSymbols symbols) {
        // Instanciate hashtable for formatting symbols if needed
        if (_formatSymbols == null) _formatSymbols = new Hashtable();

        // The name cannot be null - use empty string instead
        if (name == null) name = EMPTYSTRING;

        // Construct a DecimalFormat object containing the symbols we got
        final DecimalFormat df = new DecimalFormat();
        if (symbols != null) {
            df.setDecimalFormatSymbols(symbols);
        }
        _formatSymbols.put(name, df);
    }

    /**
     * Retrieves a named DecimalFormat object from _formatSymbols hashtable.
     */
    public final DecimalFormat getDecimalFormat(String name) {

        if (_formatSymbols != null) {
            // The name cannot be null - use empty string instead
            if (name == null) name = EMPTYSTRING;

            DecimalFormat df = (DecimalFormat)_formatSymbols.get(name);
            if (df == null) df = (DecimalFormat)_formatSymbols.get(EMPTYSTRING);
            return df;
        }
        return(null);
    }

    /**
     * Give the translet an opportunity to perform a prepass on the document
     * to extract any information that it can store in an optimized form.
     *
     * Currently, it only extracts information about attributes of type ID.
     */
    public final void prepassDocument(DOM document) {
        setIndexSize(document.getSize());
        buildIDIndex(document);
    }

    /**
     * Leverages the Key Class to implement the XSLT id() function.
     * buildIdIndex creates the index (##id) that Key Class uses.
     * The index contains the element node index (int) and Id value (String).
     */
    private final void buildIDIndex(DOM document) {
        setRootForKeys(document.getDocument());

        if (document instanceof DOMEnhancedForDTM) {
            DOMEnhancedForDTM enhancedDOM = (DOMEnhancedForDTM)document;

            // If the input source is DOMSource, the KeyIndex table is not
            // built at this time. It will be built later by the lookupId()
            // and containsId() methods of the KeyIndex class.
            if (enhancedDOM.hasDOMSource()) {
                buildKeyIndex(ID_INDEX_NAME, document);
                return;
            }
            else {
                final Hashtable elementsByID = enhancedDOM.getElementsWithIDs();

                if (elementsByID == null) {
                    return;
                }

                // Given a Hashtable of DTM nodes indexed by ID attribute values,
                // loop through the table copying information to a KeyIndex
                // for the mapping from ID attribute value to DTM node
                final Enumeration idValues = elementsByID.keys();
                boolean hasIDValues = false;

                while (idValues.hasMoreElements()) {
                    final Object idValue = idValues.nextElement();
                    final int element =
                            document.getNodeHandle(
                                        ((Integer)elementsByID.get(idValue))
                                                .intValue());

                    buildKeyIndex(ID_INDEX_NAME, element, idValue);
                    hasIDValues = true;
                }

                if (hasIDValues) {
                    setKeyIndexDom(ID_INDEX_NAME, document);
                }
            }
        }
    }

    /**
     * After constructing the translet object, this method must be called to
     * perform any version-specific post-initialization that's required.
     */
    public final void postInitialization() {
        // If the version of the translet had just one namesArray, split
        // it into multiple fields.
        if (transletVersion < VER_SPLIT_NAMES_ARRAY) {
            int arraySize = namesArray.length;
            String[] newURIsArray = new String[arraySize];
            String[] newNamesArray = new String[arraySize];
            int[] newTypesArray = new int[arraySize];

            for (int i = 0; i < arraySize; i++) {
                String name = namesArray[i];
                int colonIndex = name.lastIndexOf(':');
                int lNameStartIdx = colonIndex+1;

                if (colonIndex > -1) {
                    newURIsArray[i] = name.substring(0, colonIndex);
                }

               // Distinguish attribute and element names.  Attribute has
               // @ before local part of name.
               if (name.charAt(lNameStartIdx) == '@') {
                   lNameStartIdx++;
                   newTypesArray[i] = DTM.ATTRIBUTE_NODE;
               } else if (name.charAt(lNameStartIdx) == '?') {
                   lNameStartIdx++;
                   newTypesArray[i] = DTM.NAMESPACE_NODE;
               } else {
                   newTypesArray[i] = DTM.ELEMENT_NODE;
               }
               newNamesArray[i] =
                          (lNameStartIdx == 0) ? name
                                               : name.substring(lNameStartIdx);
            }

            namesArray = newNamesArray;
            urisArray  = newURIsArray;
            typesArray = newTypesArray;
        }

        // Was translet compiled using a more recent version of the XSLTC
        // compiler than is known by the AbstractTranslet class?  If, so
        // and we've made it this far (which is doubtful), we should give up.
        if (transletVersion > CURRENT_TRANSLET_VERSION) {
            BasisLibrary.runTimeError(BasisLibrary.UNKNOWN_TRANSLET_VERSION_ERR,
                                      this.getClass().getName());
        }
    }

    /************************************************************************
     * Index(es) for <xsl:key> / key() / id()
     ************************************************************************/

    // Container for all indexes for xsl:key elements
    private Hashtable _keyIndexes = null;
    private KeyIndex  _emptyKeyIndex = null;
    private int       _indexSize = 0;
    private int       _currentRootForKeys = 0;

    /**
     * This method is used to pass the largest DOM size to the translet.
     * Needed to make sure that the translet can index the whole DOM.
     */
    public void setIndexSize(int size) {
        if (size > _indexSize) _indexSize = size;
    }

    /**
     * Creates a KeyIndex object of the desired size - don't want to resize!!!
     */
    public KeyIndex createKeyIndex() {
        return(new KeyIndex(_indexSize));
    }

    /**
     * Adds a value to a key/id index
     *   @param name is the name of the index (the key or ##id)
     *   @param node is the node handle of the node to insert
     *   @param value is the value that will look up the node in the given index
     */
    public void buildKeyIndex(String name, int node, Object value) {
        if (_keyIndexes == null) _keyIndexes = new Hashtable();

        KeyIndex index = (KeyIndex)_keyIndexes.get(name);
        if (index == null) {
            _keyIndexes.put(name, index = new KeyIndex(_indexSize));
        }
        index.add(value, node, _currentRootForKeys);
    }

    /**
     * Create an empty KeyIndex in the DOM case
     *   @param name is the name of the index (the key or ##id)
     *   @param dom is the DOM
     */
    public void buildKeyIndex(String name, DOM dom) {
        if (_keyIndexes == null) _keyIndexes = new Hashtable();

        KeyIndex index = (KeyIndex)_keyIndexes.get(name);
        if (index == null) {
            _keyIndexes.put(name, index = new KeyIndex(_indexSize));
        }
        index.setDom(dom, dom.getDocument());
    }

    /**
     * Returns the index for a given key (or id).
     * The index implements our internal iterator interface
     */
    public KeyIndex getKeyIndex(String name) {
        // Return an empty key index iterator if none are defined
        if (_keyIndexes == null) {
            return (_emptyKeyIndex != null)
                ? _emptyKeyIndex
                : (_emptyKeyIndex = new KeyIndex(1));
        }

        // Look up the requested key index
        final KeyIndex index = (KeyIndex)_keyIndexes.get(name);

        // Return an empty key index iterator if the requested index not found
        if (index == null) {
            return (_emptyKeyIndex != null)
                ? _emptyKeyIndex
                : (_emptyKeyIndex = new KeyIndex(1));
        }

        return(index);
    }

    private void setRootForKeys(int root) {
        _currentRootForKeys = root;
    }

    /**
     * This method builds key indexes - it is overridden in the compiled
     * translet in cases where the <xsl:key> element is used
     */
    public void buildKeys(DOM document, DTMAxisIterator iterator,
                          SerializationHandler handler,
                          int root) throws TransletException {

    }

    /**
     * This method builds key indexes - it is overridden in the compiled
     * translet in cases where the <xsl:key> element is used
     */
    public void setKeyIndexDom(String name, DOM document) {
        getKeyIndex(name).setDom(document, document.getDocument());
    }

    /************************************************************************
     * DOM cache handling
     ************************************************************************/

    // Hold the DOM cache (if any) used with this translet
    private DOMCache _domCache = null;

    /**
     * Sets the DOM cache used for additional documents loaded using the
     * document() function.
     */
    public void setDOMCache(DOMCache cache) {
        _domCache = cache;
    }

    /**
     * Returns the DOM cache used for this translet. Used by the LoadDocument
     * class (if present) when the document() function is used.
     */
    public DOMCache getDOMCache() {
        return(_domCache);
    }

    /************************************************************************
     * Multiple output document extension.
     * See compiler/TransletOutput for actual implementation.
     ************************************************************************/

    public SerializationHandler openOutputHandler(String filename, boolean append)
        throws TransletException
    {
        try {
            final TransletOutputHandlerFactory factory
                = TransletOutputHandlerFactory.newInstance();

            String dirStr = new File(filename).getParent();
            if ((null != dirStr) && (dirStr.length() > 0)) {
               File dir = new File(dirStr);
               dir.mkdirs();
            }

            factory.setEncoding(_encoding);
            factory.setOutputMethod(_method);
            factory.setOutputStream(new BufferedOutputStream(new FileOutputStream(filename, append)));
            factory.setOutputType(TransletOutputHandlerFactory.STREAM);

            final SerializationHandler handler
                = factory.getSerializationHandler();

            transferOutputSettings(handler);
            handler.startDocument();
            return handler;
        }
        catch (Exception e) {
            throw new TransletException(e);
        }
    }

    public SerializationHandler openOutputHandler(String filename)
       throws TransletException
    {
       return openOutputHandler(filename, false);
    }

    public void closeOutputHandler(SerializationHandler handler) {
        try {
            handler.endDocument();
            handler.close();
        }
        catch (Exception e) {
            // what can you do?
        }
    }

    /************************************************************************
     * Native API transformation methods - _NOT_ JAXP/TrAX
     ************************************************************************/

    /**
     * Main transform() method - this is overridden by the compiled translet
     */
    public abstract void transform(DOM document, DTMAxisIterator iterator,
                                   SerializationHandler handler)
        throws TransletException;

    /**
     * Calls transform() with a given output handler
     */
    public final void transform(DOM document, SerializationHandler handler)
        throws TransletException {
        try {
            transform(document, document.getIterator(), handler);
        } finally {
            _keyIndexes = null;
        }
    }

    /**
     * Used by some compiled code as a shortcut for passing strings to the
     * output handler
     */
    public final void characters(final String string,
                                 SerializationHandler handler)
        throws TransletException {
        if (string != null) {
           //final int length = string.length();
           try {
               handler.characters(string);
           } catch (Exception e) {
               throw new TransletException(e);
           }
        }
    }

    /**
     * Add's a name of an element whose text contents should be output as CDATA
     */
    public void addCdataElement(String name) {
        if (_cdata == null) {
            _cdata = new Vector();
        }

        int lastColon = name.lastIndexOf(':');

        if (lastColon > 0) {
            String uri = name.substring(0, lastColon);
            String localName = name.substring(lastColon+1);
            _cdata.addElement(uri);
            _cdata.addElement(localName);
        } else {
            _cdata.addElement(null);
            _cdata.addElement(name);
        }
    }

    /**
     * Transfer the output settings to the output post-processor
     */
    protected void transferOutputSettings(SerializationHandler handler) {
        if (_method != null) {
            if (_method.equals("xml")) {
                if (_standalone != null) {
                    handler.setStandalone(_standalone);
                }
                if (_omitHeader) {
                    handler.setOmitXMLDeclaration(true);
                }
                handler.setCdataSectionElements(_cdata);
                if (_version != null) {
                    handler.setVersion(_version);
                }
                handler.setIndent(_indent);
                handler.setIndentAmount(_indentamount);
                if (_doctypeSystem != null) {
                    handler.setDoctype(_doctypeSystem, _doctypePublic);
                }
                handler.setIsStandalone(_isStandalone);
            }
            else if (_method.equals("html")) {
                handler.setIndent(_indent);
                handler.setDoctype(_doctypeSystem, _doctypePublic);
                if (_mediaType != null) {
                    handler.setMediaType(_mediaType);
                }
            }
        }
        else {
            handler.setCdataSectionElements(_cdata);
            if (_version != null) {
                handler.setVersion(_version);
            }
            if (_standalone != null) {
                handler.setStandalone(_standalone);
            }
            if (_omitHeader) {
                handler.setOmitXMLDeclaration(true);
            }
            handler.setIndent(_indent);
            handler.setDoctype(_doctypeSystem, _doctypePublic);
            handler.setIsStandalone(_isStandalone);
        }
    }

    private Hashtable _auxClasses = null;

    public void addAuxiliaryClass(Class auxClass) {
        if (_auxClasses == null) _auxClasses = new Hashtable();
        _auxClasses.put(auxClass.getName(), auxClass);
    }

    public void setAuxiliaryClasses(Hashtable auxClasses) {
        _auxClasses = auxClasses;
    }

    public Class getAuxiliaryClass(String className) {
        if (_auxClasses == null) return null;
        return((Class)_auxClasses.get(className));
    }

    // GTM added (see pg 110)
    public String[] getNamesArray() {
        return namesArray;
    }

    public String[] getUrisArray() {
        return urisArray;
    }

    public int[] getTypesArray() {
        return typesArray;
    }

    public String[] getNamespaceArray() {
        return namespaceArray;
    }

    public boolean hasIdCall() {
        return _hasIdCall;
    }

    public Templates getTemplates() {
        return _templates;
    }

    public void setTemplates(Templates templates) {
        _templates = templates;
    }
    /**
     * Return the state of the services mechanism feature.
     */
    public boolean useServicesMechnism() {
        return _useServicesMechanism;
    }

    /**
     * Set the state of the services mechanism feature.
     */
    public void setServicesMechnism(boolean flag) {
        _useServicesMechanism = flag;
    }

    /**
     * Return allowed protocols for accessing external stylesheet.
     */
    public String getAllowedProtocols() {
        return _accessExternalStylesheet;
    }

    /**
     * Set allowed protocols for accessing external stylesheet.
     */
    public void setAllowedProtocols(String protocols) {
        _accessExternalStylesheet = protocols;
    }

    /************************************************************************
     * DOMImplementation caching for basis library
     ************************************************************************/
    protected DOMImplementation _domImplementation = null;

    public Document newDocument(String uri, String qname)
        throws ParserConfigurationException
    {
        if (_domImplementation == null) {
            DocumentBuilderFactory dbf = FactoryImpl.getDOMFactory(_useServicesMechanism);
            _domImplementation = dbf.newDocumentBuilder().getDOMImplementation();
        }
        return _domImplementation.createDocument(uri, qname, null);
    }
}