XmlDataSetWriter.java

  1. /*
  2.  *
  3.  * The DbUnit Database Testing Framework
  4.  * Copyright (C)2002-2006, 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. package org.dbunit.dataset.xml;

  22. import java.io.IOException;
  23. import java.io.OutputStream;
  24. import java.io.UnsupportedEncodingException;
  25. import java.io.Writer;
  26. import java.nio.charset.Charset;

  27. import org.dbunit.dataset.Column;
  28. import org.dbunit.dataset.DataSetException;
  29. import org.dbunit.dataset.IDataSet;
  30. import org.dbunit.dataset.ITable;
  31. import org.dbunit.dataset.ITableMetaData;
  32. import org.dbunit.dataset.datatype.DataType;
  33. import org.dbunit.dataset.datatype.TypeCastException;
  34. import org.dbunit.dataset.stream.DataSetProducerAdapter;
  35. import org.dbunit.dataset.stream.IDataSetConsumer;
  36. import org.dbunit.util.xml.XmlWriter;
  37. import org.slf4j.Logger;
  38. import org.slf4j.LoggerFactory;

  39. /**
  40.  * @author Manuel Laflamme
  41.  * @author Last changed by: $Author$
  42.  * @version $Revision$ $Date$
  43.  * @since 1.5.5 (Jun 13, 2003)
  44.  */
  45. public class XmlDataSetWriter implements IDataSetConsumer
  46. {

  47.     /**
  48.      * Logger for this class
  49.      */
  50.     private static final Logger logger = LoggerFactory.getLogger(XmlDataSetWriter.class);

  51.     private static final String DATASET = "dataset";
  52.     private static final String TABLE = "table";
  53.     private static final String NAME = "name";
  54.     private static final String COLUMN = "column";
  55.     private static final String ROW = "row";
  56.     private static final String VALUE = "value";
  57.     private static final String NULL = "null";
  58.     private static final String NONE = "none";

  59.     static char[] CDATA_DETECTION_CHARS = new char[] {
  60.         0x20, '\n', '\r', '\t',     // whitespace
  61.         '&', '<',                   // forbidden char
  62.     };

  63.     private XmlWriter _xmlWriter;
  64.     private ITableMetaData _activeMetaData;
  65.     private boolean includeColumnComments = false;


  66.     /**
  67.      * @param outputStream The stream to which the XML will be written.
  68.      * @param encoding The encoding to be used for the {@link XmlWriter}.
  69.      * Can be null. See {@link XmlWriter#XmlWriter(OutputStream, String)}.
  70.      * @throws UnsupportedEncodingException
  71.      */
  72.     public XmlDataSetWriter(OutputStream outputStream, Charset charset)
  73.     {
  74.         _xmlWriter = new XmlWriter(outputStream, charset);
  75.         _xmlWriter.enablePrettyPrint(true);
  76.     }

  77.     public XmlDataSetWriter(Writer writer)
  78.     {
  79.         _xmlWriter = new XmlWriter(writer);
  80.         _xmlWriter.enablePrettyPrint(true);
  81.     }

  82.     public XmlDataSetWriter(Writer writer, Charset charset)
  83.     {
  84.         _xmlWriter = new XmlWriter(writer, charset);
  85.         _xmlWriter.enablePrettyPrint(true);
  86.     }

  87.     /**
  88.      * Enable or disable pretty print of the XML.
  89.      * @param enabled <code>true</code> to enable pretty print (which is the default).
  90.      * <code>false</code> otherwise.
  91.      * @since 2.4
  92.      */
  93.     public void setPrettyPrint(boolean enabled)
  94.     {
  95.         _xmlWriter.enablePrettyPrint(enabled);
  96.     }

  97.     /**
  98.      * Whether or not to write the column name as comment into the XML
  99.      * @param includeColumnComments Whether or not to write the column name as comment into the XML
  100.      */
  101.     public void setIncludeColumnComments(boolean includeColumnComments)
  102.     {
  103.       this.includeColumnComments = includeColumnComments;
  104.     }

  105.     /**
  106.      * Writes the given {@link IDataSet} using this writer.
  107.      * @param dataSet The {@link IDataSet} to be written
  108.      * @throws DataSetException
  109.      */
  110.     public void write(IDataSet dataSet) throws DataSetException
  111.     {
  112.         logger.trace("write(dataSet{}) - start", dataSet);

  113.         DataSetProducerAdapter provider = new DataSetProducerAdapter(dataSet);
  114.         provider.setConsumer(this);
  115.         provider.produce();
  116.     }

  117.     boolean needsCData(String text)
  118.     {
  119.         logger.trace("needsCData(text={}) - start", text);

  120.         if (text == null)
  121.         {
  122.             return false;
  123.         }

  124.         for (int i = 0; i < text.length(); i++)
  125.         {
  126.             char c = text.charAt(i);
  127.             for (int j = 0; j < CDATA_DETECTION_CHARS.length; j++)
  128.             {
  129.                 if (CDATA_DETECTION_CHARS[j] == c)
  130.                 {
  131.                     return true;
  132.                 }
  133.             }
  134.         }
  135.         return false;
  136.     }

  137.     ////////////////////////////////////////////////////////////////////////////
  138.     // IDataSetConsumer interface

  139.     public void startDataSet() throws DataSetException
  140.     {
  141.         logger.trace("startDataSet() - start");

  142.         try
  143.         {
  144.             _xmlWriter.writeDeclaration();
  145.             _xmlWriter.writeElement(DATASET);
  146.         }
  147.         catch (IOException e)
  148.         {
  149.             throw new DataSetException(e);
  150.         }
  151.     }

  152.     public void endDataSet() throws DataSetException
  153.     {
  154.         logger.trace("endDataSet() - start");

  155.         try
  156.         {
  157.             _xmlWriter.endElement();
  158.             _xmlWriter.close();
  159.         }
  160.         catch (IOException e)
  161.         {
  162.             throw new DataSetException(e);
  163.         }
  164.     }

  165.     public void startTable(ITableMetaData metaData) throws DataSetException
  166.     {
  167.         logger.trace("startTable(metaData={}) - start", metaData);

  168.         try
  169.         {
  170.             _activeMetaData = metaData;

  171.             String tableName = _activeMetaData.getTableName();
  172.             _xmlWriter.writeElement(TABLE);
  173.             _xmlWriter.writeAttribute(NAME, tableName);

  174.             Column[] columns = _activeMetaData.getColumns();
  175.             for (int i = 0; i < columns.length; i++)
  176.             {
  177.                 String columnName = columns[i].getColumnName();
  178.                 _xmlWriter.writeElementWithText(COLUMN, columnName);
  179.             }
  180.         }
  181.         catch (IOException e)
  182.         {
  183.             throw new DataSetException(e);
  184.         }

  185.     }

  186.     public void endTable() throws DataSetException
  187.     {
  188.         logger.trace("endTable() - start");

  189.         try
  190.         {
  191.             _xmlWriter.endElement();
  192.             _activeMetaData = null;
  193.         }
  194.         catch (IOException e)
  195.         {
  196.             throw new DataSetException(e);
  197.         }
  198.     }

  199.     public void row(Object[] values) throws DataSetException
  200.     {
  201.         logger.trace("row(values={}) - start", values);

  202.         try
  203.         {
  204.             _xmlWriter.writeElement(ROW);

  205.             Column[] columns = _activeMetaData.getColumns();
  206.             for (int i = 0; i < columns.length; i++)
  207.             {
  208.                 String columnName = columns[i].getColumnName();
  209.                 Object value = values[i];
  210.                
  211.                 // null
  212.                 if (value == null)
  213.                 {
  214.                     _xmlWriter.writeEmptyElement(NULL);
  215.                 }
  216.                 // none
  217.                 else if (value == ITable.NO_VALUE)
  218.                 {
  219.                     _xmlWriter.writeEmptyElement(NONE);
  220.                 }
  221.                 // values
  222.                 else
  223.                 {
  224.                     try
  225.                     {
  226.                         String stringValue = DataType.asString(value);

  227.                         _xmlWriter.writeElement(VALUE);
  228.                         if (needsCData(stringValue))
  229.                         {
  230.                             writeValueCData(stringValue);
  231.                         }
  232.                         else if (stringValue.length() > 0)
  233.                         {
  234.                             writeValue(stringValue);
  235.                         }
  236.                         _xmlWriter.endElement();
  237.                     }
  238.                     catch (TypeCastException e)
  239.                     {
  240.                         throw new DataSetException("table=" +
  241.                                 _activeMetaData.getTableName() + ", row=" + i +
  242.                                 ", column=" + columnName +
  243.                                 ", value=" + value, e);
  244.                     }
  245.                 }
  246.                 if ( this.includeColumnComments ) {
  247.                   _xmlWriter.writeComment( columnName );
  248.                 }
  249.             }
  250.             _xmlWriter.endElement();
  251.         }
  252.         catch (IOException e)
  253.         {
  254.             throw new DataSetException(e);
  255.         }
  256.     }

  257.     /**
  258.      * Writes the given String as CDATA using the {@link XmlWriter}.
  259.      * Can be overridden to add custom behavior.
  260.      * This implementation just invokes {@link XmlWriter#writeCData(String)}
  261.      * @param stringValue The value to be written
  262.      * @throws IOException
  263.      * @since 2.4.4
  264.      */
  265.     protected void writeValueCData(String stringValue) throws IOException
  266.     {
  267.         logger.trace("writeValueCData(stringValue={}) - start", stringValue);
  268.         _xmlWriter.writeCData(stringValue);
  269.     }
  270.    
  271.     /**
  272.      * Writes the given String as normal text using the {@link XmlWriter}.
  273.      * Can be overridden to add custom behavior.
  274.      * This implementation just invokes {@link XmlWriter#writeText(String)}.
  275.      * @param stringValue The value to be written
  276.      * @throws IOException
  277.      * @since 2.4.4
  278.      */
  279.     protected void writeValue(String stringValue) throws IOException
  280.     {
  281.         logger.trace("writeValue(stringValue={}) - start", stringValue);
  282.         _xmlWriter.writeText(stringValue);
  283.     }

  284.     /**
  285.      * @return The {@link XmlWriter} that is used for writing out XML.
  286.      * @since 2.4.4
  287.      */
  288.     protected final XmlWriter getXmlWriter()
  289.     {
  290.         return _xmlWriter;
  291.     }
  292. }