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