Although this is not exactly what you asked for you can achieve your goal by using the User Defined Java Class component with a generic functionality. Replace your steps Get previous row fields
through Non-values in row
by a single instance of this component. In the section Classes - Processor of this component insert the following code:
Object[] previousRow;
public boolean processRow(StepMetaInterface smi, StepDataInterface sdi) throws KettleException
{
// First, get a row from the default input hop
Object[] r = getRow();
// If the row object is null, we are done processing.
if (r == null) {
setOutputDone();
return false;
}
// It is always safest to call createOutputRow() to ensure that your output row's Object[] is large
// enough to handle any new fields you are creating in this step.
Object[] outputRow = createOutputRow(r, data.outputRowMeta.size());
// copy all input fields to the output fields
for (int i=0; i < getInputRowMeta().size(); i++) {
logBasic(data.inputRowMeta.getString(r, i));
if (data.inputRowMeta.getString(r, i) == null && (previousRow != null)) {
// if the current field is empty take it from the previous row
outputRow[i] = previousRow[i];
}
else {
// otherwise use the current row
outputRow[i] = r[i];
}
}
putRow(data.outputRowMeta, outputRow);
// store the current row as future previous row
previousRow = data.outputRowMeta.cloneRow(outputRow);
return true;
}
The Janino class always keeps a copy of the previous row to fill up the empty fields of the current row.
The following test setup demonstrates the use of the component. In the simplest case we process a stream read from a CSV file:

The input file is configured as follows:

and contains the following data
NUMBER;STRING;DATE;CURRENCY
1;A;01.02.2014;12,5
2;B;;13,5
;;03.12.2001;
4;;;
5;C;;
6;;20.03.2005;18,2
7;D;;
The configuration of the User Defined Java class component is as follows:

The output text file contains the enhanced rows "without gaps":
NUMBER;STRING;DATE;CURRENCY
1;A;01.02.2014; 012,50
2;B;01.02.2014; 013,50
2;B;03.12.2001; 013,50
4;B;03.12.2001; 013,50
5;C;03.12.2001; 013,50
6;C;20.03.2005; 018,20
7;D;20.03.2005; 018,20
Note:
- The component was test for these four data types but in priciple it should work for all.
- It's independent of the actual number of fields.
- Once a field is filled it can never be "unfilled" which is fine for your setup (I guess) but this may not be applicable for other setups.
- The mechanism only works if a field is
null
. Strings just containing blanks might break it, so make sure that you trim all the strings before piping them into the component.
The code was written by using http://wiki.pentaho.com/display/EAI/User+Defined+Java+Class as a tutorial.
ADDENDUM
The link provided by @manu contains the followng code. It contains a specific handling of the numeric formats. Note this it is not fully generic anymore.
Object[] previousRow;
RowMetaInterface outputMeta;
public boolean processRow(StepMetaInterface smi, StepDataInterface sdi) throws KettleException
{
// First, get a row from the default input hop
Object[] r = getRow();
// If the row object is null, we are done processing.
if (r == null) {
setOutputDone();
return false;
}
if (outputMeta == null) {
outputMeta = data.outputRowMeta.clone();
for(int i=0; i < outputMeta.size(); i++) {
ValueMetaInterface meta = outputMeta.getValueMeta(i);
if (meta.getType() == ValueMetaInterface.TYPE_NUMBER) {
meta.setPrecision(4);
meta.setConversionMask("#.####");
}
}
}
// It is always safest to call createOutputRow() to ensure that your output row's Object[] is large
// enough to handle any new fields you are creating in this step.
Object[] outputRow = createOutputRow(r, data.outputRowMeta.size());
// copy all input fields to the output fields
for (int i=0; i < getInputRowMeta().size(); i++) {
if ((r[i] == null) && (previousRow != null)) {
// if the current field is empty take it from the previous row
outputRow[i] = previousRow[i];
}
else {
// otherwise use the current row
outputRow[i] = r[i];
}
}
putRow(outputMeta, outputRow);
// store the current row as future previous row
previousRow = outputMeta.cloneRow(outputRow);
return true;
}