1 /* 2 * CSVeed (https://github.com/42BV/CSVeed) 3 * 4 * Copyright 2013-2023 CSVeed. 5 * 6 * All rights reserved. This program and the accompanying materials 7 * are made available under the terms of The Apache Software License, 8 * Version 2.0 which accompanies this distribution, and is available at 9 * https://www.apache.org/licenses/LICENSE-2.0.txt 10 */ 11 package org.csveed.bean; 12 13 import org.csveed.common.Column; 14 15 /** 16 * <p> 17 * The concept of dynamic columns comes into play when a sheet contains columns that are not really part of the columns, 18 * but should have been separate rows. For example, let's say you have a table that looks like this: 19 * </p> 20 * <code> 21 * | name | town | jan 14 | jan 15 | jan 16 | 22 * | Rob | Leiden | 4 | 1 | 7 | 23 * | Rob | Delft | 0 | 3 | 8 | 24 * | Erik | Leiden | 2 | 4 | 1 | 25 * | Erik | Sneek | 1 | 0 | 9 | 26 * </code> 27 * <p> 28 * Let's say you want to compact this table into the following, normalized format: <code> 29 * | name | town | date | visits | 30 * | Rob | Leiden | jan 14 | 4 | 31 * | Rob | Leiden | jan 15 | 1 | 32 * | Rob | Leiden | jan 16 | 7 | 33 * | Rob | Delft | jan 14 | 0 | 34 * | Rob | Delft | jan 15 | 3 | 35 * | Rob | Delft | jan 16 | 8 | 36 * | Erik | Leiden | jan 14 | 2 | 37 * | Erik | Leiden | jan 15 | 4 | 38 * | Erik | Leiden | jan 16 | 1 | 39 * | Erik | Sneek | jan 14 | 1 | 40 * | Erik | Sneek | jan 15 | 0 | 41 * | Erik | Sneek | jan 16 | 9 | 42 * </code> 43 * <p> 44 * In order to realize this goal, you need to make that startIndexDynamicColumns is set to 3 on @CsvFile. This will 45 * assume the columns starting with the third and all thereafter are dynamic. For every dynamic column, a new bean will 46 * be created. All static columns will be copied into every created bean. 47 * </p> 48 * <p> 49 * The header name and the cell value can be copied into bean properties. In the example, the bean requires two fields 50 * date and visits. date must be annotated with @CsvHeaderName and visits with @CsvHeaderValue. 51 * </p> 52 */ 53 public class DynamicColumn { 54 55 /** The start column. */ 56 private Column startColumn; 57 58 /** The current column. */ 59 private Column currentColumn; 60 61 /** 62 * Instantiates a new dynamic column. 63 * 64 * @param configuredStartColumn 65 * the configured start column 66 */ 67 public DynamicColumn(Column configuredStartColumn) { 68 this.startColumn = configuredStartColumn == null ? null : new Column(configuredStartColumn); 69 this.currentColumn = configuredStartColumn == null ? null : new Column(configuredStartColumn); 70 } 71 72 /** 73 * Check for reset. 74 * 75 * @param numberOfColumns 76 * the number of columns 77 */ 78 public void checkForReset(int numberOfColumns) { 79 if (lastDynamicColumnPassed(numberOfColumns)) { 80 reset(); 81 } 82 } 83 84 /** 85 * Reset. 86 */ 87 protected void reset() { 88 this.currentColumn = new Column(this.startColumn); 89 } 90 91 /** 92 * Last dynamic column passed. 93 * 94 * @param numberOfColumns 95 * the number of columns 96 * 97 * @return true, if successful 98 */ 99 protected boolean lastDynamicColumnPassed(int numberOfColumns) { 100 return this.currentColumn != null && this.currentColumn.getColumnIndex() > numberOfColumns; 101 } 102 103 /** 104 * At first dynamic column. 105 * 106 * @return true, if successful 107 */ 108 public boolean atFirstDynamicColumn() { 109 return this.startColumn == null || this.startColumn.equals(this.currentColumn); 110 } 111 112 /** 113 * Advance dynamic column. 114 */ 115 public void advanceDynamicColumn() { 116 if (currentColumn == null) { 117 return; 118 } 119 this.currentColumn = currentColumn.nextColumn(); 120 } 121 122 /** 123 * Checks if is dynamic column active. 124 * 125 * @param currentColumn 126 * the current column 127 * 128 * @return true, if is dynamic column active 129 */ 130 public boolean isDynamicColumnActive(Column currentColumn) { 131 return this.currentColumn != null && this.currentColumn.getColumnIndex() == currentColumn.getColumnIndex(); 132 } 133 134 }