← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 6579: Implemented CSV import and export of data value set. Useful for bootstrapping and interoperating ...

 

------------------------------------------------------------
revno: 6579
committer: Lars Helge Overland <larshelge@xxxxxxxxx>
branch nick: dhis2
timestamp: Sat 2012-04-14 20:32:00 +0200
message:
  Implemented CSV import and export of data value set. Useful for bootstrapping and interoperating with external systems.
added:
  dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalue/StreamingCsvDataValue.java
  dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/StreamingCsvDataValueSet.java
modified:
  dhis-2/dhis-dxf2/pom.xml
  dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/DataValueSetService.java
  dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/DataValueSetStore.java
  dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/DefaultDataValueSetService.java
  dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/SpringDataValueSetStore.java
  dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/lists.js
  dhis-2/dhis-web/dhis-web-importexport/src/main/java/org/hisp/dhis/importexport/action/datavalue/ExportDataValueAction.java
  dhis-2/dhis-web/dhis-web-importexport/src/main/resources/org/hisp/dhis/importexport/i18n_module.properties
  dhis-2/dhis-web/dhis-web-importexport/src/main/webapp/dhis-web-importexport/exportDataValueForm.vm
  dhis-2/dhis-web/dhis-web-importexport/src/main/webapp/dhis-web-importexport/javascript/export.js
  dhis-2/pom.xml


--
lp:dhis2
https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk

Your team DHIS 2 developers is subscribed to branch lp:dhis2.
To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription
=== modified file 'dhis-2/dhis-dxf2/pom.xml'
--- dhis-2/dhis-dxf2/pom.xml	2012-03-30 13:07:32 +0000
+++ dhis-2/dhis-dxf2/pom.xml	2012-04-14 18:32:00 +0000
@@ -36,6 +36,10 @@
       <groupId>org.hisp.dhis</groupId>
       <artifactId>dhis-support-xml</artifactId>
     </dependency>
+    <dependency>
+	  <groupId>net.sf.opencsv</groupId>
+	  <artifactId>opencsv</artifactId>
+    </dependency>
 	
     <dependency>
       <groupId>org.codehaus.jackson</groupId>

=== added file 'dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalue/StreamingCsvDataValue.java'
--- dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalue/StreamingCsvDataValue.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalue/StreamingCsvDataValue.java	2012-04-14 18:32:00 +0000
@@ -0,0 +1,179 @@
+package org.hisp.dhis.dxf2.datavalue;
+
+/*
+ * Copyright (c) 2011, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ *   list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * * Neither the name of the HISP project nor the names of its contributors may
+ *   be used to endorse or promote products derived from this software without
+ *   specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import static org.hisp.dhis.system.util.TextUtils.valueOf;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import au.com.bytecode.opencsv.CSVWriter;
+
+public class StreamingCsvDataValue
+    extends DataValue
+{
+    private CSVWriter writer;
+    
+    private List<String> values;
+    
+    public StreamingCsvDataValue( CSVWriter writer )
+    {
+        this.writer = writer;
+        this.values = new ArrayList<String>();
+    }
+    
+    public StreamingCsvDataValue( String[] row )
+    {
+        this.values = Arrays.asList( row );
+    }
+    
+    //--------------------------------------------------------------------------
+    // Getters
+    //--------------------------------------------------------------------------
+
+    @Override
+    public String getDataElement()
+    {
+        return dataElement = dataElement == null ? values.get( 0 ) : dataElement;
+    }
+
+    @Override
+    public String getPeriod()
+    {
+        return period = period == null ? values.get( 1 ) : period;
+    }
+
+    @Override
+    public String getOrgUnit()
+    {
+        return orgUnit = orgUnit == null ? values.get( 2 ) : orgUnit;
+    }
+
+    @Override
+    public String getCategoryOptionCombo()
+    {
+        return categoryOptionCombo = categoryOptionCombo == null ? values.get( 3 ) : categoryOptionCombo;
+    }
+
+    @Override
+    public String getValue()
+    {
+        return value = value == null ? values.get( 4 ) : value;
+    }
+
+    @Override
+    public String getStoredBy()
+    {
+        return storedBy = storedBy == null ? values.get( 5 ) : storedBy;
+    }
+
+    @Override
+    public String getTimestamp()
+    {
+        return timestamp = timestamp == null ? values.get( 6 ) : timestamp;
+    }
+
+    @Override
+    public String getComment()
+    {
+        return comment = comment == null ? values.get( 7 ) : comment;
+    }
+
+    @Override
+    public Boolean getFollowup()
+    {
+        return followup = followup == null ? valueOf( values.get( 8 ) ) : followup;
+    }
+
+    //--------------------------------------------------------------------------
+    // Setters
+    //--------------------------------------------------------------------------
+
+    @Override
+    public void setDataElement( String dataElement )
+    {
+        values.add( dataElement );
+    }
+
+    @Override
+    public void setPeriod( String period )
+    {
+        values.add( period );
+    }
+
+    @Override
+    public void setOrgUnit( String orgUnit )
+    {
+        values.add( orgUnit );
+    }
+
+    @Override
+    public void setCategoryOptionCombo( String categoryOptionCombo )
+    {
+        values.add( categoryOptionCombo );
+    }
+
+    @Override
+    public void setValue( String value )
+    {
+        values.add( value );
+    }
+
+    @Override
+    public void setStoredBy( String storedBy )
+    {
+        values.add( storedBy );
+    }
+
+    @Override
+    public void setTimestamp( String timestamp )
+    {
+        values.add( timestamp );
+    }
+
+    @Override
+    public void setComment( String comment )
+    {
+        values.add( comment );
+    }
+
+    @Override
+    public void setFollowup( Boolean followup )
+    {
+        values.add( valueOf( followup ) );
+    }
+
+    @Override
+    public void close()
+    {
+        String[] row = new String[values.size()];
+        
+        writer.writeNext( values.toArray( row ) );
+    }
+}

=== modified file 'dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/DataValueSetService.java'
--- dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/DataValueSetService.java	2012-04-13 20:09:02 +0000
+++ dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/DataValueSetService.java	2012-04-14 18:32:00 +0000
@@ -29,6 +29,7 @@
 
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.io.Writer;
 import java.util.Date;
 import java.util.Set;
 
@@ -42,6 +43,8 @@
     
     void writeDataValueSet( Set<String> dataSets, Date startDate, Date endDate, Set<String> orgUnits, OutputStream out );
     
+    void writeDataValueSetCsv( Set<String> dataSets, Date startDate, Date endDate, Set<String> orgUnits, Writer writer );
+    
     ImportSummary saveDataValueSet( InputStream in );
 
     ImportSummary saveDataValueSet( InputStream in, ImportOptions importOptions );

=== modified file 'dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/DataValueSetStore.java'
--- dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/DataValueSetStore.java	2012-04-13 20:09:02 +0000
+++ dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/DataValueSetStore.java	2012-04-14 18:32:00 +0000
@@ -28,6 +28,7 @@
  */
 
 import java.io.OutputStream;
+import java.io.Writer;
 import java.util.Date;
 import java.util.Set;
 
@@ -38,6 +39,9 @@
 
 public interface DataValueSetStore
 {
-    public void writeDataValueSet( DataSet dataSet, Date completeDate, Period period, OrganisationUnit orgUnit, 
+    public void writeDataValueSetXml( DataSet dataSet, Date completeDate, Period period, OrganisationUnit orgUnit, 
         Set<DataElement> dataElements, Set<Period> periods, Set<OrganisationUnit> orgUnits, OutputStream out );
+    
+    public void writeDataValueSetCsv( Set<DataElement> dataElements, 
+        Set<Period> periods, Set<OrganisationUnit> orgUnits, Writer writer );
 }

=== modified file 'dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/DefaultDataValueSetService.java'
--- dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/DefaultDataValueSetService.java	2012-04-13 20:09:02 +0000
+++ dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/DefaultDataValueSetService.java	2012-04-14 18:32:00 +0000
@@ -37,6 +37,7 @@
 
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.io.Writer;
 import java.util.Date;
 import java.util.HashSet;
 import java.util.Map;
@@ -146,42 +147,21 @@
         
         period_ = periodService.reloadPeriod( period_ );
         
-        dataValueSetStore.writeDataValueSet( dataSet_, completeDate, period_, orgUnit_, dataSet_.getDataElements(), wrap( period_ ), wrap( orgUnit_ ), out );
+        dataValueSetStore.writeDataValueSetXml( dataSet_, completeDate, period_, orgUnit_, dataSet_.getDataElements(), wrap( period_ ), wrap( orgUnit_ ), out );
     }
 
     public void writeDataValueSet( Set<String> dataSets, Date startDate, Date endDate, Set<String> orgUnits, OutputStream out )
     {
-        Set<DataElement> dataElements = new HashSet<DataElement>();
-        
-        for ( String ds : dataSets )
-        {
-            DataSet dataSet = dataSetService.getDataSet( ds );
-            
-            if ( dataSet == null )
-            {
-                throw new IllegalArgumentException( ERROR_INVALID_DATA_SET + ds );
-            }
-            
-            dataElements.addAll( dataSet.getDataElements() );
-        }
-        
-        Set<Period> periods = new HashSet<Period>( periodService.getPeriodsBetweenDates( startDate, endDate ) );
-        
-        Set<OrganisationUnit> organisationUnits = new HashSet<OrganisationUnit>();
-        
-        for ( String ou : orgUnits )
-        {
-            OrganisationUnit orgUnit = organisationUnitService.getOrganisationUnit( ou );            
-
-            if ( orgUnit == null )
-            {
-                throw new IllegalArgumentException( ERROR_INVALID_ORG_UNIT + ou );
-            }
-            
-            organisationUnits.add( orgUnit );
-        }
-        
-        dataValueSetStore.writeDataValueSet( null, null, null, null, dataElements, periods, organisationUnits, out );
+        Set<Period> periods = new HashSet<Period>( periodService.getPeriodsBetweenDates( startDate, endDate ) );
+        
+        dataValueSetStore.writeDataValueSetXml( null, null, null, null, getDataElements( dataSets ), periods, getOrgUnits( orgUnits ), out );
+    }
+    
+    public void writeDataValueSetCsv( Set<String> dataSets, Date startDate, Date endDate, Set<String> orgUnits, Writer writer )
+    {
+        Set<Period> periods = new HashSet<Period>( periodService.getPeriodsBetweenDates( startDate, endDate ) );
+        
+        dataValueSetStore.writeDataValueSetCsv( getDataElements( dataSets ), periods, getOrgUnits( orgUnits ), writer );
     }
     
     public ImportSummary saveDataValueSet( InputStream in )
@@ -362,4 +342,42 @@
         
         summary.setDataSetComplete( DateUtils.getMediumDateString( completeDate ) );
     }
+    
+    private Set<DataElement> getDataElements( Set<String> dataSets )
+    {
+        Set<DataElement> dataElements = new HashSet<DataElement>();
+        
+        for ( String ds : dataSets )
+        {
+            DataSet dataSet = dataSetService.getDataSet( ds );
+            
+            if ( dataSet == null )
+            {
+                throw new IllegalArgumentException( ERROR_INVALID_DATA_SET + ds );
+            }
+            
+            dataElements.addAll( dataSet.getDataElements() );
+        }
+        
+        return dataElements;
+    }
+    
+    public Set<OrganisationUnit> getOrgUnits( Set<String> orgUnits )
+    {
+        Set<OrganisationUnit> organisationUnits = new HashSet<OrganisationUnit>();
+        
+        for ( String ou : orgUnits )
+        {
+            OrganisationUnit orgUnit = organisationUnitService.getOrganisationUnit( ou );            
+
+            if ( orgUnit == null )
+            {
+                throw new IllegalArgumentException( ERROR_INVALID_ORG_UNIT + ou );
+            }
+            
+            organisationUnits.add( orgUnit );
+        }
+        
+        return organisationUnits;
+    }
 }

=== modified file 'dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/SpringDataValueSetStore.java'
--- dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/SpringDataValueSetStore.java	2012-04-14 16:34:07 +0000
+++ dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/SpringDataValueSetStore.java	2012-04-14 18:32:00 +0000
@@ -32,12 +32,12 @@
 import static org.hisp.dhis.system.util.TextUtils.getCommaDelimitedString;
 
 import java.io.OutputStream;
+import java.io.Writer;
 import java.util.Collection;
 import java.util.Date;
 import java.util.Set;
 
 import org.amplecode.staxwax.factory.XMLFactory;
-import org.amplecode.staxwax.writer.XMLWriter;
 import org.hisp.dhis.dataelement.DataElement;
 import org.hisp.dhis.dataset.DataSet;
 import org.hisp.dhis.dxf2.datavalue.DataValue;
@@ -48,6 +48,8 @@
 import org.springframework.jdbc.core.JdbcTemplate;
 import org.springframework.jdbc.support.rowset.SqlRowSet;
 
+import au.com.bytecode.opencsv.CSVWriter;
+
 public class SpringDataValueSetStore
     implements DataValueSetStore
 {
@@ -58,14 +60,26 @@
     // DataValueSetStore implementation
     //--------------------------------------------------------------------------
 
-    public void writeDataValueSet( DataSet dataSet, Date completeDate, Period period, OrganisationUnit orgUnit, 
+    public void writeDataValueSetXml( DataSet dataSet, Date completeDate, Period period, OrganisationUnit orgUnit, 
         Set<DataElement> dataElements, Set<Period> periods, Set<OrganisationUnit> orgUnits, OutputStream out )
     {
-        XMLWriter writer = XMLFactory.getXMLWriter( out );
-        
+        DataValueSet dataValueSet = new StreamingDataValueSet( XMLFactory.getXMLWriter( out ) );
+        
+        writeDataValueSet( dataSet, completeDate, period, orgUnit, dataElements, periods, orgUnits, dataValueSet );        
+    }
+    
+    public void writeDataValueSetCsv( Set<DataElement> dataElements, Set<Period> periods, Set<OrganisationUnit> orgUnits, Writer writer )
+    {
+        DataValueSet dataValueSet = new StreamingCsvDataValueSet( new CSVWriter( writer ) );
+        
+        writeDataValueSet( null, null, null, null, dataElements, periods, orgUnits, dataValueSet );
+    }
+    
+    private void writeDataValueSet( DataSet dataSet, Date completeDate, Period period, OrganisationUnit orgUnit, 
+        Set<DataElement> dataElements, Set<Period> periods, Set<OrganisationUnit> orgUnits, DataValueSet dataValueSet )
+    {        
         SqlRowSet rowSet = jdbcTemplate.queryForRowSet( getDataValueSql( dataElements, periods, orgUnits ) );
 
-        DataValueSet dataValueSet = new StreamingDataValueSet( writer );
         dataValueSet.setDataSet( dataSet != null ? dataSet.getUid() : null );
         dataValueSet.setCompleteDate( getMediumDateString( completeDate ) );
         dataValueSet.setPeriod( period != null ? period.getIsoDate() : null );

=== added file 'dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/StreamingCsvDataValueSet.java'
--- dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/StreamingCsvDataValueSet.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-dxf2/src/main/java/org/hisp/dhis/dxf2/datavalueset/StreamingCsvDataValueSet.java	2012-04-14 18:32:00 +0000
@@ -0,0 +1,94 @@
+package org.hisp.dhis.dxf2.datavalueset;
+
+/*
+ * Copyright (c) 2011, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright notice, this
+ *   list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ *   this list of conditions and the following disclaimer in the documentation
+ *   and/or other materials provided with the distribution.
+ * * Neither the name of the HISP project nor the names of its contributors may
+ *   be used to endorse or promote products derived from this software without
+ *   specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+import java.io.IOException;
+
+import org.hisp.dhis.dxf2.datavalue.DataValue;
+import org.hisp.dhis.dxf2.datavalue.StreamingCsvDataValue;
+
+import au.com.bytecode.opencsv.CSVReader;
+import au.com.bytecode.opencsv.CSVWriter;
+
+public class StreamingCsvDataValueSet
+    extends DataValueSet
+{
+    private CSVWriter writer;
+    
+    private CSVReader reader;
+    
+    private String[] nextRow;
+    
+    public StreamingCsvDataValueSet( CSVWriter writer )
+    {
+        this.writer = writer;
+    }
+    
+    public StreamingCsvDataValueSet( CSVReader reader )
+    {
+        this.reader = reader;
+    }
+    
+    @Override
+    public boolean hasNextDataValue()
+    {
+        try
+        {
+            return ( nextRow = reader.readNext() ) != null;            
+        }
+        catch ( IOException ex )
+        {
+            throw new RuntimeException( ex );
+        }
+    }
+
+    @Override
+    public DataValue getNextDataValue()
+    {
+        return new StreamingCsvDataValue( nextRow );
+    }
+
+    @Override
+    public DataValue getDataValueInstance()
+    {
+        return new StreamingCsvDataValue( writer );
+    }
+
+    @Override
+    public void close()
+    {
+        try
+        {
+            writer.close();
+        }
+        catch ( IOException ex )
+        {
+            throw new RuntimeException( ex );
+        }
+    }    
+}

=== modified file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/lists.js'
--- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/lists.js	2011-06-19 11:30:00 +0000
+++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/javascripts/lists.js	2012-04-14 18:32:00 +0000
@@ -309,7 +309,7 @@
  * Creates a hidden select list used for temporarily storing options for
  * filtering
  * 
- * TODO: avoid performance hit on page with many selects, by checking use of
+ * TODO: REMOVE! avoid performance hit on page with many selects, by checking use of
  * filterList method
  */
 $(document).ready(function() {

=== modified file 'dhis-2/dhis-web/dhis-web-importexport/src/main/java/org/hisp/dhis/importexport/action/datavalue/ExportDataValueAction.java'
--- dhis-2/dhis-web/dhis-web-importexport/src/main/java/org/hisp/dhis/importexport/action/datavalue/ExportDataValueAction.java	2012-04-13 22:28:40 +0000
+++ dhis-2/dhis-web/dhis-web-importexport/src/main/java/org/hisp/dhis/importexport/action/datavalue/ExportDataValueAction.java	2012-04-14 18:32:00 +0000
@@ -29,6 +29,7 @@
 
 import static org.hisp.dhis.system.util.DateUtils.getMediumDate;
 import static org.hisp.dhis.system.util.CodecUtils.filenameEncode;
+import static org.hisp.dhis.util.ContextUtils.*;
 
 import java.util.Collection;
 import java.util.HashSet;
@@ -54,7 +55,9 @@
 {
     private final static String FILE_PREFIX = "Export";
     private final static String FILE_SEPARATOR = "_";
-    private final static String FILE_EXTENSION = ".xml";
+    private final static String EXTENSION_XML = ".xml";
+    private final static String EXTENSION_CSV = ".csv";
+    private final static String FORMAT_CSV = "csv";
 
     @Autowired
     private SelectionTreeManager selectionTreeManager;
@@ -90,6 +93,13 @@
         this.endDate = endDate;
     }
 
+    private String exportFormat;
+
+    public void setExportFormat( String exportFormat )
+    {
+        this.exportFormat = exportFormat;
+    }
+
     // -------------------------------------------------------------------------
     // Action implementation
     // -------------------------------------------------------------------------
@@ -111,9 +121,18 @@
         
         HttpServletResponse response = ServletActionContext.getResponse();
         
-        ContextUtils.configureResponse( response, ContextUtils.CONTENT_TYPE_XML, true, getFileName(), true );
-        
-        dataValueSetService.writeDataValueSet( selectedDataSets, getMediumDate( startDate ), getMediumDate( endDate ), orgUnits, response.getOutputStream() );
+        if ( FORMAT_CSV.equals( exportFormat ) )
+        {
+            ContextUtils.configureResponse( response, CONTENT_TYPE_CSV, true, getFileName( EXTENSION_CSV ), true );
+            
+            dataValueSetService.writeDataValueSetCsv( selectedDataSets,getMediumDate( startDate ), getMediumDate( endDate ), orgUnits, response.getWriter() );
+        }
+        else
+        {
+            ContextUtils.configureResponse( response, CONTENT_TYPE_XML, true, getFileName( EXTENSION_XML ), true );
+            
+            dataValueSetService.writeDataValueSet( selectedDataSets, getMediumDate( startDate ), getMediumDate( endDate ), orgUnits, response.getOutputStream() );
+        }
                 
         return SUCCESS;
     }
@@ -122,7 +141,7 @@
     // Supportive methods
     // -------------------------------------------------------------------------
 
-    private String getFileName()
+    private String getFileName( String extension )
     {
         String fileName = FILE_PREFIX + FILE_SEPARATOR + startDate + FILE_SEPARATOR + endDate;
         
@@ -131,8 +150,6 @@
             fileName += FILE_SEPARATOR + filenameEncode( selectionTreeManager.getSelectedOrganisationUnits().iterator().next().getShortName() );
         }
         
-        fileName += FILE_EXTENSION;
-        
-        return fileName;
+        return fileName + extension;
     }
 }

=== modified file 'dhis-2/dhis-web/dhis-web-importexport/src/main/resources/org/hisp/dhis/importexport/i18n_module.properties'
--- dhis-2/dhis-web/dhis-web-importexport/src/main/resources/org/hisp/dhis/importexport/i18n_module.properties	2012-04-13 22:38:23 +0000
+++ dhis-2/dhis-web/dhis-web-importexport/src/main/resources/org/hisp/dhis/importexport/i18n_module.properties	2012-04-14 18:32:00 +0000
@@ -284,4 +284,6 @@
 conflicts=Conflicts
 no_conflicts_found=No conflicts found
 type=Type
-count=Count
\ No newline at end of file
+count=Count
+export_as_xml=Export as XML
+export_as_csv=Export as CSV
\ No newline at end of file

=== modified file 'dhis-2/dhis-web/dhis-web-importexport/src/main/webapp/dhis-web-importexport/exportDataValueForm.vm'
--- dhis-2/dhis-web/dhis-web-importexport/src/main/webapp/dhis-web-importexport/exportDataValueForm.vm	2012-04-13 22:28:40 +0000
+++ dhis-2/dhis-web/dhis-web-importexport/src/main/webapp/dhis-web-importexport/exportDataValueForm.vm	2012-04-14 18:32:00 +0000
@@ -30,7 +30,7 @@
 
 <form id="exportForm" name="exportForm" method="post" action="exportDataValue.action">
 
-<input type="hidden" name="exportFormat" value="$!exportFormat">
+<input type="hidden" id="exportFormat" name="exportFormat">
 
 <table width="708">
 	
@@ -95,8 +95,10 @@
 	<!-- Submit -->
 	
 	<tr>		
-		<td><input type="button" value="$i18n.getString( 'export' )" style="width:50%" onclick="exportDataValue()"></td>
-		<td colspan="2"></td>
+		<td><input type="button" value="$i18n.getString( 'export_as_xml' )" style="width:48%" onclick="exportDataValue( 'xml' )">
+		<input type="button" value="$i18n.getString( 'export_as_csv' )" style="width:48%" onclick="exportDataValue( 'csv' )"></td>
+		<td></td>
+		<td></td>
 	</tr>
 	
 </table>

=== modified file 'dhis-2/dhis-web/dhis-web-importexport/src/main/webapp/dhis-web-importexport/javascript/export.js'
--- dhis-2/dhis-web/dhis-web-importexport/src/main/webapp/dhis-web-importexport/javascript/export.js	2012-04-13 22:28:40 +0000
+++ dhis-2/dhis-web/dhis-web-importexport/src/main/webapp/dhis-web-importexport/javascript/export.js	2012-04-14 18:32:00 +0000
@@ -3,9 +3,10 @@
 // Export
 // -----------------------------------------------------------------------------
 
-function exportDataValue()
+function exportDataValue( format )
 {
-    selectAll( document.getElementById( "selectedDataSets" ) );
+	$( "#exportFormat" ).val( format );
+    selectAllById( "selectedDataSets" );
 	
 	if ( validateDataValueExportForm() )
 	{

=== modified file 'dhis-2/pom.xml'
--- dhis-2/pom.xml	2012-03-30 13:07:32 +0000
+++ dhis-2/pom.xml	2012-04-14 18:32:00 +0000
@@ -567,6 +567,11 @@
         <artifactId>commons-email</artifactId>
         <version>1.2</version>
       </dependency>
+      <dependency>
+        <groupId>net.sf.opencsv</groupId>
+        <artifactId>opencsv</artifactId>
+        <version>2.3</version>
+      </dependency>
       <!--DBMS -->
       <dependency>
         <groupId>com.h2database</groupId>