Let me know if this is a duplicate or if this is just a setting that I overlooked. To my knowledge I haven't found anything similar to what I need. So here goes:

Currently when I download my CSV file all of my multi-select fields show up as follows (keep in mind that all of these options are included in one multi-select question called "Question 1"):

+----------+-----------+----------+------------+------------+
| Option 1 | Option 2 | Option 3| Option 4 | Option 5 |
+----------+-----------+----------+------------+------------+
| Yes | No | Yes | No | Yes |
+----------+-----------+----------+------------+------------+

How do I make it so that it says this instead?:

+--------------------------------+
| Question 1 |
+--------------------------------+
|"Option 1, Option 3, Option 5"|
+--------------------------------+

Has anyone else run into this issue? I find the CSV export of multi-select fields kind of useless... any workarounds?

Comments

amariotti’s picture

My text tables are all screwed up... sorry!

amariotti’s picture

StatusFileSize
new21.7 KB

Attached screenshots of what the tables should look like.

amariotti’s picture

I found the CSV function in the webform_report.inc file. Anyone have any ideas what could be done to produce the output that I need?

/**
 * Generate a Excel-readable CSV file containing all submissions for a webform.
 * 
 * The CSV requires that the data be presented in a flat file.  In order
 * to maximize useability to the Excel community and minimize subsequent
 * stats or spreadsheet programming this program extracts data from the
 * various records for a given session and presents them as a single file
 * where each row represents a single record.
 * The structure of the file is:
 *   Heading Line 1: Gives group overviews padded by empty cells to the
 *                   next group.  A group may be a question and corresponds
 *                   to a component in the webform philosophy. Each group
 *                   overview will have a fixed number of columns beneath it.
 *   Heading line 2: gives column headings
 *   Data line 1 .....
 *   Data line 2 .....
 * 
 * An example of this format is given below.  Note the columns have had spaces
 * added so the columns line up.  This is not the case with actual file where
 * a column may be null.  Note also, that multiple choice questions as produced
 * by checkboxes or radio buttons have been presented as "yes" or "no" and the
 * actual choice text is retained only in the header line 2.
 * Data from text boxes and input fields are written out in the body of the table.
 * 
 *   Submission Details,    ,   ,      ,Question 1,        ,        ,..,        ,Question 2,        ,        ,..,        ,Question n
 *   timestamp         ,time,SID,userid,Choice 1  ,Choice 2,Choice 3,..,Choice n,Choice 1  ,Choice 2,Choice 3,..,Choice n,Comment
 *   21 Feb 2005       ,1835,23 ,34    ,Yes       ,No      ,No      ,..,No      ,Yes       ,Yes     ,Yes     ,..,Yes     ,My comment
 *   23 Feb 2005       ,1125,24 ,89    ,Yes       ,Yes     ,No      ,..,No      ,Yes       ,Yes     ,Yes     ,..,Yes     ,Hello
 *   ...............................................................................................................
 *   27 Feb 2005       ,1035,56 ,212   ,Yes       ,No      ,No      ,..,No      ,Yes       ,No      ,Yes     ,..,Yes     ,How is this?
 * 
 */
function webform_results_download($node) {
  $delim = variable_get('webform_csv_delimiter', ',');
  // Convert tabs.
  if ($delim == '\t') {
    $delim = "\t";
    $extension = 'tsv';
    $content_type = 'text/tab-separated-values';
  }
  else {
    $extension = 'csv';
    $content_type = 'text/csv';
  }

  $file_name = tempnam(variable_get('file_directory_temp', FILE_DIRECTORY_TEMP), 'webform');
  $handle = @fopen($file_name, 'w'); // The @ suppresses errors.

  $header[0] .= $node->title . str_repeat($delim, 4);
  $header[1] .= t("Submission Details") . str_repeat($delim, 5);
  $header[2] .= implode($delim, array(t('Serial'), t('SID'), t('Time'), t('IP Address'), t('UID'), t('Username')));

  // Compile header information.
  webform_load_components(); // Load all components.
  foreach ($node->webform['components'] as $cid => $component) {
    $csv_header_function   = "_webform_csv_headers_". $component['type'];
    if (function_exists($csv_header_function)) {
      // Let each component determine its headers.
      $component_header = $csv_header_function($component);
      $header[0] .= $delim .'"'. str_replace(array('"', '\,'), array('""', '"'. $delim .'"'), $component_header[0]) .'"';
      $header[1] .= $delim .'"'. str_replace(array('"', '\,'), array('""', '"'. $delim .'"'), $component_header[1]) .'"';
      $header[2] .= $delim .'"'. str_replace(array('"', '\,'), array('""', '"'. $delim .'"'), $component_header[2]) .'"';
    }
  }

  // Write header information.
  $file_record = $header[0] ."\n". $header[1] ."\n". $header[2] ."\n";
  @fwrite($handle, $file_record);

  // Get all the submissions for the node.
  $submissions = webform_get_submissions($node->nid);

  // Generate a row for each submission.
  $rowcount = 0;
  foreach ($submissions as $sid => $submission) {
    $row = ++$rowcount . $delim . $sid . $delim .'"'. format_date($submission->submitted, 'small') .'"'. $delim .'"'. $submission->remote_addr .'"'. $delim . $submission->uid . $delim.'"'. $submission->name .'"';
    foreach ($node->webform['components'] as $cid => $component) {
      $csv_data_function   = "_webform_csv_data_". $component['type'];
      if (function_exists($csv_data_function)) {
        // Let each component add its data.
        $row .= $delim .'"'. str_replace(array('"', '\,'), array('""', '"'. $delim .'"'), $csv_data_function($submission->data[$cid], $component)) .'"';
      }
    }
    // Write data from submissions.
    @fwrite($handle, $row ."\n");
  }
  // Close the file.
  @fclose($handle);

  drupal_set_header("Content-type: $content_type; charset=utf-8");
  drupal_set_header("Content-Disposition: attachment; filename=". preg_replace('/\.$/', '', str_replace(' ', '_', $node->title)) .".". $extension);

  @readfile($file_name);  // The @ makes it silent.
  @unlink($file_name);  // Clean up, the @ makes it silent.
  exit(0);
}
amariotti’s picture

Someone name your price to fix this issue! It's something I'm really interested in at the moment and am willing to do whatever I can to make it happen. If this could be a setting under admin/settings/webform where the user could change the multi-select csv data from "Store in individual columns with boolean data" or "Store in single column separated by commas." Someone let me know!

quicksketch’s picture

I'm not sure why the change would make the CSV more helpful. By combining the values into a single cell, it makes it impossible to create charts or graphs based on the the number of responses to each answer. Could you describe why this change is necessary or how it would make the CSV more effective?

amariotti’s picture

I understand where you're coming from on this.

Two reasons that I can think of:
1) We're needing to import the CSV into our Customer Relationship Management software (Salesforce) and to map that field it needs to be one field with the selected values listed and not one column for each selecting with yes or no.
2) We used webform for a group of courses that we had available over the summer and the CSV was useless with all of our classes in columns with a Yes or No if they selected it or not. it would've been more effective to have a single column with a list of the classes they selected (i.e. "Web Design,Media Design,Programming" etc.)

Let me know if this doesn't make sense. I've got a guy kind of on-board to fix this for me. Given my reasons above would this be something that could be included in the module? It would have an on/off switch in case people don't want to use it. Up to this point I haven't had a need for the "boolean" format for the multi-select fields.

I agree with you that for charts and graphs this doesn't make sense, so maybe instead of it being an on/off setting it would be adding a page when you click on Download so that you can download the multi-selects in boolean format or in the format I'm needing. Make sense?

quicksketch’s picture

I agree with you that for charts and graphs this doesn't make sense, so maybe instead of it being an on/off setting it would be adding a page when you click on Download so that you can download the multi-selects in boolean format or in the format I'm needing. Make sense?

I've been thinking this would be an *excellent* idea for a while (making a page with download options). I'd like to figure out what sort of download options do make the most sense, mostly in the UI that's presented to the user downloading. We should definitely include the field delimiter as an option also (currently it's only on admin/settings/webform).

Field Delimiter:
[ Comma (,) | v ]

File Format:
( • ) Expanded select options (Better for charts)
(   ) Compacted select options (SalesForce Import)

[ Download ]
amariotti’s picture

That's exactly what I was thinking for the UI. Keeping it simple and like you have it defaulting to the "charts" version.

I think this could be a big and important change to the way the CSV file exports from Webform. I know it frustrated me when I didn't have any other option. How hard would this be to change in the source code?

amariotti’s picture

Here's what I would recommend though, after having looked at:

Field Delimiter:
[ Comma (,) | v ]

Multi-Select Options Format:
( • ) Expanded select options (Better for charts)
+----------+----------+----------+
| Option 1 | Option 2 | Option 3 |
+----------+----------+----------+
|     Yes     |    No      |    Yes     | 
+----------+----------+----------+

(    ) Compacted select options (Better for printing)
+----------+----------+----------+
|               Question 1               |
+----------+----------+----------+
|  Option 1,Option 2,Option 3    |
+----------+----------+----------+

[ Download ]

I think the examples would speak louder. I really think that if people had this option that it would make printing results from each Webform a lot easier. What do you think? Hopefully my stupid tables come across looking ok.

amariotti’s picture

Off topic: I just realized that you're Nate from Lullabot. I was at your Portland Workshop earlier this year (January). Great to see you on d.o and interact with you!

quicksketch’s picture

Title: CSV question on multi-select field » Option to choose CSV Select Format
Category: bug » feature

Hey amariotti, sorry I dropped off the planet right before DrupalCon and am just now getting back to everything. Coincidentally, we just had another workshop in Portland in September (part of the reason for my absence), too bad you couldn't attend again!

I'm about to make a 2.2 release of the module, which will include a configuration form for CSV files (allowing you to choose the format of XLS or CSV), but not include this particular option just yet. Probably the next release. Now that the form is in place though, it makes adding in the option much easier in the future.

amariotti’s picture

Sounds good! Thanks for the update Nate!

amariotti’s picture

Version: 5.x-2.1.3 » 6.x-2.6

Hi, Nate! Sorry to resurrect this thing 8 months later.

How could we get this into a version of 6.x, Nathan? :)

ericclaeren’s picture

Hi!

Posted a topic about this issue : http://drupal.org/node/453034

Is it possible to provide a fix for this in the latest 5.x and 6.x versions?
Have the same problem for importing data into an external application.

Thanks! Cheers,

ericclaeren’s picture

Any idea if or when this feature will be added to webform?

ericclaeren’s picture

Hi Nathan!

Kicking this topic again, any news about this request?

quicksketch’s picture

Heya dreamlabs and amariotti, I'm still ready to get this in, and our outline seems solid, I just haven't had time to write such functionality. Are you guys interested in providing patches?

ericclaeren’s picture

My php / drupal knowledge is limited, but I have did some searching through the code and found the following:

Files used for the export:
webform_report.inc
webform_export.inc
components/select.inc

webform_report.inc
Uses this function to produce the rows with headers and used for export.
function webform_results_download($node, $format = 'delimiter', $options = array())

In this function two foreach loops are executed, one for the headers and one for the data.
The header format is produced by select.inc : _webform_csv_headers_select
The data format is produced by select.inc: _webform_csv_data_select

So I think that select.inc needs to be modified that there is an alternative csv select function which uses only one header with and doesn't uses X.
And webform_results_download() needs to have an extra option for alternative select output which uses the alternative header and data select.

But I have no idea if that is a good "Drupal" approach. And I have no clue how to add the options to the download select format.
So I can try to modify this module, but I seriously could use some help :)

ericclaeren’s picture

Hi Guys,

think I have fixed it for Drupal 5, I'm doing some testing right now, and it all looks fine.
I have added one checkbox: Compacted select options, if you choose it then you get one header with imploded data values, when unselected you get the current situation.

I use tortoise, but my diff / patch file isn't good.

All code is set to - and + everything is added later, I would like a diff file where only the changed lines are changed.
Could someone explain my how to make a proper patch file?

Also can somebody review my code please, I don't know if my solution is proper and fits within this module.

Thanks!

Eric

amariotti’s picture

Post your code and I'll see what I can do for the 6.x version. Feel free to contact me through my contact form to if I don't respond for a while. I really need this feature soon. :)

ericclaeren’s picture

Well tried to create a diff file with tortoise but it outputs the whole file, so here is the changed code for drupal 5

webform/webform_report.inc

starting at line 331: function: webform_results_download_form

  $form['delimiter'] = array(
    '#type' => 'select',
    '#title' => t('Delimited text format'),
    '#description' => t('This is the delimiter used in the CSV/TSV file when downloading Webform results. Using tabs in the export is the most reliable method for preserving non-latin characters. You may want to change this to another character depending on the program with which you anticipate importing results.'),
    '#default_value' => variable_get('webform_csv_delimiter', '\t'),
    '#options' => array(
      ','  => t('Comma (,)'),
      '\t' => t('Tab (\t)'),
      ';'  => t('Semicolon (;)'),
      ':'  => t('Colon (:)'),
      '|'  => t('Pipe (|)'),
      '.'  => t('Period (.)'),
      ' '  => t('Space ( )'),
    ),
  );
  
 +++ $form['compacted_select_option'] = array(
 +++ 	'#type' => 'checkbox',
 +++	'#title' => t('Compact Select Options'),
 +++	'#description' => t('Select this option if you want to download Select components values as one compacted value.'),
 +++	'#return_value' => 1,
 +++ '#default_value' => variable_get('compacted_select_option', 0), 
 +++	'#prefix' => '<fieldset>',
 +++	'#suffix' => '</fieldset>'
 +++  );
  
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Download'),
  );

You can change the description or title

starting at line 401: function: webform_results_download

if (function_exists($csv_header_function)) {	
			+++ if($component['type'] == 'select' && $options['compacted_select_option'] == 1) $component['options'][compacted_select_option] = true;
			// Let each component determine its headers.
			$component_header = $csv_header_function($component);
			$header[0] = array_merge($header[0], (array)$component_header[0]);
			$header[1] = array_merge($header[1], (array)$component_header[1]);
			$header[2] = array_merge($header[2], (array)$component_header[2]);
}

starting at line 431: function: webform_results_download

if (function_exists($csv_data_function)) {
        +++ if($component['type'] == 'select' && $options['compacted_select_option'] == 1) $component['options'][compacted_select_option] = true;
        // Let each component add its data.
        $raw_data = isset($submission->data[$cid]) ? $submission->data[$cid] : NULL;

webform/components/select.inc

starting at line 403: function: _webform_csv_headers_select

Replace

if ($component['extra']['multiple']) {
  	+++ if($component['options'][compacted_select_option]){
	+++	$headers[0][] = '';
	+++	$headers[1][] = '';
	+++	$headers[2][] = $component['name'];
	+++ }
	+++ else{
		$headers[0][] = '';
		$headers[1][] = $component['name'];
		$items = _webform_select_options($component['extra']['items'], TRUE);
		$count = 0;
		foreach ($items as $key => $item) {
		  // Empty column per sub-field in main header.
		  if ($count != 0) {
			$headers[0][] = '';
			$headers[1][] = '';
		  }
		  $headers[2][] = $key;
		  $count++;
		}
	+++ }	
  }

Same trick at

starting at line 441: function: _webform_csv_data_select

if ($component['extra']['multiple']) {  
  	+++ if($component['options'][compacted_select_option]){
	+++	if(is_array($data['value'])){
	+++		$return = implode(",", $data['value']);
	+++	}else{
	+++		$return = '';
	+++	}
        +++ }
	+++ else{
		foreach ($options as $key => $item) {      
		  if (in_array($key, (array)$data['value']) === TRUE) {
			$return[] = 'X';
		  }
		  else {
			$return[] = '';
		  }
		}
	+++ }
  }

Does this help you??
Let me know if you have an questions! Could you add this to the 5x version to please.
Thanks!!

ericclaeren’s picture

Hi Nathan and Amarotti,

Any updates? Haven't heard from you guys.
Let me know if the porting to drupal 6 worked for you and if this function can be added to the current version?

Cheers,

quicksketch’s picture

Version: 6.x-2.6 »
Status: Active » Needs work

I've stopped adding features to the 2.x version so I can focus on a single branch for development (no more Drupal 5 support). However this also means it's much more open to new features. So yes an updated patch against HEAD would definitely help, but it doesn't look like this feature will ever make it to Drupal 5.

amariotti’s picture

My bad....

I thought I specified that we were on Drupal 6 now. :)

The poster above has a solution for Drupal 5.x, I'm just interested in 6.x. Is it in the works, Nathan?

ericclaeren’s picture

Version: » 5.x-2.9
Assigned: Unassigned » ericclaeren
Status: Needs work » Needs review
StatusFileSize
new3.91 KB

Hi Nathan,

I have create a patch for the latest drupal 5 webform (2.9) version. With the option to export the data to a compact format instead of columns with an X as value.
Could you please review my patch and if it's well written include this for any new updates.

Thanks!

quicksketch’s picture

Version: 5.x-2.9 »
Status: Needs review » Needs work

As I noted in #23, the 2.x version is no longer getting any new features. This feature won't ever make it to Drupal 5 in the official release.

The patch has some useful code but the approach isn't quite what we should be using. Instead of jamming the option into the $component array, we should make it so that the csv functions take an $options array or something similar. I anticipate there will probably be more options desired in the future.

ericclaeren’s picture

Thanks for your comment. If I ever need to build this for Drupal 6.x I will use your approach. Cheers.

quicksketch’s picture

Status: Needs work » Fixed
StatusFileSize
new36.71 KB
new16.41 KB

Well a year and half later... here we are, not much further than where we started. I rewrote the changes to be compatible with the 3.x version, since as I've noted above no new features are being added to the 2.x branch or the Drupal 5 version.

I've added an additional argument to all CSV functions so we can pass each component universal download settings, even through right now only select lists are utilizing it. I also themed the help text for these options to make it clear what each option does. This patch is almost entirely the API change and theming. The actual changes to the CSV download function were pretty trivial. This patch has been committed to the 3.x version.

roball’s picture

I've just tested this new feature and it works great!

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.