写一个 header 以便段默认名称也根据最大出现次数打印

write a header so that segment default name is also printed on the basis of max occurrence

现在,我可以写 header 但无法打印段内的 header 名称,有什么办法可以做到这一点吗?

输入文件-

1john dew BA xxx  
1sam hart MA yyy

它没有在段内打印默认名称。
输出文件-

Record,FirstName,LastName,Title,Filler  
1,john,dew,22,85,22,85,22,85,BA,xxx  
1,sam,hart,78,45,78,45,78,45,MA,yyy

Java:

public class XlsWriter {
    public static void main(String[] args) throws Exception {

        StreamFactory factory = StreamFactory.newInstance();

        factory.load("C:\Users\PV5057094\Demo_workspace\XlsxMapper\src\main\resources\Employee.xml");


    BeanReader br = factory.createReader("EmployeeInfo",new File("C:\Temp\Soc\textInput.txt"));

        BeanWriter out = factory.createWriter("EmployeeInfoCSV", new File("C:\Temp\Soc\output.csv"));

        out.write("headers",null);
        Object record;

        while ((record=br.read())!=null) {


            out.write(record);

            System.out.println("Record Written:" + record.toString());

        }

        // in.close();
        out.flush();
        out.close();
    }

}

BeanIO-
<?xml version="1.0" encoding="UTF-8"?>
<beanio xmlns="http://www.beanio.org/2012/03"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.beanio.org/2012/03 http://www.beanio.org/2012/03/mapping.xsd">

    <stream name="EmployeeInfo" format="fixedlength">

        <record name="a" minOccurs="0" maxOccurs="unbounded"
            class="com.Employee">
            <field name="record" length="3" literal="AAA" rid="true" />
            <field name="firstName" length="5" />
            <field name="lastName" length="5" />
            <segment name="error" collection="list" minOccurs="0"
                maxOccurs="3" class="com.Error">
                <field name="origin_of_error" length="2" />
                <field name="fld_name" length="2" />

            </segment>
            <field name="title" length="5" />
            <field name="filler" length="5" />
        </record>

    </stream>


    <stream name="EmployeeInfoCSV" format="csv">
        <record name="headers" minOccurs="1" maxOccurs="1">
            <field name="recordColumn" default="Record" />
            <field name="firstNameColumn" default="FirstName" />
            <field name="lastNameColumn" default="LastName" />
            <segment name="error" collection="list" minOccurs="0"
                maxOccurs="5" class="com.Error">
                <field name="origin_of_error" default="origin_of_error" />
                <field name="fld_name" default="fld_name" />

            </segment>
            <field name="titleColumn" default="Title" />
            <field name="fillerColumn" default="Filler" />
        </record>
        <record name="a" minOccurs="0" maxOccurs="unbounded"
            class="com.Employee">
            <field name="record" length="3" literal="AAA" rid="true" />
            <field name="firstName" length="5" />
            <field name="lastName" length="5" />
            <segment name="error" collection="list" minOccurs="0"
                maxOccurs="3" class="com.Error">
                <field name="origin_of_error" length="2" />
                <field name="fld_name" length="2" />

            </segment>
            <field name="title" length="5" />
            <field name="filler" length="5" />
        </record>
    </stream>
</beanio>

预期输出-

Record,FirstName,LastName,origin_of_error,fld_name,origin_of_error,fld_name,origin_of_error,fld_name,Title,Filler
1,john,dew,22,85,22,85,22,85,BA,xxx
1,sam,hart,78,45,78,45,78,45,MA,yyy

要使列 headers 动态化,我们需要将列 headers 移动到它们自己的 class 中。

添加 HeaderColumnsErrorColumns classes 以包含不同列的名称。

public class HeaderColumns {

  private String recordColumn = "Record";
  private String firstNameColumn = "FirstName";
  private String lastNameColumn = "LastName";
  private String titleColumn = "Title";
  private String fillerColumn = "Filler";
  private List<ErrorColumns> errorColumns;

  public void addErrorColumns(final ErrorColumns errorColumn) {
    if (errorColumns == null) {
      errorColumns = new ArrayList<>();
    }
    errorColumns.add(errorColumn);
  }
  // getter/setters removed
}

注意 addErrorColumns 方法。

public class ErrorColumns {

  private String originOfErrorColumn = "origin_of_error";
  private String fldNameColumn = "fld_name";
  // getter/setters removed
}

我们需要添加一个方法 Employee class 来 return 读取的错误计数。

public class Employee {

  private String record;
  private String firstName;
  private String lastName;
  private String title;
  private String filler;
  private int errorCount;
  private List<Error> error;

  public int getErrorCount() {
    return error != null ? error.size() : 0;
  }
  // getter/setters removed
}

映射文件中列的记录定义 headers 现在看起来很像数据的实际记录定义 a

<stream name="EmployeeInfoCSV" format="csv">
  <record name="headers" minOccurs="1" maxOccurs="1" 
          class="com.HeaderColumns">
    <field name="recordColumn" rid="true" literal="Record"/>
    <field name="firstNameColumn"/>
    <field name="lastNameColumn"/>
    <segment name="errorColumns" collection="list" minOccurs="0" maxOccurs="unbounded" 
             class="com.ErrorColumns">
      <field name="originOfErrorColumn"/>
      <field name="fldNameColumn"/>
    </segment>
    <field name="titleColumn"/>
    <field name="fillerColumn"/>
  </record>
  <record name="a" minOccurs="0" maxOccurs="unbounded" 
          class="com.Employee">
    <field name="record" length="1"/>
    <field name="firstName" maxLength="5"/>
    <field name="lastName" maxLength="5"/>
    <segment name="error" collection="list" minOccurs="0" maxOccurs="unbounded" 
             class="com.Error">
      <field name="origin_of_error" maxLength="2"/>
      <field name="fld_name" maxLength="2"/>
    </segment>
    <field name="title" maxLength="5"/>
    <field name="filler" maxLength="5"/>
  </record>
</stream>

现在我们需要确保 errorColumns 列表中填充的 objects 数量与我们为第一个 Employee 记录读取的数量相同。

public static void main(String[] args) throws Exception {

    StreamFactory factory = StreamFactory.newInstance();
    factory.load("C:\Users\PV5057094\Demo_workspace\XlsxMapper\src\main\resources\Employee.xml");

    BeanReader br = factory.createReader("EmployeeInfo",new File("C:\Temp\Soc\textInput.txt"));
    BeanWriter out = factory.createWriter("EmployeeInfoCSV", new File("C:\Temp\Soc\output.csv"));

    boolean columnHeadersWritten = false;
    Object record;
    while ((record=br.read())!=null) {

      if (!columnHeadersWritten) {
        final Employee employee = (Employee) record;
        final HeaderColumns headerColumns = new HeaderColumns();
        for (int i = 0; i < employee.getErrorCount(); i++) {
          headerColumns.addErrorColumns(new ErrorColumns());
        }
        out.write(headerColumns);
        columnHeadersWritten = true;
      }

      out.write(record);
      System.out.println("Record Written:" + record.toString());
    }

    in.close();
    out.flush();
    out.close();
}

现在我们有了动态列 headers,它基于从第一个员工记录中读取的实际错误数量。