On 12 March 2012 22:11, Emmanuel Bourg <ebo...@apache.org> wrote:
> [csv] is missing some elements to ease the use of headers. I have no clear
> idea on how to address this, here are my thoughts.
>
> Headers are used when the fields are accessed by the column name rather than
> by the index. This provides some flexibility because the input file can be
> slightly modified by reordering the columns or by inserting new columns
> without breaking the existing code.
>
> Using the current API here is how one would work with headers:
>
>  CSVParser parser = new CSVParser(in);
>  Iterator<String[]> it = parser.iterator();
>
>  // read the header
>  String[] header = it.next();
>
>  // build a name to index mapping
>  Map<String, Integer> mapping = new HashMap<>();
>  for (int i = 0; i < header.length; i++) {
>      mapping.put(header[i], i);
>  }
>
>  // parse the records
>  for (String[] record : parser) {
>      Person person = new Person();
>      person.setName(record[mapping.get("name")]);
>      person.setEmail(record[mapping.get("email")]);
>      person.setPhone(record[mapping.get("phone")]);
>      persons.add(person);
>  }
>
> The user has to take care of the mapping, which is not very friendly. I have
> several solutions in mind:
>
> 1. Do nothing and address it in the next release with the bean mapping.
> Parsing the file would then look like this:
>
>  CSVFormat<Person> format = CSVFormat.DEFAULT.withType(Person.class);
>  for (Person person : format.parse(in)) {
>      persons.add(person);
>  }
>

Does this automatically mean that the file has a header?
Or is there another way to link columns to Person attributes?

I don't think this should be the only way of handling named columns;
it's not always convenient to create a type.

> 2. Add a parser returning a Map instead of a String[]
>
>  // declare the header in the format,
>  // the header line will be parsed automatically
>  CSVFormat format = CSVFormat.DEFAULT.withHeader();
>
>  for (Map<String, String> record : new CSVMapParser(in, format))) {
>      Person person = new Person();
>      person.setName(record.get("name"));
>      person.setEmail(record.get("email"));
>      person.setPhone(record.get("phone"));
>      persons.add(person);
>  }

That seems OK; one can also just use the column values directly.

>
> 2bis. Have the same CSVParser class returning String[] or Map<String,
> String> depending on a generic parameter. Not sure it's possible with type
> erasure.
>

It's not possible for two methods to differ only by return parameter
type, so this can only be done if the method parameters are different
after type erasure.

> 3. Have the parser maintain the name->index mapping. The parser read the
> first line automatically if the format declares a header, and a
> getColumnIndex() method is exposed.
>
>  CSVFormat format = CSVFormat.DEFAULT.withHeader();
>  CSVParser parser = new CSVParser(in, format);
>
>  // parse the records
>  for (String[] record : parser) {
>      Person person = new Person();
>      person.setName(record[parser.getColumnIndex("name")]);
>      person.setEmail(record[parser.getColumnIndex("email")]);
>      person.setPhone(record[parser.getColumnIndex("phone")]);
>      persons.add(person);
>  }

Quite awkard to use.

>
> What do you think?
>
> Emmanuel Bourg
>

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org
For additional commands, e-mail: dev-h...@commons.apache.org

Reply via email to