KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jgap > xml > XMLManager


1 /*
2  * This file is part of JGAP.
3  *
4  * JGAP offers a dual license model containing the LGPL as well as the MPL.
5  *
6  * For licencing information please see the file license.txt included with JGAP
7  * or have a look at the top of class org.jgap.Chromosome which representatively
8  * includes the JGAP license policy applicable for any file delivered with JGAP.
9  */

10 package org.jgap.xml;
11
12 import java.io.*;
13 import java.lang.reflect.*;
14 import java.util.*;
15 import javax.xml.parsers.*;
16 import javax.xml.transform.*;
17 import javax.xml.transform.dom.*;
18 import javax.xml.transform.stream.*;
19 import junitx.util.PrivateAccessor;
20
21 import org.jgap.*;
22 import org.w3c.dom.*;
23
24 /**
25  * The XMLManager performs marshalling of genetic entity instances
26  * (such as Chromosomes and Genotypes) to XML representations of those
27  * entities, as well as unmarshalling. All of the methods in this class are
28  * static, so no construction is required (or allowed).
29  *
30  * @author Neil Rotstan
31  * @author Klaus Meffert
32  * @since 1.0
33  */

34 public class XMLManager {
35
36   /** String containing the CVS revision. Read out via reflection!*/
37   private final static String JavaDoc CVS_REVISION = "$Revision: 1.19 $";
38
39   /**
40    * Constant representing the name of the genotype XML element tag.
41    */

42   private static final String JavaDoc GENOTYPE_TAG = "genotype";
43
44   /**
45    * Constant representing the name of the chromosome XML element tag.
46    */

47   private static final String JavaDoc CHROMOSOME_TAG = "chromosome";
48
49   /**
50    * Constant representing the name of the gene XML element tag.
51    */

52   private static final String JavaDoc GENES_TAG = "genes";
53
54   /**
55    * Constant representing the name of the gene XML element tag.
56    */

57   private static final String JavaDoc GENE_TAG = "gene";
58
59   private static final String JavaDoc ALLELE_TAG = "allele";
60
61   /**
62    * Constant representing the name of the size XML attribute that is
63    * added to genotype and chromosome elements to describe their size.
64    */

65   private static final String JavaDoc SIZE_ATTRIBUTE = "size";
66
67   /**
68    * Constant representing the fully-qualified name of the concrete
69    * Gene class that was marshalled.
70    */

71   private static final String JavaDoc CLASS_ATTRIBUTE = "class";
72
73   /**
74    * Shared DocumentBuilder, which is used to create new DOM Document
75    * instances.
76    */

77   private static final DocumentBuilder m_documentCreator;
78
79   /**
80    * Shared lock object used for synchronization purposes.
81    */

82   private static final Object JavaDoc m_lock = new Object JavaDoc();
83
84   /**
85    * @author Neil Rotstan
86    * @since 1.0
87    */

88   static {
89     try {
90       m_documentCreator =
91           DocumentBuilderFactory.newInstance().newDocumentBuilder();
92     }
93     catch (ParserConfigurationException parserError) {
94       throw new RuntimeException JavaDoc(
95           "XMLManager: Unable to setup DocumentBuilder: "
96           + parserError.getMessage());
97     }
98   }
99
100   /**
101    * Private constructor. All methods in this class are static, so no
102    * construction is allowed.
103    */

104   private XMLManager() {
105   }
106
107   /**
108    * Marshall a Chromosome instance to an XML Document representation,
109    * including its contained Gene instances.
110    *
111    * @param a_subject the chromosome to represent as an XML document
112    * @return a Document object representing the given Chromosome
113    *
114    * @author Neil Rotstan
115    * @since 1.0
116    * @deprecated use XMLDocumentBuilder instead
117    */

118   public static Document representChromosomeAsDocument(final IChromosome
119       a_subject) {
120     // DocumentBuilders do not have to be thread safe, so we have to
121
// protect creation of the Document with a synchronized block.
122
// -------------------------------------------------------------
123
Document chromosomeDocument;
124     synchronized (m_lock) {
125       chromosomeDocument = m_documentCreator.newDocument();
126     }
127     Element chromosomeElement =
128         representChromosomeAsElement(a_subject, chromosomeDocument);
129     chromosomeDocument.appendChild(chromosomeElement);
130     return chromosomeDocument;
131   }
132
133   /**
134    * Marshall a Genotype to an XML Document representation, including its
135    * population of Chromosome instances.
136    *
137    * @param a_subject the genotype to represent as an XML document
138    * @return a Document object representing the given Genotype
139    *
140    * @author Neil Rotstan
141    * @since 1.0
142    * @deprecated use XMLDocumentBuilder instead
143    */

144   public static Document representGenotypeAsDocument(final Genotype a_subject) {
145     // DocumentBuilders do not have to be thread safe, so we have to
146
// protect creation of the Document with a synchronized block.
147
// -------------------------------------------------------------
148
Document genotypeDocument;
149     synchronized (m_lock) {
150       genotypeDocument = m_documentCreator.newDocument();
151     }
152     Element genotypeElement =
153         representGenotypeAsElement(a_subject, genotypeDocument);
154     genotypeDocument.appendChild(genotypeElement);
155     return genotypeDocument;
156   }
157
158   /**
159    * Marshall an array of Genes to an XML Element representation.
160    *
161    * @param a_geneValues the genes to represent as an XML element
162    * @param a_xmlDocument a Document instance that will be used to create
163    * the Element instance. Note that the element will NOT be added to the
164    * document by this method
165    * @return an Element object representing the given genes
166    *
167    * @author Neil Rotstan
168    * @author Klaus Meffert
169    * @since 1.0
170    * @deprecated use XMLDocumentBuilder instead
171    */

172   public static Element representGenesAsElement(final Gene[] a_geneValues,
173                                                 final Document a_xmlDocument) {
174     // Create the parent genes element.
175
// --------------------------------
176
Element genesElement = a_xmlDocument.createElement(GENES_TAG);
177     // Now add gene sub-elements for each gene in the given array.
178
// -----------------------------------------------------------
179
Element geneElement;
180     for (int i = 0; i < a_geneValues.length; i++) {
181       // Create the allele element for this gene.
182
// ----------------------------------------
183
geneElement = a_xmlDocument.createElement(GENE_TAG);
184       // Add the class attribute and set its value to the class
185
// name of the concrete class representing the current Gene.
186
// ---------------------------------------------------------
187
geneElement.setAttribute(CLASS_ATTRIBUTE,
188                                a_geneValues[i].getClass().getName());
189       // Create a text node to contain the string representation of
190
// the gene's value (allele).
191
// ----------------------------------------------------------
192
Element alleleRepresentation = representAlleleAsElement(a_geneValues[i],
193           a_xmlDocument);
194       // And now add the text node to the gene element, and then
195
// add the gene element to the genes element.
196
// -------------------------------------------------------
197
geneElement.appendChild(alleleRepresentation);
198       genesElement.appendChild(geneElement);
199     }
200     return genesElement;
201   }
202
203   /**
204    *
205    * @param a_gene Gene
206    * @param a_xmlDocument Document
207    * @return Element
208    *
209    * @author Klaus Meffert
210    * @since 2.0
211    */

212   private static Element representAlleleAsElement(final Gene a_gene,
213                                                   final Document a_xmlDocument) {
214     Element alleleElement = a_xmlDocument.createElement(ALLELE_TAG);
215     alleleElement.setAttribute("class", a_gene.getClass().getName());
216     alleleElement.setAttribute("value", a_gene.getPersistentRepresentation());
217     return alleleElement;
218   }
219
220   /**
221    * Marshall a Chromosome instance to an XML Element representation,
222    * including its contained Genes as sub-elements. This may be useful in
223    * scenarios where representation as an entire Document is undesirable,
224    * such as when the representation of this Chromosome is to be combined
225    * with other elements in a single Document.
226    *
227    * @param a_subject the chromosome to represent as an XML element
228    * @param a_xmlDocument a Document instance that will be used to create
229    * the Element instance. Note that the element will NOT be added to the
230    * document by this method
231    * @return an Element object representing the given Chromosome
232    *
233    * @author Neil Rotstan
234    * @since 1.0
235    * @deprecated use XMLDocumentBuilder instead
236    */

237   public static Element representChromosomeAsElement(final IChromosome a_subject,
238       final Document a_xmlDocument) {
239     // Start by creating an element for the chromosome and its size
240
// attribute, which represents the number of genes in the chromosome.
241
// ------------------------------------------------------------------
242
Element chromosomeElement =
243         a_xmlDocument.createElement(CHROMOSOME_TAG);
244     chromosomeElement.setAttribute(SIZE_ATTRIBUTE,
245                                    Integer.toString(a_subject.size()));
246     // Next create the genes element with its nested gene elements,
247
// which will contain string representations of the alleles.
248
// --------------------------------------------------------------
249
Element genesElement = representGenesAsElement(a_subject.getGenes(),
250         a_xmlDocument);
251     // Add the new genes element to the chromosome element and then
252
// return the chromosome element.
253
// -------------------------------------------------------------
254
chromosomeElement.appendChild(genesElement);
255     return chromosomeElement;
256   }
257
258   /**
259    * Marshall a Genotype instance into an XML Element representation,
260    * including its population of Chromosome instances as sub-elements.
261    * This may be useful in scenarios where representation as an
262    * entire Document is undesirable, such as when the representation
263    * of this Genotype is to be combined with other elements in a
264    * single Document.
265    *
266    * @param a_subject the genotype to represent as an XML element
267    * @param a_xmlDocument a Document instance that will be used to create
268    * the Element instance. Note that the element will NOT be added to the
269    * document by this method
270    * @return an Element object representing the given Genotype
271    *
272    * @author Neil Rotstan
273    * @since 1.0
274    * @deprecated use XMLDocumentBuilder instead
275    */

276   public static Element representGenotypeAsElement(final Genotype a_subject,
277       final Document a_xmlDocument) {
278     Population population = a_subject.getPopulation();
279     // Start by creating the genotype element and its size attribute,
280
// which represents the number of chromosomes present in the
281
// genotype.
282
// --------------------------------------------------------------
283
Element genotypeTag = a_xmlDocument.createElement(GENOTYPE_TAG);
284     genotypeTag.setAttribute(SIZE_ATTRIBUTE,
285                              Integer.toString(population.size()));
286     // Next, add nested elements for each of the chromosomes in the
287
// genotype.
288
// ------------------------------------------------------------
289
for (int i = 0; i < population.size(); i++) {
290       Element chromosomeElement
291           = representChromosomeAsElement(population.getChromosome(i),
292                                        a_xmlDocument);
293       genotypeTag.appendChild(chromosomeElement);
294     }
295     return genotypeTag;
296   }
297
298   /**
299    * Unmarshall a Chromosome instance from a given XML Element
300    * representation.
301    *
302    * @param a_activeConfiguration current Configuration object
303    * @param a_xmlElement the XML Element representation of the Chromosome
304    * @return a new Chromosome instance setup with the data from the XML Element
305    * representation
306    *
307    * @throws ImproperXMLException if the given Element is improperly
308    * structured or missing data
309    * @throws UnsupportedRepresentationException if the actively configured
310    * Gene implementation does not support the string representation of the
311    * alleles used in the given XML document
312    * @throws GeneCreationException if there is a problem creating or populating
313    * a Gene instance
314    *
315    * @author Neil Rotstan
316    * @since 1.0
317    */

318   public static Gene[] getGenesFromElement(
319       Configuration a_activeConfiguration, Element a_xmlElement)
320       throws ImproperXMLException, UnsupportedRepresentationException,
321       GeneCreationException {
322     // Do some sanity checking. Make sure the XML Element isn't null and
323
// that it in fact represents a set of genes.
324
// -----------------------------------------------------------------
325
if (a_xmlElement == null ||
326         ! (a_xmlElement.getTagName().equals(GENES_TAG))) {
327       throw new ImproperXMLException(
328           "Unable to build Chromosome instance from XML Element: " +
329           "given Element is not a 'genes' element.");
330     }
331     List genes = Collections.synchronizedList(new ArrayList());
332     // Extract the nested gene elements.
333
// ---------------------------------
334
NodeList geneElements = a_xmlElement.getElementsByTagName(GENE_TAG);
335     if (geneElements == null) {
336       throw new ImproperXMLException(
337           "Unable to build Gene instances from XML Element: " +
338           "'" + GENE_TAG + "'" +
339           " sub-elements not found.");
340     }
341     // For each gene, get the class attribute so we know what class
342
// to instantiate to represent the gene instance, and then find
343
// the child text node, which is where the string representation
344
// of the allele is located, and extract the representation.
345
// -------------------------------------------------------------
346
int numberOfGeneNodes = geneElements.getLength();
347     for (int i = 0; i < numberOfGeneNodes; i++) {
348       Element thisGeneElement = (Element) geneElements.item(i);
349       thisGeneElement.normalize();
350       // Fetch the class attribute and create an instance of that
351
// class to represent the current gene.
352
// --------------------------------------------------------
353
String JavaDoc geneClassName =
354           thisGeneElement.getAttribute(CLASS_ATTRIBUTE);
355       Gene thisGeneObject;
356       Class JavaDoc geneClass = null;
357       try {
358         geneClass = Class.forName(geneClassName);
359         try {
360           Constructor constr = geneClass.getConstructor(new Class JavaDoc[] {
361               Configuration.class});
362           thisGeneObject = (Gene) constr.newInstance(new Object JavaDoc[] {
363               a_activeConfiguration});
364         }
365         catch (NoSuchMethodException JavaDoc nsme) {
366           // Try it by calling method newGeneInternal.
367
// -----------------------------------------
368
Constructor constr = geneClass.getConstructor(new Class JavaDoc[] {});
369           thisGeneObject = (Gene) constr.newInstance(new Object JavaDoc[] {});
370           thisGeneObject = (Gene) PrivateAccessor.invoke(thisGeneObject,
371               "newGeneInternal", new Class JavaDoc[] {}, new Object JavaDoc[] {});
372         }
373       }
374       catch (Throwable JavaDoc e) {
375         throw new GeneCreationException(geneClass, e);
376       }
377       // Find the text node and fetch the string representation of
378
// the allele.
379
// ---------------------------------------------------------
380
NodeList children = thisGeneElement.getChildNodes();
381       int childrenSize = children.getLength();
382       String JavaDoc alleleRepresentation = null;
383       for (int j = 0; j < childrenSize; j++) {
384         Element alleleElem = (Element) children.item(j);
385         if (alleleElem.getTagName().equals(ALLELE_TAG)) {
386           alleleRepresentation = alleleElem.getAttribute("value");
387         }
388         if (children.item(j).getNodeType() == Node.TEXT_NODE) {
389           // We found the text node. Extract the representation.
390
// ---------------------------------------------------
391
alleleRepresentation = children.item(j).getNodeValue();
392           break;
393         }
394       }
395       // Sanity check: Make sure the representation isn't null.
396
// ------------------------------------------------------
397
if (alleleRepresentation == null) {
398         throw new ImproperXMLException(
399             "Unable to build Gene instance from XML Element: " +
400             "value (allele) is missing representation.");
401       }
402       // Now set the value of the gene to that reflect the
403
// string representation.
404
// -------------------------------------------------
405
try {
406         thisGeneObject.setValueFromPersistentRepresentation(
407             alleleRepresentation);
408       }
409       catch (UnsupportedOperationException JavaDoc e) {
410         throw new GeneCreationException(
411             "Unable to build Gene because it does not support the " +
412             "setValueFromPersistentRepresentation() method.");
413       }
414       // Finally, add the current gene object to the list of genes.
415
// ----------------------------------------------------------
416
genes.add(thisGeneObject);
417     }
418     return (Gene[]) genes.toArray(new Gene[genes.size()]);
419   }
420
421   /**
422    * Unmarshall a Chromosome instance from a given XML Element
423    * representation.
424    *
425    * @param a_activeConfiguration the current active Configuration object
426    * that is to be used during construction of the Chromosome
427    * @param a_xmlElement the XML Element representation of the Chromosome
428    * @return a new Chromosome instance setup with the data from the XML
429    * Element representation
430    *
431    * @throws ImproperXMLException if the given Element is improperly
432    * structured or missing data
433    * @throws InvalidConfigurationException if the given Configuration is in
434    * an inconsistent state
435    * @throws UnsupportedRepresentationException if the actively configured
436    * Gene implementation does not support the string representation of the
437    * alleles used in the given XML document
438    * @throws GeneCreationException if there is a problem creating or populating
439    * a Gene instance
440    *
441    * @author Neil Rotstan
442    * @since 1.0
443    */

444   public static Chromosome getChromosomeFromElement(
445       Configuration a_activeConfiguration, Element a_xmlElement)
446       throws ImproperXMLException, InvalidConfigurationException,
447       UnsupportedRepresentationException, GeneCreationException {
448     // Do some sanity checking. Make sure the XML Element isn't null and
449
// that in fact represents a chromosome.
450
// -----------------------------------------------------------------
451
if (a_xmlElement == null ||
452         ! (a_xmlElement.getTagName().equals(CHROMOSOME_TAG))) {
453       throw new ImproperXMLException(
454           "Unable to build Chromosome instance from XML Element: " +
455           "given Element is not a 'chromosome' element.");
456     }
457     // Extract the nested genes element and make sure it exists.
458
// ---------------------------------------------------------
459
Element genesElement = (Element)
460         a_xmlElement.getElementsByTagName(GENES_TAG).item(0);
461     if (genesElement == null) {
462       throw new ImproperXMLException(
463           "Unable to build Chromosome instance from XML Element: " +
464           "'genes' sub-element not found.");
465     }
466     // Construct the genes from their representations.
467
// -----------------------------------------------
468
Gene[] geneAlleles = getGenesFromElement(a_activeConfiguration,
469                                              genesElement);
470     // Construct the new Chromosome with the genes and return it.
471
// ----------------------------------------------------------
472
return new Chromosome(a_activeConfiguration, geneAlleles);
473   }
474
475   /**
476    * Unmarshall a Genotype instance from a given XML Element representation.
477    * Its population of Chromosomes will be unmarshalled from the Chromosome
478    * sub-elements.
479    *
480    * @param a_activeConfiguration the current active Configuration object
481    * that is to be used during construction of the Genotype and Chromosome
482    * instances
483    * @param a_xmlElement the XML Element representation of the Genotype
484    * @return a new Genotype instance, complete with a population of Chromosomes,
485    * setup with the data from the XML Element representation
486    *
487    * @throws ImproperXMLException if the given Element is improperly structured
488    * or missing data
489    * @throws InvalidConfigurationException if the given Configuration is in an
490    * inconsistent state
491    * @throws UnsupportedRepresentationException if the actively configured
492    * Gene implementation does not support the string representation of the
493    * alleles used in the given XML document
494    * @throws GeneCreationException if there is a problem creating or populating
495    * a Gene instance
496    *
497    * @author Neil Rotstan
498    * @author Klaus Meffert
499    * @since 1.0
500    */

501   public static Genotype getGenotypeFromElement(
502       Configuration a_activeConfiguration, Element a_xmlElement)
503       throws ImproperXMLException, InvalidConfigurationException,
504       UnsupportedRepresentationException, GeneCreationException {
505
506     // Sanity check. Make sure the XML element isn't null and that it
507
// actually represents a genotype.
508
if (a_xmlElement == null ||
509         ! (a_xmlElement.getTagName().equals(GENOTYPE_TAG))) {
510       throw new ImproperXMLException(
511           "Unable to build Genotype instance from XML Element: " +
512           "given Element is not a 'genotype' element.");
513     }
514     // Fetch all of the nested chromosome elements and convert them
515
// into Chromosome instances.
516
// ------------------------------------------------------------
517
NodeList chromosomes =
518         a_xmlElement.getElementsByTagName(CHROMOSOME_TAG);
519     int numChromosomes = chromosomes.getLength();
520     Population population = new Population(a_activeConfiguration, numChromosomes);
521     for (int i = 0; i < numChromosomes; i++) {
522       population.addChromosome(getChromosomeFromElement(a_activeConfiguration,
523                                                (Element) chromosomes.item(i)));
524     }
525     // Construct a new Genotype with the chromosomes and return it.
526
// ------------------------------------------------------------
527
return new Genotype(a_activeConfiguration, population);
528   }
529
530   /**
531    * Unmarshall a Genotype instance from a given XML Document representation.
532    * Its population of Chromosomes will be unmarshalled from the Chromosome
533    * sub-elements.
534    *
535    * @param a_activeConfiguration the current active Configuration object that
536    * is to be used during construction of the Genotype and Chromosome instances
537    * @param a_xmlDocument the XML Document representation of the Genotype
538    *
539    * @return A new Genotype instance, complete with a population of Chromosomes,
540    * setup with the data from the XML Document representation
541    *
542    * @throws ImproperXMLException if the given Document is improperly structured
543    * or missing data
544    * @throws InvalidConfigurationException if the given Configuration is in an
545    * inconsistent state
546    * @throws UnsupportedRepresentationException if the actively configured Gene
547    * implementation does not support the string representation of the alleles
548    * used in the given XML document
549    * @throws GeneCreationException if there is a problem creating or populating
550    * a Gene instance
551    *
552    * @author Neil Rotstan
553    * @since 1.0
554    */

555   public static Genotype getGenotypeFromDocument(
556       Configuration a_activeConfiguration, Document a_xmlDocument)
557       throws ImproperXMLException, InvalidConfigurationException,
558       UnsupportedRepresentationException, GeneCreationException {
559     // Extract the root element, which should be a genotype element.
560
// After verifying that the root element is not null and that it
561
// in fact is a genotype element, then convert it into a Genotype
562
// instance.
563
// --------------------------------------------------------------
564
Element rootElement = a_xmlDocument.getDocumentElement();
565     if (rootElement == null ||
566         ! (rootElement.getTagName().equals(GENOTYPE_TAG))) {
567       throw new ImproperXMLException(
568           "Unable to build Genotype from XML Document: " +
569           "'genotype' element must be at root of document.");
570     }
571     return getGenotypeFromElement(a_activeConfiguration, rootElement);
572   }
573
574   /**
575    * Unmarshall a Chromosome instance from a given XML Document
576    * representation. Its genes will be unmarshalled from the gene
577    * sub-elements.
578    *
579    * @param a_activeConfiguration the current active Configuration object that
580    * is to be used during construction of the Chromosome instances
581    * @param a_xmlDocument the XML Document representation of the Chromosome
582    *
583    * @return a new Chromosome instance setup with the data from the XML Document
584    * representation
585    *
586    * @throws ImproperXMLException if the given Document is improperly structured
587    * or missing data
588    * @throws InvalidConfigurationException if the given Configuration is in an
589    * inconsistent state
590    * @throws UnsupportedRepresentationException if the actively configured Gene
591    * implementation does not support the string representation of the alleles
592    * used in the given XML document
593    * @throws GeneCreationException if there is a problem creating or populating
594    * a Gene instance
595    *
596    * @author Neil Rotstan
597    * @since 1.0
598    */

599   public static Chromosome getChromosomeFromDocument(Configuration
600       a_activeConfiguration, Document a_xmlDocument)
601       throws ImproperXMLException, InvalidConfigurationException,
602       UnsupportedRepresentationException, GeneCreationException {
603     // Extract the root element, which should be a chromosome element.
604
// After verifying that the root element is not null and that it
605
// in fact is a chromosome element, then convert it into a Chromosome
606
// instance.
607
// ------------------------------------------------------------------
608
Element rootElement = a_xmlDocument.getDocumentElement();
609     if (rootElement == null ||
610         ! (rootElement.getTagName().equals(CHROMOSOME_TAG))) {
611       throw new ImproperXMLException(
612           "Unable to build Chromosome instance from XML Document: " +
613           "'chromosome' element must be at root of Document.");
614     }
615     return getChromosomeFromElement(a_activeConfiguration, rootElement);
616   }
617
618   /**
619    * Reads in an XML file and returns a Document object
620    * @param file the file to be read in
621    * @throws IOException
622    * @throws SAXException
623    * @return Document
624    *
625    * @author Klaus Meffert
626    * @since 2.0
627    */

628   public static Document readFile(File file)
629       throws IOException, org.xml.sax.SAXException JavaDoc {
630     return m_documentCreator.parse(file);
631   }
632
633   /**
634    * Writes an XML file from a Document object
635    * @param doc the Document object to be written to file
636    * @param file the file to be written
637    * @throws IOException
638    *
639    * @author Klaus Meffert
640    * @since 2.0
641    */

642   public static void writeFile(Document doc, File file)
643       throws IOException {
644     // Use a Transformer for output
645
TransformerFactory tFactory =
646         TransformerFactory.newInstance();
647     Transformer transformer;
648     try {
649       transformer = tFactory.newTransformer();
650     }
651     catch (TransformerConfigurationException tex) {
652       throw new IOException(tex.getMessage());
653     }
654     DOMSource source = new DOMSource(doc);
655     FileOutputStream fos = new FileOutputStream(file);
656     StreamResult result = new StreamResult(fos);
657     try {
658       transformer.transform(source, result);
659       fos.close();
660     }
661     catch (TransformerException tex) {
662       throw new IOException(tex.getMessage());
663     }
664   }
665 }
666
Popular Tags