SuperCSV Cellprocessor that depends on multiple columns

1.7k views Asked by At

I came across the supercsv library and it seems like a very good piece of work. However I have a question that I wasn't able to answer with the documentation provided in their website, wondering if anyone here can help.

Basically I have a csv file that has a column that only appears when another column is set to a specific value. So an example would be the following:

IsBirthDate,BirthDate

Yes,11/05/1985

No

Yes,12/01/1999

No

No

You see what I mean. Is there a way to create a cellprocessor that can take this dependency into account and throw an exception when a row like this is found:

No,12/09/1968

Cheers

1

There are 1 answers

0
sakis kaliakoudas On BEST ANSWER

Seems like this has already been answered on the Super CSV forums: http://sourceforge.net/p/supercsv/feature-requests/25/#30a5

Copying the post in case link goes down:

I think you're asking whether you can validate that Items have a parentPartNumber but skip that validation for Products. This is essentially cross-validation (validation involving more than 1 column).

The only way I can think of to achieve this with cell processors is to write a custom cell processor that inspects the value in another column, and decides what to do based on the value. Every cell processor has access to the CsvContext, which contains the raw (unprocessed) values.

So you can write a processor such as the following. It behaves like Optional if the value in a given column (where column numbers start at 1) equals the value its expecting. Otherwise, it simply delegates to the next processor in the chain.

package example;

import java.util.List;

import org.supercsv.cellprocessor.Optional;
import org.supercsv.cellprocessor.ift.CellProcessor;
import org.supercsv.util.CsvContext;

public class OptionalIfOtherColumnEquals extends Optional {

  private final int column;

  private final Object constantValue;

  public OptionalIfOtherColumnEquals(int column, 
                                     Object constantValue) {
    super();
    this.column = column;
    this.constantValue = constantValue;
  }

  public OptionalIfOtherColumnEquals(int column, 
                                     Object constantValue, 
                                     CellProcessor next) {
    super(next);
    this.column = column;
    this.constantValue = constantValue;
  }

  @Override
  public Object execute(Object value, CsvContext context) {

    // unprocessed row
    List<Object> row = context.getRowSource();

    // optional if other column matches value
    if (row.get(column - 1).equals(constantValue)){
      return super.execute(value, context);
    }

    // otherwise continue to next processor
    return next.execute(value, context);
  }

}

I replaced the processor definition for the parentPartNumber column with new OptionalIfOtherColumnEquals(2, "Product", new IsValueIn(partNumbers)) and it works for Products and Items but it fails validation on the Packages at the end of the file.

I'll leave that as an exercise for you to solve, but you can see that you can achieve cross-validation if you really have to. Hope this helps.