Skip to content

CsvMapReader / CsvMapWriter #235

@thekid

Description

@thekid

Scope of Change

Instead of working with integers describing the cell offsets in CSV files, we will add a class CsvMapReader to read data into a map, and a class CsvMapWriter to write data from a map to CSV files.

Rationale

Enable writing code to flexibly deal with changing field order.

Functionality

These classes will complement the "list", "bean" and "object" versions already inside the package text.csv.

Reading

Assuming the following CSV file:

id;realname;email
1549;Timm Friebe;timm@example.com

The current way to deal with this in a way that nothing breaks when the order of the fields changes is:

<?php
  $reader= new CsvListReader(new TextReader($input));
  $lookup= array_flip($reader->getHeaders());
  while ($record= $reader->read()) {
    $email= $record[$lookup['email']];
  }
?>

With the new CsvMapReader class, this functionality is built in

<?php
  $reader= new CsvMapReader(new TextReader($input));
  $reader->setKeys($reader->getHeaders());
  while ($record= $reader->read()) {
    $email= $record['email'];
  }
?>

Writing

Writing maps is almost the same as writing lists if we regard this on a per-line basis, since we can simply use array_values() to transform maps into lists. In the mode when we've set no headers, both versions are actually equivalent.

<?php
  $writer= new CsvListWriter(new TextWriter($output));
  $writer->setHeaders(array('id', 'email'));
  $writer->write(array_values(array(
    'id'    => 1,
    'email' => 'thekid@example.com'
  )));
?>

The difference is that the order of the headers defines the order in which the record's values are written, so even if our passed map would contain array('email' => '...', 'id' => 1), the order in the file would still be correct with the map writer implementation; while in the list writer implementation the email address would be written to the first field in the output, and id to the second.

<?php
  $writer= new CsvMapWriter(new TextWriter($output));
  $writer->setHeaders(array('id', 'email'));
  $writer->write(array(
    'id'    => 1,
    'email' => 'thekid@example.com'
  ));

  // Also yields correct result
  $writer->write(array(
    'email' => 'thekid@example.com',
    'id'    => 1
  ));
?>

Security considerations

None.

Speed impact

None, just two new classes.

Dependencies

None.

Related documents

http://supercsv.sourceforge.net/javadoc/org/supercsv/io/CsvMapReader.html
http://grails.org/plugin/csv
#191 The original "new CSV API" RFC

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions