1

我有一些非常大的 XML 文件,我需要对其进行解析并将相关数据提取到 csv 文件中,本质上是对 XML 文档执行部分展平。XML 文件将具有存储所有记录的“记录标记”。它看起来很像这样,例如:

<persons>
    <person id="1">
        <firstname>James</firstname>
        <lastname>Smith</lastname>
        <middlename></middlename>
        <dob_year>1980</dob_year>
        <dob_month>1</dob_month>
        <gender>M</gender>
        <salary currency="Euro">10000</salary>   
    </person>
    <person id="2">
        <firstname>Michael</firstname>
        <lastname></lastname>
        <middlename>Rose</middlename>
        <dob_year>1990</dob_year>
        <dob_month>6</dob_month>
        <gender>M</gender>
        <salary currency="Dollor">10000</salary>
</persons>

这里的记录标签是“人”,转换为 CSV 的结果如下所示:

_id, dob_month, dob_year,firstname,gender,lastname, middlename  salary 
1,1,1980, James,M,Smith,,{"_VALUE":10000,"_currency":"Euro"}
2,6,1990, Michael M,, Rose,{"_VALUE":10000,"_currency":"Dollor"}

这可能是不正确的——我很快就输入了它——但你明白了。

有一些限制要记住:

  1. 该文件非常大 - 1GB+ - 所以我无法将它加载到内存中。
  2. 我应该只读一次。
  3. (显然)数据不能丢失或不正确。

好的,所以我目前有一个解析器,它将一个简单的 XML 文件转换为一个给定“ROWTAG”的 csv,这是其中包含记录的标签(person在本例中)。你可以在这里看到它。

但它有一些限制。我知道如何修复/解决其中的大多数问题,但是如果不打破约束,我无法弄清楚其中的两个问题。

  1. 根据解析器的实现方式,标签的顺序很重要。假设我有一个如下所示的 xml 文件:
<person id="1">
        <firstname>James</firstname>
        <middlename></middlename> 
        <lastname>Smith</lastname>
    </person>
    <person id="2">
        <firstname>Michael</firstname>
        <lastname>Jordan</lastname>
        <middlename>Rose</middlename>
</person>

第一个记录标签中的中间名排在第二位,第二个记录中的中间名排在第三位。这将产生一个如下所示的 CSV 文件:

firstname,middlename,lastname
James,,Smith,
Michael,Jordan,Rose

迈克尔的名字被记录为迈克尔乔丹罗斯,当时应该是迈克尔罗斯乔丹。

  1. 如果添加、删除或更改属性,程序不会反映这一点。这是因为程序只查看第一个记录元素中的标签,而不关心下一个元素中的标签(如示例一所示)。

让我们举这个例子:

<person id="1">
        <firstname>James</firstname>
        <middlename></middlename> 
        <lastname>Smith</lastname>
    </person>
    <person id="2">
        <firstname>Michael</firstname>
        <lastname>Jordan</lastname>
        <middlename>Rose</middlename>
        <dob>1/10/11</dob>
</person>

生成的 CSV 如下所示:

firstname,middlename,lastname
James,,Smith,
Michael,Jordan,Rose, 1/10/11

这当然是个大问题,必须解决。

我的解决方案

在找到解决方案之前,我将快速总结一下该程序的工作原理。解析器在 XML 文档中移动,每次遇到标记时,都会将其返回给我的程序。正如我所解释的,我的程序有一个“rowTag”,程序正在寻找它。一旦遇到它,我的程序就会开始查看这个 rowTag 中的所有标签和值,并将它们保存在 StringBuilder 中。当遇到结束 rowTag 时,它将转储该信息。在第一次迭代期间,它还将保存它遇到的所有标头,然后在到达结束标记后转储记录的值之前,它将首先转储标头。

现在......正如我所提到的,这会在保存订单以及任何更改、删除或添加的标签方面产生问题。我有一个解决订单的解决方案,它应该解决未更新的标头问题,但我不确定它是否适用于我的用例(我将在一分钟内解释原因)。

我的想法是有一个类似 hashmap 的东西,它收集标签的值以及它们随着时间的推移遇到的顺序。键是标签的值,值是标签第一次出现的顺序。

当我们在程序中移动时收集记录时,我们会将它们放在一个与哈希图一样大的数组中,并放在它需要的正确位置。如果我们遇到新标签,我们将简单地调整数组的大小并将标签添加到哈希图中,而不是它当前遇到的顺序的值(因为这可能会覆盖某些东西),而是前一个元素的值 + 1 (这将是一个有序的哈希图,所以我会知道前一个元素是什么)。

一旦我们完全完成了程序,我们会将收集到的标题转储到文件的第一行。

所以,让我们看第一个例子:

<person id="1">
        <firstname>James</firstname>
        <middlename></middlename> 
        <lastname>Smith</lastname>
    </person>
    <person id="2">
        <firstname>Michael</firstname>
        <lastname>Jordan</lastname>
        <middlename>Rose</middlename>
</person>

第一次运行后的 hashmap 如下所示:

{firstname: 0, middlename: 1, lastname: 2}

当我们到达第二条记录时,中间名和姓氏的位置被交换,我们将简单地将姓氏放在该array[2]位置,并将中间名放在该array[1]位置。

如果我们遗漏了一些东西,例如这样的:

<person id="1">
        <firstname>James</firstname>
        <middlename></middlename> 
        <lastname>Smith</lastname>
    </person>
    <person id="2">
        <firstname>Michael</firstname>
        <lastname>Rose</lastname>
</person>

在第二次运行期间,该数组在第二个值中将为空(因为中间名不存在),我们只需将其转换为空字符串,并像往常一样在此处附加一个逗号。

有趣的部分是添加某些内容时:

<person id="1">
        <firstname>James</firstname>
        <middlename></middlename> 
        <lastname>Smith</lastname>
    </person>
    <person id="2">
        <firstname>Michael</firstname>
        <lastname>Rose</lastname>
        <dob></dob> 
</person>

这将生成如下所示的 CSV:

firstname,middlename,lastname,dob
James,,Smith
Michael,,Rose,1/10/11

,第一列在之后没有额外的Smith内容,但似乎即使这不是有效的 CSV 也可以吗?凉爽的。

无论如何-我认为现在真正的问题来了。我实际上并没有在 java 中使用 bufferedreader/bufferedwriter。我们正在使用 Azure 附带的流读取器/写入器,因为当然所有这些文件都在云上,并且在底层它基本上只是休息 api 调用。所以我认为我不能将标题转储到文件的第一行。无论如何,我什至不确定这是否可能。

所以。有哪位大神有想法吗?

4

1 回答 1

0
xls to csv convert




public class DeviceLibraryModel {
    private String parameterName;
    private String  dataType;
    private String  noOfRegister;
    private String  address;


    public String getParameterName() {
        return parameterName;
    }

    public String getDataType() {
        return dataType;
    }

    public String getNoOfRegister() {
        return noOfRegister;
    }

    public String getAddress() {
        return address;
    }

    public void setParameterName(String parameterName) {
        this.parameterName = parameterName;
    }

    public void setDataType(String dataType) {
        this.dataType = dataType;
    }

    public void setNoOfRegister(String noOfRegister) {
        this.noOfRegister = noOfRegister;
    }

    public void setAddress(String address) {
        this.address = address;
    }


    @Override
    public String toString() {
        return "DeviceLibraryModel{" + "ParameterName=" + parameterName + ", DataType=" + dataType + ", NoOfRegister=" + noOfRegister + ", Address=" + address + '}';
    }


}



> 



public class HeaderNameIndex  {


   private int pratameterNameIndex;
   private int dataTypeIndex;
   private int noOfRegister;
    private int address;

    public HeaderNameIndex(){

    }

    public int getPratameterNameIndex() {
        return pratameterNameIndex;
    }

    public int getDataTypeIndex() {
        return dataTypeIndex;
    }

    public int getNoOfRegister() {
        return noOfRegister;
    }

    public int getAddress() {
        return address;
    }

    public void setPratameterNameIndex(int pratameterNameIndex) {
        this.pratameterNameIndex = pratameterNameIndex;
    }

    public void setDataTypeIndex(int dataTypeIndex) {
        this.dataTypeIndex = dataTypeIndex;
    }

    public void setNoOfRegister(int noOfRegister) {
        this.noOfRegister = noOfRegister;
    }

    public void setAddress(int address) {
        this.address = address;
    }


    }






package model;


public interface HeaderNameInt {

    String PARAMETERNAME="Parameter Name";
    String DATATYPE="Data Type";
    String NOOFREGISTER="No Of Register";
    String ADDRESS="Address";



}


package services;




public class ReadFromXls extends HeaderNameIndex implements HeaderNameInt {

    public List<DeviceLibraryModel> xlsConvert(String xlsPath) throws FileNotFoundException, IOException {
        File file = new File(xlsPath);
        FileInputStream fi = new FileInputStream(file);
        List<DeviceLibraryModel> list = new ArrayList<>();
        HeaderNameIndex objHeaderNameIndex = new HeaderNameIndex();

        Workbook hw = new HSSFWorkbook(fi);
        Sheet sheet = hw.getSheetAt(0);


        Iterator<Row> rit = sheet.rowIterator();

        int rowNumber = 0;
        while (rit.hasNext()) {

            Row next = rit.next();

                DeviceLibraryModel dm = new DeviceLibraryModel();

                Iterator<Cell> cit = next.cellIterator();
                while (cit.hasNext()) {

                Cell cellit = cit.next();

                int iColumnIndex = cellit.getColumnIndex();
                DataFormatter dataFormatter = new DataFormatter();//to get all string
                String formatCellValue = dataFormatter.formatCellValue(cellit);

                if (rowNumber == 0) {
                    switch (formatCellValue) {
                        case PARAMETERNAME:
                            objHeaderNameIndex.setPratameterNameIndex(iColumnIndex);
                            break;

                        case DATATYPE:
                            objHeaderNameIndex.setDataTypeIndex(iColumnIndex);
                            //System.err.println(objHeaderNameIndex.getDataTypeIndex());
                            break;

                        case NOOFREGISTER:
                            objHeaderNameIndex.setNoOfRegister(iColumnIndex);
                            //System.err.println(objHeaderNameIndex.getNoOfRegister());
                            break;
                        case ADDRESS:
                            objHeaderNameIndex.setAddress(iColumnIndex);
                            break;

                        default:
                            System.err.println("nothing");

                    }
                }
                if (rowNumber > 0) {

                    if(iColumnIndex == objHeaderNameIndex.getPratameterNameIndex()) 
                        dm.setParameterName(formatCellValue);
                     else if (iColumnIndex == objHeaderNameIndex.getDataTypeIndex()) 
                        dm.setDataType(formatCellValue);
                     else if (iColumnIndex == objHeaderNameIndex.getNoOfRegister()) 
                        dm.setNoOfRegister(formatCellValue);
                     else if (iColumnIndex == objHeaderNameIndex.getAddress()) 
                        dm.setAddress(formatCellValue);

                }
            }
            if (rowNumber > 0) {

               list.add(dm);
            }
            rowNumber++;
            fi.close();
        }
       // System.err.println(list);

        return list;
    }
}






public class ConvertXlsToCsv {

    public void toCsv() throws IOException{
    ReadFromXls readXls=new ReadFromXls();
    String xlsPath="C:\\Users\\admin\\Desktop\\Java Training\\Input file\\Device.xls";
    List<DeviceLibraryModel> list = readXls.xlsConvert(xlsPath);
    String sep=",";
    String csvPath="C:\\Users\\admin\\Desktop\\Java Training\\Input file\\XlsToCsv.csv"; 
    File file=new File(csvPath);
    FileWriter writeData=new FileWriter(file,true);

       for(DeviceLibraryModel dm:list)
       {
           if(file.exists())
           {
           String parameterName = dm.getParameterName();
          writeData.append(parameterName+ '\n');
          writeData.append(sep+dm.getDataType()+sep+ '\n');     
          writeData.append(dm.getNoOfRegister()+sep+ '\n');
          writeData.append(dm.getAddress()+sep+ '\n');
          }else

           {
               String parameterName = dm.getParameterName();
               writeData.write(parameterName);
               writeData.write(sep+dm.getDataType()+sep);
               writeData.write(dm.getNoOfRegister()+sep);
               writeData.write(dm.getAddress()+sep);
           }


       }



       writeData.flush();
           writeData.close();  



    }
}


`



public class ReadXls {
    public static void main(String[] args)  {


        ConvertXlsToCsv convert=new ConvertXlsToCsv();
        try {

            convert.toCsv();

             } catch (IOException ex) {

                 System.err.println(ex);
            Logger.getLogger(ReadXls.class.getName()).log(Level.SEVERE, null, ex);
        }


    }

}
`
于 2020-02-27T05:18:15.277 回答