Le 13/03/2012 00:56, sebb a écrit : > 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.
I agree. Sometimes, the colums are just a part of a class that would need other parameters not in the columns (but perhaps in a custom comment of the header, if these parameters are constant throughout the file. So providing intermediate level API (with mapping already done, but still access to individual fields) is a must. > >> 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. +1 Luc > >> >> 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 > --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org For additional commands, e-mail: dev-h...@commons.apache.org