View Javadoc
1   /*
2    *
3    * The DbUnit Database Testing Framework
4    * Copyright (C)2002-2004, DbUnit.org
5    *
6    * This library is free software; you can redistribute it and/or
7    * modify it under the terms of the GNU Lesser General Public
8    * License as published by the Free Software Foundation; either
9    * version 2.1 of the License, or (at your option) any later version.
10   *
11   * This library is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   * Lesser General Public License for more details.
15   *
16   * You should have received a copy of the GNU Lesser General Public
17   * License along with this library; if not, write to the Free Software
18   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19   *
20   */
21  
22  package org.dbunit.dataset.xml;
23  
24  import org.slf4j.Logger;
25  import org.slf4j.LoggerFactory;
26  
27  import org.dbunit.dataset.CachedDataSet;
28  import org.dbunit.dataset.DataSetException;
29  import org.dbunit.dataset.IDataSet;
30  
31  import org.xml.sax.InputSource;
32  
33  import java.io.File;
34  import java.io.IOException;
35  import java.io.InputStream;
36  import java.io.OutputStream;
37  import java.io.Reader;
38  import java.io.Writer;
39  import java.net.URL;
40  
41  /**
42   * Reads and writes flat XML dataset document. Each XML element corresponds to a table row.
43   *       Each XML element name corresponds to a table name. The XML attributes
44   *       correspond to table columns.
45   * <p>
46   * Flat XML dataset document sample:
47   * <p>
48   * <pre>
49   * &lt;!DOCTYPE dataset SYSTEM "my-dataset.dtd"&gt;
50   * &lt;dataset&gt;
51   *     &lt;TEST_TABLE COL0="row 0 col 0"
52   *         COL1="row 0 col 1"
53   *         COL2="row 0 col 2"/&gt;
54   *     &lt;TEST_TABLE COL1="row 1 col 1"/&gt;
55   *     &lt;SECOND_TABLE COL0="row 0 col 0"
56   *           COL1="row 0 col 1" /&gt;
57   *     &lt;EMPTY_TABLE/&gt;
58   * &lt;/dataset&gt;</pre>
59   * <p>
60   * To specify null values, omit corresponding attribute.
61   * In the above example, missing COL0 and COL2 attributes of TEST_TABLE second row represents null values.
62   * <p>
63   * Table metadata is deduced from the first row of each table by default. 
64   * <b>Beware that DbUnit may think a table misses some columns if the first row of that table has one or more null values.</b>
65   * You can do one of the following things to avoid this:
66   * <ul>
67   * <li>Use a DTD. DbUnit will use the columns declared in the DTD as table metadata. 
68   * DbUnit only supports external system URI. The URI can be absolute or relative.
69   * </li>
70   * <li>Since DBUnit 2.3.0 there is a functionality called "column sensing" which basically 
71   * reads in the whole XML into a buffer and dynamically adds new columns as they appear. 
72   * It can be used as demonstrated in the following example:
73   * <pre>
74   *   // since dbunit 2.4.7
75   *   FlatXmlDataSetBuilder builder = new FlatXmlDataSetBuilder();
76   *   builder.setInputSource(new File("src/xml/flatXmlTableTest.xml"));
77   *   builder.setColumnSensing(true);
78   *   IDataSet dataSet = builder.build();
79   *   
80   *   // or dbunit release <= 2.4.6:
81   *   boolean enableColumnSensing = true;
82   *   IDataSet dataSet = new FlatXmlDataSet(
83   *            new File("src/xml/flatXmlTableTest.xml"), false, enableColumnSensing);
84   * </pre>
85   * </li>
86   * </ul>
87   * </p>
88   * 
89   * @author Manuel Laflamme
90   * @author gommma (gommma AT users.sourceforge.net)
91   * @author Last changed by: $Author$
92   * @version $Revision$ $Date$
93   * @since 1.0 (Mar 12, 2002) 
94   */
95  public class FlatXmlDataSet extends CachedDataSet
96  {
97      /**
98       * Logger for this class
99       */
100     private static final Logger logger = LoggerFactory.getLogger(FlatXmlDataSet.class);
101 
102     /**
103      * Creates a new {@link FlatXmlDataSet} with the data of the given producer.
104      * @param flatXmlProducer The producer that provides the {@link FlatXmlDataSet} content
105      * @throws DataSetException 
106      * @since 2.4.7
107      */
108     public FlatXmlDataSet(FlatXmlProducer flatXmlProducer) throws DataSetException
109     {
110         super(flatXmlProducer, flatXmlProducer.isCaseSensitiveTableNames());
111     }
112     
113     /**
114      * Creates an FlatXmlDataSet object with the specified InputSource.
115      * @deprecated since 2.4.7 - use {@link FlatXmlDataSetBuilder} to create a {@link FlatXmlDataSet}
116      */
117     public FlatXmlDataSet(InputSource source) throws IOException, DataSetException
118     {
119         super(new FlatXmlProducer(source));
120     }
121 
122     /**
123      * Creates an FlatXmlDataSet object with the specified xml file.
124      * Relative DOCTYPE uri are resolved from the xml file path.
125      *
126      * @param xmlFile the xml file
127      * @deprecated since 2.4.7 - use {@link FlatXmlDataSetBuilder} to create a {@link FlatXmlDataSet}
128      */
129     public FlatXmlDataSet(File xmlFile) throws IOException, DataSetException
130     {
131         this(xmlFile, true);
132     }
133 
134     /**
135      * Creates an FlatXmlDataSet object with the specified xml file.
136      * Relative DOCTYPE uri are resolved from the xml file path.
137      *
138      * @param xmlFile the xml file
139      * @param dtdMetadata if <code>false</code> do not use DTD as metadata
140      * @deprecated since 2.4.7 - use {@link FlatXmlDataSetBuilder} to create a {@link FlatXmlDataSet}
141      */
142     public FlatXmlDataSet(File xmlFile, boolean dtdMetadata)
143             throws IOException, DataSetException
144     {
145         this(xmlFile.toURL(), dtdMetadata);
146     }
147 
148     /**
149      * Creates an FlatXmlDataSet object with the specified xml file.
150      * Relative DOCTYPE uri are resolved from the xml file path.
151      *
152      * @param xmlFile the xml file
153      * @param dtdMetadata if <code>false</code> do not use DTD as metadata
154      * @param columnSensing Whether or not the columns should be sensed automatically. Every XML row
155      * is scanned for columns that have not been there in a previous column.
156      * @deprecated since 2.4.7 - use {@link FlatXmlDataSetBuilder} to create a {@link FlatXmlDataSet}
157      */
158     public FlatXmlDataSet(File xmlFile, boolean dtdMetadata, boolean columnSensing)
159             throws IOException, DataSetException
160     {
161         this(xmlFile.toURL(), dtdMetadata, columnSensing);
162     }
163 
164     /**
165      * Creates an FlatXmlDataSet object with the specified xml file.
166      * Relative DOCTYPE uri are resolved from the xml file path.
167      *
168      * @param xmlFile the xml file
169      * @param dtdMetadata if <code>false</code> do not use DTD as metadata
170      * @param columnSensing Whether or not the columns should be sensed automatically. Every XML row
171      * is scanned for columns that have not been there in a previous column.
172      * @param caseSensitiveTableNames Whether or not this dataset should use case sensitive table names
173      * @deprecated since 2.4.7 - use {@link FlatXmlDataSetBuilder} to create a {@link FlatXmlDataSet}
174      */
175     public FlatXmlDataSet(File xmlFile, boolean dtdMetadata, boolean columnSensing, boolean caseSensitiveTableNames)
176     throws IOException, DataSetException
177     {
178         this(xmlFile.toURL(), dtdMetadata, columnSensing, caseSensitiveTableNames);
179     }
180 
181     /**
182      * Creates an FlatXmlDataSet object with the specified xml URL.
183      * Relative DOCTYPE uri are resolved from the xml file path.
184      *
185      * @param xmlUrl the xml URL
186      * @deprecated since 2.4.7 - use {@link FlatXmlDataSetBuilder} to create a {@link FlatXmlDataSet}
187      */
188     public FlatXmlDataSet(URL xmlUrl) throws IOException, DataSetException
189     {
190         this(xmlUrl, true);
191     }
192 
193     /**
194      * Creates an FlatXmlDataSet object with the specified xml URL.
195      * Relative DOCTYPE uri are resolved from the xml file path.
196      *
197      * @param xmlUrl the xml URL
198      * @param dtdMetadata if <code>false</code> do not use DTD as metadata
199      * @deprecated since 2.4.7 - use {@link FlatXmlDataSetBuilder} to create a {@link FlatXmlDataSet}
200      */
201     public FlatXmlDataSet(URL xmlUrl, boolean dtdMetadata)
202             throws IOException, DataSetException
203     {
204         this(xmlUrl, dtdMetadata, false);
205     }
206     
207 
208     /**
209      * Creates an FlatXmlDataSet object with the specified xml URL.
210      * Relative DOCTYPE uri are resolved from the xml file path.
211      *
212      * @param xmlUrl the xml URL
213      * @param dtdMetadata if <code>false</code> do not use DTD as metadata
214      * @param columnSensing Whether or not the columns should be sensed automatically. Every XML row
215      * is scanned for columns that have not been there in a previous column.
216      * @deprecated since 2.4.7 - use {@link FlatXmlDataSetBuilder} to create a {@link FlatXmlDataSet}
217      */
218     public FlatXmlDataSet(URL xmlUrl, boolean dtdMetadata, boolean columnSensing)
219     throws IOException, DataSetException
220     {
221         super(new FlatXmlProducer(
222                 new InputSource(xmlUrl.toString()), dtdMetadata, columnSensing));
223     }
224 
225     /**
226      * Creates an FlatXmlDataSet object with the specified xml file.
227      * Relative DOCTYPE uri are resolved from the xml file path.
228      *
229      * @param xmlUrl the xml file
230      * @param dtdMetadata if <code>false</code> do not use DTD as metadata
231      * @param columnSensing Whether or not the columns should be sensed automatically. Every XML row
232      * is scanned for columns that have not been there in a previous column.
233      * @param caseSensitiveTableNames Whether or not this dataset should use case sensitive table names
234      * @deprecated since 2.4.7 - use {@link FlatXmlDataSetBuilder} to create a {@link FlatXmlDataSet}
235      */
236     public FlatXmlDataSet(URL xmlUrl, boolean dtdMetadata, boolean columnSensing, boolean caseSensitiveTableNames)
237     throws IOException, DataSetException
238     {
239         super(new FlatXmlProducer(
240                   new InputSource(xmlUrl.toString()), dtdMetadata, columnSensing, caseSensitiveTableNames), 
241               caseSensitiveTableNames);
242     }
243 
244     /**
245      * Creates an FlatXmlDataSet object with the specified xml reader.
246      * Relative DOCTYPE uri are resolved from the current working directory.
247      *
248      * @param xmlReader the xml reader
249      * @deprecated since 2.4.7 - use {@link FlatXmlDataSetBuilder} to create a {@link FlatXmlDataSet}
250      */
251     public FlatXmlDataSet(Reader xmlReader) throws IOException, DataSetException
252     {
253         this(xmlReader, true);
254     }
255 
256     /**
257      * Creates an FlatXmlDataSet object with the specified xml reader.
258      * Relative DOCTYPE uri are resolved from the current working directory.
259      *
260      * @param xmlReader the xml reader
261      * @param dtdMetadata if <code>false</code> do not use DTD as metadata
262      * @deprecated since 2.4.7 - use {@link FlatXmlDataSetBuilder} to create a {@link FlatXmlDataSet}
263      */
264     public FlatXmlDataSet(Reader xmlReader, boolean dtdMetadata)
265             throws IOException, DataSetException
266     {
267         this(xmlReader, dtdMetadata, false, false);
268     }
269 
270     /**
271      * Creates an FlatXmlDataSet object with the specified xml file.
272      * Relative DOCTYPE uri are resolved from the xml file path.
273      *
274      * @param xmlReader the xml reader
275      * @param dtdMetadata if <code>false</code> do not use DTD as metadata
276      * @param columnSensing Whether or not the columns should be sensed automatically. Every XML row
277      * is scanned for columns that have not been there in a previous column.
278      * @param caseSensitiveTableNames Whether or not this dataset should use case sensitive table names
279      * @since 2.4.3
280      * @deprecated since 2.4.7 - use {@link FlatXmlDataSetBuilder} to create a {@link FlatXmlDataSet}
281      */
282     public FlatXmlDataSet(Reader xmlReader, boolean dtdMetadata, boolean columnSensing, boolean caseSensitiveTableNames)
283     throws IOException, DataSetException
284     {
285         super(new FlatXmlProducer(new InputSource(xmlReader), dtdMetadata, columnSensing, caseSensitiveTableNames),
286                 caseSensitiveTableNames);
287     }
288 
289     /**
290      * Creates an FlatXmlDataSet object with the specified xml and dtd readers.
291      *
292      * @param xmlReader the xml reader
293      * @param dtdReader the dtd reader
294      * @deprecated since 2.4.7 - use {@link FlatXmlDataSetBuilder} to create a {@link FlatXmlDataSet}
295      */
296     public FlatXmlDataSet(Reader xmlReader, Reader dtdReader)
297             throws IOException, DataSetException
298     {
299         this(xmlReader, new FlatDtdDataSet(dtdReader));
300     }
301 
302     /**
303      * Creates an FlatXmlDataSet object with the specified xml reader.
304      *
305      * @param xmlReader the xml reader
306      * @param metaDataSet the dataset used as metadata source.
307      * @deprecated since 2.4.7 - use {@link FlatXmlDataSetBuilder} to create a {@link FlatXmlDataSet}
308      */
309     public FlatXmlDataSet(Reader xmlReader, IDataSet metaDataSet)
310             throws IOException, DataSetException
311     {
312         super(new FlatXmlProducer(new InputSource(xmlReader), metaDataSet));
313     }
314 
315     /**
316      * Creates an FlatXmlDataSet object with the specified xml input stream.
317      * Relative DOCTYPE uri are resolved from the current working directory.
318      *
319      * @param xmlStream the xml input stream
320      * @deprecated since 2.4.7 - use {@link FlatXmlDataSetBuilder} to create a {@link FlatXmlDataSet}
321      */
322     public FlatXmlDataSet(InputStream xmlStream) throws IOException, DataSetException
323     {
324         this(xmlStream, true);
325     }
326 
327     /**
328      * Creates an FlatXmlDataSet object with the specified xml input stream.
329      * Relative DOCTYPE uri are resolved from the current working directory.
330      *
331      * @param xmlStream the xml input stream
332      * @param dtdMetadata if <code>false</code> do not use DTD as metadata
333      * @deprecated since 2.4.7 - use {@link FlatXmlDataSetBuilder} to create a {@link FlatXmlDataSet}
334      */
335     public FlatXmlDataSet(InputStream xmlStream, boolean dtdMetadata)
336             throws IOException, DataSetException
337     {
338         super(new FlatXmlProducer(new InputSource(xmlStream), dtdMetadata));
339     }
340 
341     /**
342      * Creates an FlatXmlDataSet object with the specified xml and dtd input
343      * stream.
344      *
345      * @param xmlStream the xml input stream
346      * @param dtdStream the dtd input stream
347      * @deprecated since 2.4.7 - use {@link FlatXmlDataSetBuilder} to create a {@link FlatXmlDataSet}
348      */
349     public FlatXmlDataSet(InputStream xmlStream, InputStream dtdStream)
350             throws IOException, DataSetException
351     {
352         this(xmlStream, new FlatDtdDataSet(dtdStream));
353     }
354 
355     /**
356      * Creates an FlatXmlDataSet object with the specified xml input stream.
357      *
358      * @param xmlStream the xml input stream
359      * @param metaDataSet the dataset used as metadata source.
360      * @deprecated since 2.4.7 - use {@link FlatXmlDataSetBuilder} to create a {@link FlatXmlDataSet}
361      */
362     public FlatXmlDataSet(InputStream xmlStream, IDataSet metaDataSet)
363             throws IOException, DataSetException
364     {
365         super(new FlatXmlProducer(new InputSource(xmlStream), metaDataSet));
366     }
367 
368     /**
369      * Write the specified dataset to the specified output stream as xml.
370      */
371     public static void write(IDataSet dataSet, OutputStream out)
372             throws IOException, DataSetException
373     {
374         logger.debug("write(dataSet={}, out={}) - start", dataSet, out);
375 
376         FlatXmlWriter datasetWriter = new FlatXmlWriter(out);
377         datasetWriter.setIncludeEmptyTable(true);
378         datasetWriter.write(dataSet);
379     }
380 
381     /**
382      * Write the specified dataset to the specified writer as xml.
383      */
384     public static void write(IDataSet dataSet, Writer writer)
385             throws IOException, DataSetException
386     {
387         logger.debug("write(dataSet={}, writer={}) - start", dataSet, writer);
388         write(dataSet, writer, null);
389     }
390 
391     /**
392      * Write the specified dataset to the specified writer as xml.
393      */
394     public static void write(IDataSet dataSet, Writer writer, String encoding)
395             throws IOException, DataSetException
396     {
397     	if (logger.isDebugEnabled())
398     	{
399     		logger.debug("write(dataSet={}, writer={}, encoding={}) - start",
400     				new Object[]{ dataSet, writer, encoding });
401     	}
402 
403         FlatXmlWriter datasetWriter = new FlatXmlWriter(writer, encoding);
404         datasetWriter.setIncludeEmptyTable(true);
405         datasetWriter.write(dataSet);
406     }
407 
408     /**
409      * Write a DTD for the specified dataset to the specified output.
410      * @deprecated use {@link FlatDtdDataSet#write}
411      */
412     public static void writeDtd(IDataSet dataSet, OutputStream out)
413             throws IOException, DataSetException
414     {
415         logger.debug("writeDtd(dataSet={}, out={}) - start", dataSet, out);
416         FlatDtdDataSet.write(dataSet, out);
417     }
418 }
419 
420 
421 
422 
423 
424 
425 
426 
427 
428 
429 
430