001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    package org.apache.camel.converter.jaxp;
018    
019    import java.io.ByteArrayInputStream;
020    import java.io.File;
021    import java.io.IOException;
022    import java.io.InputStream;
023    import java.io.InputStreamReader;
024    import java.io.Reader;
025    import java.io.StringReader;
026    import java.io.StringWriter;
027    import java.lang.reflect.Constructor;
028    import java.nio.ByteBuffer;
029    import java.util.Properties;
030    
031    import javax.xml.parsers.DocumentBuilder;
032    import javax.xml.parsers.DocumentBuilderFactory;
033    import javax.xml.parsers.ParserConfigurationException;
034    import javax.xml.transform.OutputKeys;
035    import javax.xml.transform.Result;
036    import javax.xml.transform.Source;
037    import javax.xml.transform.Transformer;
038    import javax.xml.transform.TransformerConfigurationException;
039    import javax.xml.transform.TransformerException;
040    import javax.xml.transform.TransformerFactory;
041    import javax.xml.transform.dom.DOMResult;
042    import javax.xml.transform.dom.DOMSource;
043    import javax.xml.transform.sax.SAXSource;
044    import javax.xml.transform.stream.StreamResult;
045    import javax.xml.transform.stream.StreamSource;
046    
047    import org.w3c.dom.Document;
048    import org.w3c.dom.Element;
049    import org.w3c.dom.Node;
050    import org.w3c.dom.NodeList;
051    import org.xml.sax.InputSource;
052    import org.xml.sax.SAXException;
053    import org.xml.sax.XMLReader;
054    
055    import org.apache.camel.Converter;
056    import org.apache.camel.Exchange;
057    import org.apache.camel.util.ObjectHelper;
058    
059    /**
060     * A helper class to transform to and from various JAXB types such as {@link Source} and {@link Document}
061     *
062     * @version $Revision: 19331 $
063     */
064    @Converter
065    public class XmlConverter {
066        @Deprecated
067        //It will be removed in Camel 3.0, please use the Exchange.DEFAULT_CHARSET 
068        public static final String DEFAULT_CHARSET_PROPERTY = "org.apache.camel.default.charset";
069        
070        public static final String OUTPUT_PROPERTIES_PREFIX = "org.apache.camel.xmlconverter.output.";
071        public static String defaultCharset = ObjectHelper.getSystemProperty(Exchange.DEFAULT_CHARSET_PROPERTY, "UTF-8");
072    
073        /*
074         * When converting a DOM tree to a SAXSource, we try to use Xalan internal DOM parser if
075         * available. Else, transform the DOM tree to a String and build a SAXSource on top of it.
076         */
077        private static final Class<?> DOM_TO_SAX_CLASS;
078    
079        private DocumentBuilderFactory documentBuilderFactory;
080        private TransformerFactory transformerFactory;
081    
082        static {
083            Class<?> cl = null;
084            try {
085                // will not warn the user if the class could not be found
086                cl = ObjectHelper.loadClass("org.apache.xalan.xsltc.trax.DOM2SAX", XmlConverter.class.getClassLoader(), false);
087            } catch (Exception e) {
088                // ignore
089            }
090            DOM_TO_SAX_CLASS = cl;
091        }
092    
093    
094        public XmlConverter() {
095        }
096    
097        public XmlConverter(DocumentBuilderFactory documentBuilderFactory) {
098            this.documentBuilderFactory = documentBuilderFactory;
099        }
100    
101        /**
102         * Returns the default set of output properties for conversions.
103         */
104        public Properties defaultOutputProperties() {
105            Properties properties = new Properties();
106            properties.put(OutputKeys.ENCODING, defaultCharset);
107            properties.put(OutputKeys.OMIT_XML_DECLARATION, "yes");
108            return properties;
109        }
110    
111        /**
112         * Converts the given input Source into the required result
113         */
114        public void toResult(Source source, Result result) throws TransformerException {
115            toResult(source, result, defaultOutputProperties());
116        }
117    
118        /**
119         * Converts the given input Source into the required result
120         */
121        public void toResult(Source source, Result result, Properties outputProperties) throws TransformerException {
122            if (source == null) {
123                return;
124            }
125    
126            Transformer transformer = createTransfomer();
127            if (transformer == null) {
128                throw new TransformerException("Could not create a transformer - JAXP is misconfigured!");
129            }
130            transformer.setOutputProperties(outputProperties);
131            transformer.transform(source, result);
132        }
133    
134        /**
135         * Converts the given NodeList to a boolean
136         */
137        @Converter
138        public Boolean toBoolean(NodeList list) {
139            return list.getLength() > 0;
140        }
141    
142        /**
143         * Converts the given byte[] to a Source
144         */
145        @Converter
146        public BytesSource toBytesSource(byte[] data) {
147            return new BytesSource(data);
148        }
149    
150    
151        /**
152         * Converts the given String to a Source
153         */
154        @Converter
155        public StringSource toStringSource(String data) {
156            return new StringSource(data);
157        }
158    
159        /**
160         * Converts the given Document to a Source
161         * @deprecated use toDOMSource instead
162         */
163        @Deprecated
164        public DOMSource toSource(Document document) {
165            return toDOMSource(document);
166        }
167    
168        /**
169         * Converts the given Document to a Source
170         */
171        @Converter
172        public DOMSource toDOMSource(Document document) {
173            return new DOMSource(document);
174        }
175    
176        /**
177         * Converts the given Node to a Source
178         */
179        @Converter
180        public Source toSource(Node node) {
181            return new DOMSource(node);
182        }
183        
184        /**
185         * Converts the given String to a Source
186         */
187        @Converter
188        public Source toSource(String data) {
189            return new StringSource(data);
190        }
191    
192        /**
193         * Converts the given input Source into text
194         */
195        @Deprecated
196        //It will be removed in Camel 3.0, please use the method which take the exchange as the parameter
197        public String toString(Source source) throws TransformerException {
198            return toString(source, null);
199        }
200    
201        /**
202         * Converts the given input Source into text
203         */
204        @Converter
205        public String toString(Source source, Exchange exchange) throws TransformerException {
206            if (source == null) {
207                return null;
208            } else if (source instanceof StringSource) {
209                return ((StringSource) source).getText();
210            } else if (source instanceof BytesSource) {
211                return new String(((BytesSource) source).getData());
212            } else {
213                StringWriter buffer = new StringWriter();           
214                if (exchange != null) {
215                    // check the camelContext properties first
216                    Properties properties = ObjectHelper.getCamelPropertiesWithPrefix(OUTPUT_PROPERTIES_PREFIX, exchange.getContext());
217                    if (properties.size() > 0) {
218                        toResult(source, new StreamResult(buffer), properties);
219                        return buffer.toString();
220                    }            
221                }
222                // using the old way to deal with it
223                toResult(source, new StreamResult(buffer));            
224                return buffer.toString();
225            }
226        }
227    
228        /**
229         * Converts the given input Source into bytes
230         */
231        @Converter
232        public byte[] toByteArray(Source source, Exchange exchange) throws TransformerException {
233            String answer = toString(source, exchange);
234            if (exchange != null) {
235                return exchange.getContext().getTypeConverter().convertTo(byte[].class, exchange, answer);
236            } else {
237                return answer.getBytes();
238            }
239        }
240        
241        /**
242         * Converts the given input Node into text
243         */
244        @Deprecated
245        //It will be removed in Camel 3.0, please use the method which take the exchange as the parameter
246        public String toString(Node node) throws TransformerException {
247            return toString(node, null);
248        }
249        
250        /**
251         * Converts the given input Node into text
252         */
253        @Converter
254        public String toString(Node node, Exchange exchange) throws TransformerException {
255            return toString(new DOMSource(node), exchange);
256        }
257    
258        /**
259         * Converts the source instance to a {@link DOMSource} or returns null if the conversion is not
260         * supported (making it easy to derive from this class to add new kinds of conversion).
261         */
262        @Converter
263        public DOMSource toDOMSource(Source source) throws ParserConfigurationException, IOException, SAXException, TransformerException {
264            if (source instanceof DOMSource) {
265                return (DOMSource) source;
266            } else if (source instanceof SAXSource) {
267                return toDOMSourceFromSAX((SAXSource) source);
268            } else if (source instanceof StreamSource) {
269                return toDOMSourceFromStream((StreamSource) source);
270            } else {
271                return null;
272            }
273        }
274    
275        /**
276         * Converts the source instance to a {@link DOMSource} or returns null if the conversion is not
277         * supported (making it easy to derive from this class to add new kinds of conversion).
278         */
279        @Converter
280        public DOMSource toDOMSource(String text) throws ParserConfigurationException, IOException, SAXException, TransformerException {
281            Source source = toSource(text);
282            if (source != null) {
283                return toDOMSourceFromStream((StreamSource) source);
284            } else {
285                return null;
286            }
287        }
288    
289        
290        /**
291         * Converts the source instance to a {@link SAXSource} or returns null if the conversion is not
292         * supported (making it easy to derive from this class to add new kinds of conversion).
293         */
294        @Deprecated
295        //It will be removed in Camel 3.0, please use the method which take the exchange as the parameter
296        public SAXSource toSAXSource(String source) throws IOException, SAXException, TransformerException {
297            return toSAXSource(source, null);
298        }
299        
300        /**
301         * Converts the source instance to a {@link SAXSource} or returns null if the conversion is not
302         * supported (making it easy to derive from this class to add new kinds of conversion).
303         */
304        @Converter
305        public SAXSource toSAXSource(String source, Exchange exchange) throws IOException, SAXException, TransformerException {
306            return toSAXSource(toSource(source), exchange);
307        }
308       
309        /**
310         * Converts the source instance to a {@link SAXSource} or returns null if the conversion is not
311         * supported (making it easy to derive from this class to add new kinds of conversion).
312         */
313        @Deprecated
314        //It will be removed in Camel 3.0, please use the method which take the exchange as the parameter    
315        public SAXSource toSAXSource(InputStream source) throws IOException, SAXException, TransformerException {
316            return toSAXSource(source, null);
317        }
318        
319        /**
320         * Converts the source instance to a {@link SAXSource} or returns null if the conversion is not
321         * supported (making it easy to derive from this class to add new kinds of conversion).
322         */
323        @Converter
324        public SAXSource toSAXSource(InputStream source, Exchange exchange) throws IOException, SAXException, TransformerException {
325            return toSAXSource(toStreamSource(source), exchange);
326        }
327        
328        /**
329         * Converts the source instance to a {@link SAXSource} or returns null if the conversion is not
330         * supported (making it easy to derive from this class to add new kinds of conversion).
331         */
332        @Deprecated
333        //It will be removed in Camel 3.0, please use the method which take the exchange as the parameter
334        public SAXSource toSAXSource(Source source) throws IOException, SAXException, TransformerException {
335            return toSAXSource(source, null);
336        }
337        
338        /**
339         * Converts the source instance to a {@link SAXSource} or returns null if the conversion is not
340         * supported (making it easy to derive from this class to add new kinds of conversion).
341         */
342        @Converter
343        public SAXSource toSAXSource(Source source, Exchange exchange) throws IOException, SAXException, TransformerException {
344            if (source instanceof SAXSource) {
345                return (SAXSource) source;
346            } else if (source instanceof DOMSource) {
347                return toSAXSourceFromDOM((DOMSource) source, exchange);
348            } else if (source instanceof StreamSource) {
349                return toSAXSourceFromStream((StreamSource) source);
350            } else {
351                return null;
352            }
353        }
354    
355        @Deprecated
356        //It will be removed in Camel 3.0, please use the method which take the exchange as the parameter    
357        public StreamSource toStreamSource(Source source) throws TransformerException {
358            return toStreamSource(source, null);
359        }
360        
361        @Converter
362        public StreamSource toStreamSource(Source source, Exchange exchange) throws TransformerException {
363            if (source instanceof StreamSource) {
364                return (StreamSource) source;
365            } else if (source instanceof DOMSource) {
366                return toStreamSourceFromDOM((DOMSource) source, exchange);
367            } else if (source instanceof SAXSource) {
368                return toStreamSourceFromSAX((SAXSource) source, exchange);
369            } else {
370                return null;
371            }
372        }
373    
374        @Converter
375        public StreamSource toStreamSource(InputStream in) throws TransformerException {
376            if (in != null) {
377                return new StreamSource(in);
378            }
379            return null;
380        }
381    
382        @Converter
383        public StreamSource toStreamSource(Reader in) throws TransformerException {
384            if (in != null) {
385                return new StreamSource(in);
386            }
387            return null;
388        }
389    
390        @Converter
391        public StreamSource toStreamSource(File in) throws TransformerException {
392            if (in != null) {
393                return new StreamSource(in);
394            }
395            return null;
396        }
397    
398        @Converter
399        public StreamSource toStreamSource(byte[] in, Exchange exchange) throws TransformerException {
400            if (in != null) {
401                InputStream is = exchange.getContext().getTypeConverter().convertTo(InputStream.class, in);
402                return new StreamSource(is);
403            }
404            return null;
405        }
406    
407        @Converter
408        public StreamSource toStreamSource(ByteBuffer in, Exchange exchange) throws TransformerException {
409            if (in != null) {
410                InputStream is = exchange.getContext().getTypeConverter().convertTo(InputStream.class, in);
411                return new StreamSource(is);
412            }
413            return null;
414        }
415    
416        @Deprecated
417        //It will be removed in Camel 3.0, please use the method which take the exchange as the parameter
418        public StreamSource toStreamSourceFromSAX(SAXSource source) throws TransformerException {
419            return toStreamSourceFromSAX(source, null);
420        }
421        
422        @Converter
423        public StreamSource toStreamSourceFromSAX(SAXSource source, Exchange exchange) throws TransformerException {
424            InputSource inputSource = source.getInputSource();
425            if (inputSource != null) {
426                if (inputSource.getCharacterStream() != null) {
427                    return new StreamSource(inputSource.getCharacterStream());
428                }
429                if (inputSource.getByteStream() != null) {
430                    return new StreamSource(inputSource.getByteStream());
431                }
432            }
433            String result = toString(source, exchange);
434            return new StringSource(result);
435        }
436    
437        @Deprecated
438        //It will be removed in Camel 3.0, please use the method which take the exchange as the parameter
439        public StreamSource toStreamSourceFromDOM(DOMSource source) throws TransformerException {
440            return toStreamSourceFromDOM(source, null);
441        }
442        
443        @Converter
444        public StreamSource toStreamSourceFromDOM(DOMSource source, Exchange exchange) throws TransformerException {
445            String result = toString(source, exchange);
446            return new StringSource(result);
447        }
448    
449        @Converter
450        public SAXSource toSAXSourceFromStream(StreamSource source) {
451            InputSource inputSource;
452            if (source.getReader() != null) {
453                inputSource = new InputSource(source.getReader());
454            } else {
455                inputSource = new InputSource(source.getInputStream());
456            }
457            inputSource.setSystemId(source.getSystemId());
458            inputSource.setPublicId(source.getPublicId());
459            return new SAXSource(inputSource);
460        }
461    
462        @Deprecated
463        //It will be removed in Camel 3.0, please use the method which take the exchange as the parameter
464        public Reader toReaderFromSource(Source src) throws TransformerException {
465            return toReaderFromSource(src, null);
466        }
467        
468        @Converter
469        public Reader toReaderFromSource(Source src, Exchange exchange) throws TransformerException {
470            StreamSource stSrc = toStreamSource(src, exchange);
471            Reader r = stSrc.getReader();
472            if (r == null) {
473                r = new InputStreamReader(stSrc.getInputStream());
474            }
475            return r;
476        }
477    
478        @Converter
479        public DOMSource toDOMSource(InputStream is) throws ParserConfigurationException, IOException, SAXException {
480            InputSource source = new InputSource(is);
481            String systemId = source.getSystemId();
482            DocumentBuilder builder = createDocumentBuilder();
483            Document document = builder.parse(source);
484            return new DOMSource(document, systemId);
485        }
486    
487        @Converter
488        public DOMSource toDOMSourceFromStream(StreamSource source) throws ParserConfigurationException, IOException, SAXException {
489            Document document;
490            String systemId = source.getSystemId();
491    
492            DocumentBuilder builder = createDocumentBuilder();
493            Reader reader = source.getReader();
494            if (reader != null) {
495                document = builder.parse(new InputSource(reader));
496            } else {
497                InputStream inputStream = source.getInputStream();
498                if (inputStream != null) {
499                    InputSource inputsource = new InputSource(inputStream);
500                    inputsource.setSystemId(systemId);
501                    document = builder.parse(inputsource);
502                } else {
503                    throw new IOException("No input stream or reader available on StreamSource: " + source);
504                }
505            }
506            return new DOMSource(document, systemId);
507        }
508        
509        @Deprecated
510        //It will be removed in Camel 3.0, please use the method which take the exchange as the parameter
511        public SAXSource toSAXSourceFromDOM(DOMSource source) throws TransformerException {
512            return toSAXSourceFromDOM(source, null);
513        }
514        
515        @Converter
516        public SAXSource toSAXSourceFromDOM(DOMSource source, Exchange exchange) throws TransformerException {
517            if (DOM_TO_SAX_CLASS != null) {
518                try {
519                    Constructor<?> cns = DOM_TO_SAX_CLASS.getConstructor(Node.class);
520                    XMLReader converter = (XMLReader) cns.newInstance(source.getNode());
521                    return new SAXSource(converter, new InputSource());
522                } catch (Exception e) {
523                    throw new TransformerException(e);
524                }
525            } else {
526                String str = toString(source, exchange);
527                StringReader reader = new StringReader(str);
528                return new SAXSource(new InputSource(reader));
529            }
530        }
531    
532        @Converter
533        public DOMSource toDOMSourceFromSAX(SAXSource source) throws IOException, SAXException, ParserConfigurationException, TransformerException {
534            return new DOMSource(toDOMNodeFromSAX(source));
535        }
536    
537        @Converter
538        public Node toDOMNodeFromSAX(SAXSource source) throws ParserConfigurationException, IOException, SAXException, TransformerException {
539            DOMResult result = new DOMResult();
540            toResult(source, result);
541            return result.getNode();
542        }
543    
544        /**
545         * Converts the given TRaX Source into a W3C DOM node
546         */
547        @Converter
548        public Node toDOMNode(Source source) throws TransformerException, ParserConfigurationException, IOException, SAXException {
549            DOMSource domSrc = toDOMSource(source);
550            return domSrc != null ? domSrc.getNode() : null;
551        }
552    
553        /**
554         * Create a DOM element from the given source.
555         */
556        @Converter
557        public Element toDOMElement(Source source) throws TransformerException, ParserConfigurationException, IOException, SAXException {
558            Node node = toDOMNode(source);
559            return toDOMElement(node);
560        }
561    
562        /**
563         * Create a DOM element from the DOM node.
564         * Simply cast if the node is an Element, or
565         * return the root element if it is a Document.
566         */
567        @Converter
568        public Element toDOMElement(Node node) throws TransformerException {
569            // If the node is an document, return the root element
570            if (node instanceof Document) {
571                return ((Document) node).getDocumentElement();
572                // If the node is an element, just cast it
573            } else if (node instanceof Element) {
574                return (Element) node;
575                // Other node types are not handled
576            } else {
577                throw new TransformerException("Unable to convert DOM node to an Element");
578            }
579        }
580    
581        /**
582         * Converts the given data to a DOM document
583         *
584         * @param data is the data to be parsed
585         * @return the parsed document
586         */
587        @Converter
588        public Document toDOMDocument(byte[] data) throws IOException, SAXException, ParserConfigurationException {
589            DocumentBuilder documentBuilder = getDocumentBuilderFactory().newDocumentBuilder();
590            return documentBuilder.parse(new ByteArrayInputStream(data));
591        }
592    
593        /**
594         * Converts the given {@link InputStream} to a DOM document
595         *
596         * @param in is the data to be parsed
597         * @return the parsed document
598         */
599        @Converter
600        public Document toDOMDocument(InputStream in) throws IOException, SAXException, ParserConfigurationException {
601            DocumentBuilder documentBuilder = getDocumentBuilderFactory().newDocumentBuilder();
602            return documentBuilder.parse(in);
603        }
604    
605        /**
606         * Converts the given {@link InputStream} to a DOM document
607         *
608         * @param in is the data to be parsed
609         * @return the parsed document
610         */
611        @Converter
612        public Document toDOMDocument(Reader in) throws IOException, SAXException, ParserConfigurationException {
613            return toDOMDocument(new InputSource(in));
614        }
615    
616        /**
617         * Converts the given {@link InputSource} to a DOM document
618         *
619         * @param in is the data to be parsed
620         * @return the parsed document
621         */
622        @Converter
623        public Document toDOMDocument(InputSource in) throws IOException, SAXException, ParserConfigurationException {
624            DocumentBuilder documentBuilder = getDocumentBuilderFactory().newDocumentBuilder();
625            return documentBuilder.parse(in);
626        }
627    
628        /**
629         * Converts the given {@link String} to a DOM document
630         *
631         * @param text is the data to be parsed
632         * @return the parsed document
633         */
634        @Converter
635        public Document toDOMDocument(String text) throws IOException, SAXException, ParserConfigurationException {
636            return toDOMDocument(new StringReader(text));
637        }
638    
639        /**
640         * Converts the given {@link File} to a DOM document
641         *
642         * @param file is the data to be parsed
643         * @return the parsed document
644         */
645        @Converter
646        public Document toDOMDocument(File file) throws IOException, SAXException, ParserConfigurationException {
647            DocumentBuilder documentBuilder = getDocumentBuilderFactory().newDocumentBuilder();
648            return documentBuilder.parse(file);
649        }
650    
651        /**
652         * Create a DOM document from the given source.
653         */
654        @Converter
655        public Document toDOMDocument(Source source) throws TransformerException, ParserConfigurationException, IOException, SAXException {
656            Node node = toDOMNode(source);
657            return toDOMDocument(node);
658        }
659    
660        /**
661         * Create a DOM document from the given Node.
662         *
663         * If the node is an document, just cast it, if the node is an root element, retrieve its
664         * owner element or create a new document and import the node.
665         */
666        @Converter
667        public Document toDOMDocument(final Node node) throws ParserConfigurationException, TransformerException {
668            ObjectHelper.notNull(node, "node");
669    
670            // If the node is the document, just cast it
671            if (node instanceof Document) {
672                return (Document) node;
673                // If the node is an element
674            } else if (node instanceof Element) {
675                Element elem = (Element) node;
676                // If this is the root element, return its owner document
677                if (elem.getOwnerDocument().getDocumentElement() == elem) {
678                    return elem.getOwnerDocument();
679                    // else, create a new doc and copy the element inside it
680                } else {
681                    Document doc = createDocument();
682                    // import node must no occur concurrent on the same node (must be its owner)
683                    // so we need to synchronize on it
684                    synchronized (node.getOwnerDocument()) {
685                        doc.appendChild(doc.importNode(node, true));
686                    }
687                    return doc;
688                }
689                // other element types are not handled
690            } else {
691                throw new TransformerException("Unable to convert DOM node to a Document: " + node);
692            }
693        }
694    
695        @Deprecated
696        //It will be removed in Camel 3.0, please use the method which take the exchange as the parameter
697        public InputStream toInputStream(DOMSource source) throws TransformerException, IOException {
698            return toInputStream(source, null);
699        }
700        
701        @Converter
702        public InputStream toInputStream(DOMSource source, Exchange exchange) throws TransformerException, IOException {
703            String s = toString(source, exchange);
704            return new ByteArrayInputStream(s.getBytes());
705        }
706    
707        @Deprecated
708        //It will be removed in Camel 3.0, please use the method which take the exchange as the parameter
709        public InputStream toInputStream(Document dom) throws TransformerException, IOException {
710            return toInputStream(dom, null);
711        }
712        
713        @Converter
714        public InputStream toInputStream(Document dom, Exchange exchange) throws TransformerException, IOException {
715            String s = toString(dom, exchange);
716            return new ByteArrayInputStream(s.getBytes());
717        }
718    
719        @Converter
720        public InputSource toInputSource(InputStream is) {
721            return new InputSource(is);
722        }
723    
724        // Properties
725        //-------------------------------------------------------------------------
726        public DocumentBuilderFactory getDocumentBuilderFactory() {
727            if (documentBuilderFactory == null) {
728                documentBuilderFactory = createDocumentBuilderFactory();
729            }
730            return documentBuilderFactory;
731        }
732    
733        public void setDocumentBuilderFactory(DocumentBuilderFactory documentBuilderFactory) {
734            this.documentBuilderFactory = documentBuilderFactory;
735        }
736    
737    
738        // Helper methods
739        //-------------------------------------------------------------------------
740        public DocumentBuilderFactory createDocumentBuilderFactory() {
741            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
742            factory.setNamespaceAware(true);
743            factory.setIgnoringElementContentWhitespace(true);
744            factory.setIgnoringComments(true);
745            return factory;
746        }
747    
748    
749        public DocumentBuilder createDocumentBuilder() throws ParserConfigurationException {
750            DocumentBuilderFactory factory = getDocumentBuilderFactory();
751            return factory.newDocumentBuilder();
752        }
753    
754        public Document createDocument() throws ParserConfigurationException {
755            DocumentBuilder builder = createDocumentBuilder();
756            return builder.newDocument();
757        }
758    
759        public TransformerFactory getTransformerFactory() {
760            if (transformerFactory == null) {
761                transformerFactory = createTransformerFactory();
762            }
763            return transformerFactory;
764        }
765    
766        public void setTransformerFactory(TransformerFactory transformerFactory) {
767            this.transformerFactory = transformerFactory;
768        }
769    
770        public Transformer createTransfomer() throws TransformerConfigurationException {
771            TransformerFactory factory = getTransformerFactory();
772            return factory.newTransformer();
773        }
774    
775        public TransformerFactory createTransformerFactory() {
776            return TransformerFactory.newInstance();
777        }
778    
779    }