使用SAX解析ooxml(2007版本)格式的Excel

2007版本的excel使用ooxml规范 生成的xml文档格式,熟悉文档格式,才能解析正确

<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main"
           xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
           xmlns:xdr="http://schemas.openxmlformats.org/drawingml/2006/spreadsheetDrawing"
           xmlns:x14="http://schemas.microsoft.com/office/spreadsheetml/2009/9/main"
           xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
           xmlns:etc="http://www.wps.cn/officeDocument/2017/etCustomData">
    <sheetPr/>
    <dimension ref="A1:G20"/>
    <sheetViews>
        <sheetView workbookViewId="0">
            <selection activeCell="F2" sqref="F2"/>
        </sheetView>
    </sheetViews>
    <sheetFormatPr defaultColWidth="10" defaultRowHeight="14.4" outlineLevelCol="6"/>
    <cols>
        <col min="1" max="1" width="21.7777777777778" customWidth="1"/>
        <col min="2" max="2" width="12.1111111111111" customWidth="1"/>
        <col min="3" max="3" width="42.4722222222222" customWidth="1"/>
        <col min="4" max="4" width="13.7037037037037" customWidth="1"/>
        <col min="5" max="6" width="20.7592592592593" customWidth="1"/>
        <col min="7" max="7" width="19.1296296296296" customWidth="1"/>
        <col min="8" max="8" width="9.76851851851852" customWidth="1"/>
    </cols>
    <sheetData>
        <row r="1" ht="66" customHeight="1" spans="1:6">
            <c r="A1" s="1">
                <v>0</v>
            </c>
            <c r="B1" s="1" t="s">
                <v>0</v>
            </c>
            <c r="C1" s="1" t="s">
                <v>1</v>
            </c>
            <c r="D1" s="1" t="s">
                <v>2</v>
            </c>
            <c r="F1" s="1"/>
        </row>
        <row r="2" ht="60" customHeight="1" spans="2:6">
            <c r="B2" s="1" t="s">
                <v>3</v>
            </c>
            <c r="C2" s="1" t="s">
                <v>4</v>
            </c>
            <c r="D2" s="1" t="s">
                <v>5</v>
            </c>
            <c r="E2" s="1" t="s">
                <v>6</v>
            </c>
            <c r="F2" t="s">
                <v>7</v>
            </c>
        </row>
        <row r="3" ht="61" customHeight="1" spans="1:7">
            <c r="A3" s="1">
                <v>0</v>
            </c>
            <c r="B3" s="1" t="s">
                <v>8</v>
            </c>
            <c r="C3" s="1" t="s">
                <v>9</v>
            </c>
            <c r="D3" s="1" t="s">
                <v>9</v>
            </c>
            <c r="E3" s="1" t="s">
                <v>10</v>
            </c>
            <c r="F3" s="1" t="s">
                <v>11</v>
            </c>
            <c r="G3" s="1" t="s">
                <v>12</v>
            </c>
        </row>
        <row r="4" ht="57" customHeight="1" spans="3:3">
            <c r="C4" s="2" t="s">
                <v>13</v>
            </c>
        </row>
        <row r="5" ht="25.6" customHeight="1" spans="1:6">
            <c r="A5" s="1">
                <v>0</v>
            </c>
            <c r="C5" s="3" t="s">
                <v>14</v>
            </c>
            <c r="D5" s="3"/>
            <c r="E5" s="3"/>
            <c r="F5" s="3"/>
        </row>
        <row r="6" ht="16.55" customHeight="1" spans="1:7">
            <c r="A6" s="1">
                <v>0</v>
            </c>
            <c r="C6" s="4" t="s">
                <v>15</v>
            </c>
            <c r="D6" s="4"/>
            <c r="E6" s="4"/>
            <c r="F6" s="4"/>
            <c r="G6" s="4"/>
        </row>
        <row r="7" ht="19.9" customHeight="1" spans="1:7">
            <c r="A7" s="1">
                <v>0</v>
            </c>
            <c r="C7" s="5" t="s">
                <v>16</v>
            </c>
            <c r="D7" s="11" t="s">
                <v>17</v>
            </c>
            <c r="E7" s="11" t="s">
                <v>18</v>
            </c>
            <c r="F7" s="12" t="s">
                <v>19</v>
            </c>
            <c r="G7" s="12" t="s">
                <v>20</v>
            </c>
        </row>
        <row r="8" ht="19.9" customHeight="1" spans="1:7">
            <c r="A8" s="1">
                <v>0</v>
            </c>
            <c r="C8" s="8" t="s">
                <v>21</v>
            </c>
            <c r="D8" s="13" t="s">
                <v>22</v>
            </c>
            <c r="E8" s="14">
                <v>60.111</v>
            </c>
            <c r="F8" s="14">
                <v>0.01</v>
            </c>
            <c r="G8" s="15">
                <v>60.101</v>
            </c>
        </row>
        <row r="9" ht="19.9" customHeight="1" spans="1:7">
            <c r="A9" s="1" t="s">
                <v>23</v>
            </c>
            <c r="B9" s="1" t="s">
                <v>24</v>
            </c>
            <c r="C9" s="16" t="s">
                <v>25</v>
            </c>
            <c r="D9" s="17" t="s">
                <v>26</v>
            </c>
            <c r="E9" s="18">
                <v>20.1</v>
            </c>
            <c r="F9" s="19">
                <v>0.005</v>
            </c>
            <c r="G9" s="20">
                <v>20.095</v>
            </c>
        </row>
        <row r="10" ht="19.9" customHeight="1" spans="1:7">
            <c r="A10" s="1" t="s">
                <v>23</v>
            </c>
            <c r="B10" s="1" t="s">
                <v>27</v>
            </c>
            <c r="C10" s="8" t="s">
                <v>28</v>
            </c>
            <c r="D10" s="13" t="s">
                <v>29</v>
            </c>
            <c r="E10" s="14">
                <v>40.011</v>
            </c>
            <c r="F10" s="14">
                <v>0.005</v>
            </c>
            <c r="G10" s="15">
                <v>40.006</v>
            </c>
        </row>
        <row r="11" ht="19.9" customHeight="1" spans="1:7">
            <c r="A11" s="1">
                <v>0</v>
            </c>
            <c r="C11" s="21" t="s">
                <v>30</v>
            </c>
            <c r="D11" s="22" t="s">
                <v>31</v>
            </c>
            <c r="E11" s="23">
                <v>300000</v>
            </c>
            <c r="F11" s="23">
                <v>1300</v>
            </c>
            <c r="G11" s="24">
                <v>298700</v>
            </c>
        </row>
        <row r="12" ht="19.9" customHeight="1" spans="1:7">
            <c r="A12" s="1" t="s">
                <v>23</v>
            </c>
            <c r="B12" s="1" t="s">
                <v>32</v>
            </c>
            <c r="C12" s="25" t="s">
                <v>25</v>
            </c>
            <c r="D12" s="26" t="s">
                <v>33</v>
            </c>
            <c r="E12" s="19">
                <v>100000</v>
            </c>
            <c r="F12" s="19">
                <v>500</v>
            </c>
            <c r="G12" s="20">
                <v>99500</v>
            </c>
        </row>
        <row r="13" ht="19.9" customHeight="1" spans="1:7">
            <c r="A13" s="1" t="s">
                <v>23</v>
            </c>
            <c r="B13" s="1" t="s">
                <v>34</v>
            </c>
            <c r="C13" s="8" t="s">
                <v>28</v>
            </c>
            <c r="D13" s="13" t="s">
                <v>35</v>
            </c>
            <c r="E13" s="14">
                <v>200000</v>
            </c>
            <c r="F13" s="14">
                <v>800</v>
            </c>
            <c r="G13" s="15">
                <v>199200</v>
            </c>
        </row>
        <row r="14" ht="19.9" customHeight="1" spans="1:7">
            <c r="A14" s="1">
                <v>0</v>
            </c>
            <c r="C14" s="27" t="s">
                <v>36</v>
            </c>
            <c r="D14" s="13" t="s">
                <v>37</v>
            </c>
            <c r="E14" s="14">
                <v>0</v>
            </c>
            <c r="F14" s="14">
                <v>0</v>
            </c>
            <c r="G14" s="15">
                <v>0</v>
            </c>
        </row>
        <row r="15" ht="19.9" customHeight="1" spans="1:7">
            <c r="A15" s="1" t="s">
                <v>23</v>
            </c>
            <c r="B15" s="1" t="s">
                <v>38</v>
            </c>
            <c r="C15" s="25" t="s">
                <v>25</v>
            </c>
            <c r="D15" s="26" t="s">
                <v>39</v>
            </c>
            <c r="E15" s="19">
                <v>0</v>
            </c>
            <c r="F15" s="19">
                <v>0</v>
            </c>
            <c r="G15" s="20">
                <v>0</v>
            </c>
        </row>
        <row r="16" ht="19.9" customHeight="1" spans="1:7">
            <c r="A16" s="1" t="s">
                <v>23</v>
            </c>
            <c r="B16" s="1" t="s">
                <v>40</v>
            </c>
            <c r="C16" s="8" t="s">
                <v>28</v>
            </c>
            <c r="D16" s="13" t="s">
                <v>41</v>
            </c>
            <c r="E16" s="14">
                <v>0</v>
            </c>
            <c r="F16" s="14">
                <v>0</v>
            </c>
            <c r="G16" s="24">
                <v>0</v>
            </c>
        </row>
        <row r="17" ht="19.9" customHeight="1" spans="1:7">
            <c r="A17" s="1">
                <v>0</v>
            </c>
            <c r="C17" s="27" t="s">
                <v>42</v>
            </c>
            <c r="D17" s="13" t="s">
                <v>43</v>
            </c>
            <c r="E17" s="14">
                <v>300060.111</v>
            </c>
            <c r="F17" s="14">
                <v>3860.454646</v>
            </c>
            <c r="G17" s="24">
                <v>296199.656354</v>
            </c>
        </row>
        <row r="18" ht="19.9" customHeight="1" spans="1:7">
            <c r="A18" s="1" t="s">
                <v>23</v>
            </c>
            <c r="B18" s="1" t="s">
                <v>44</v>
            </c>
            <c r="C18" s="25" t="s">
                <v>25</v>
            </c>
            <c r="D18" s="26" t="s">
                <v>45</v>
            </c>
            <c r="E18" s="19">
                <v>100020.1</v>
            </c>
            <c r="F18" s="19">
                <v>3059.571857</v>
            </c>
            <c r="G18" s="20">
                <v>96960.528143</v>
            </c>
        </row>
        <row r="19" ht="19.9" customHeight="1" spans="1:7">
            <c r="A19" s="1" t="s">
                <v>23</v>
            </c>
            <c r="B19" s="1" t="s">
                <v>46</v>
            </c>
            <c r="C19" s="8" t="s">
                <v>28</v>
            </c>
            <c r="D19" s="28" t="s">
                <v>47</v>
            </c>
            <c r="E19" s="29">
                <v>200040.011</v>
            </c>
            <c r="F19" s="29">
                <v>800.882789</v>
            </c>
            <c r="G19" s="30">
                <v>199239.128211</v>
            </c>
        </row>
        <row r="20" ht="15.8" customHeight="1" spans="1:7">
            <c r="A20" s="1">
                <v>0</v>
            </c>
            <c r="C20" s="1" t="s">
                <v>48</v>
            </c>
            <c r="D20" s="1"/>
            <c r="E20" s="1"/>
            <c r="F20" s="1"/>
            <c r="G20" s="1"/>
        </row>
    </sheetData>
    <mergeCells count="3">
        <mergeCell ref="C5:F5"/>
        <mergeCell ref="C6:G6"/>
        <mergeCell ref="C20:G20"/>
    </mergeCells>
    <pageMargins left="0.75" right="0.75" top="0.26875" bottom="0.26875" header="0" footer="0"/>
    <pageSetup paperSize="9" orientation="portrait"/>
    <headerFooter/>
</worksheet>
//将ooxml格式的excel转化为opc规范格式
OPCPackage pkg = OPCPackage.open(file);
XSSFReader xssfReader = new XSSFReader(pkg);
//样式表
stylesTable = xssfReader.getStylesTable();
//共享字符串变量表
SharedStringsTable sst = xssfReader.getSharedStringsTable();
//获取解析器
XMLReader parser = XMLReaderFactory.createXMLReader("com.sun.org.apache.xerces.internal.parsers.SAXParser");
this.sst = sst;
parser.setContentHandler(this);
XSSFReader.SheetIterator sheets = (XSSFReader.SheetIterator) xssfReader.getSheetsData();
while (sheets.hasNext()) { //遍历sheet
    curRow = 1; //标记初始行为第一行
    sheetIndex++;
    InputStream sheet = sheets.next(); //sheets.next()和sheets.getSheetName()不能换位置,否则sheetName报错
    sheetName = sheets.getSheetName();
    InputSource sheetSource = new InputSource(sheet);
    parser.parse(sheetSource); //解析excel的每条记录,在这个过程中startElement()、characters()、endElement()这三个函数会依次执行
    sheet.close();
}

核心思想:
自定义Handler实现Defaulthandler,并重写其中的startElement,characters,endElement方法

class myHandler extends DefaultHandler{
	//第一步
    @Override
    public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {
    	//重点使用
    	name:当前元素的XML 限定(前缀)名
    	attributes:当前元素节点的属性
    	//例:c表示单元格cell
    	if(name.equals("c")){...}
    }
    //第二步
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
    	//获取textNode中的值,该值在不同数据类型下,代表含义不同
    	//如当前单元格时字符串类型,则里面的值表示该单元格实际值在SST(共享字符串变量表)中的索引
    	//若当前单元格类型是数字类型,则表示实际数字值
        value = new String(ch, start, length);
    }
    //第三步
    @Override
    public void endElement(String uri, String localName, String name) throws SAXException {
    		//跟开始节点相对应,xml中的元素都是成对出现的,有开始,有结束
    }
}

其中的难点在与判断当前单元格的数据类型,并获取其实际值,以及空单元补全问题:

 /**
     * 单元格中的数据可能的数据类型
     */
    enum CellDataType {
        BOOL, ERROR, FORMULA, INLINESTR, SSTINDEX, NUMBER, DATE, NULL
    }

判断当前单元格类型的方法:

 public void getCellDataType(Attributes attributes) {
        nextDataType = CellDataType.NUMBER; //cellType为空,则表示该单元格类型为数字
        formatIndex = -1;
        formatString = null;
        //通过XML 限定(前缀)名查找属性的值
        String cellType = attributes.getValue("t"); //单元格类型
        String cellStyleStr = attributes.getValue("s"); //
        String columnData = attributes.getValue("r"); //获取单元格的位置,如A1,B1

        if ("b".equals(cellType)) { //处理布尔值
            nextDataType = CellDataType.BOOL;
        } else if ("e".equals(cellType)) {  //处理错误
            nextDataType = CellDataType.ERROR;
        } else if ("inlineStr".equals(cellType)) {//处理excel函数
            nextDataType = CellDataType.INLINESTR;
        } else if ("s".equals(cellType)) { //处理字符串
            nextDataType = CellDataType.SSTINDEX;
        } else if ("str".equals(cellType)) {//处理公式
            nextDataType = CellDataType.FORMULA;
        }
        
		//excel中的日期类型较难处理,下面是其处理方式
        if (cellStyleStr != null) {
            int styleIndex = Integer.parseInt(cellStyleStr);
            XSSFCellStyle style = stylesTable.getStyleAt(styleIndex);
            formatIndex = style.getDataFormat();
            formatString = style.getDataFormatString();
			//说明是日期类型
            if (formatString.contains("m/d/yy")) {
                nextDataType = CellDataType.DATE;
                formatString = "yyyy-MM-dd hh:mm:ss";
            }
            //说明是NULL类型,我也不知道NULL类型是啥
            if (formatString == null) {
                nextDataType = CellDataType.NULL;
                formatString = BuiltinFormats.getBuiltinFormat(formatIndex);
            }
        }
    }

解析excel的时候,有两个大问题不好解决:
第一个:空格问题,总是因为各种原因,导致空格检测不出来,造成数据列不对应
第二个:就是字段名称与字段值会对应不上。在我应用中,我是需要将excel解析后,再将数据解析整理成sql语句,并将数据插入到数据库,所以如果数据和字段对应不上,会造成严重的错误。我的解决办法是:使用单元格的索引作为Key

/**
     * 解析的excel,配置项 行号:从0开始,列号:从A开始
     * 整个报表第一列:数据有效列判断 值:VALID#,说明是要操作插入数据库的列 值为其它:说明无效活或者其他用处
     * 第一行:第B列=数据表名称,第C列=删除数据时的筛选条件 第D列=报表标题
     * 第二行:从第二列开始:报表参数 key#value
     * 第三行:从第二列开始 表字段名,与表中数据列列号对应
     */
static {
        /*
            条件行
         */
        positionMap.put("rowA",new String[]{"0","99"});//标题名,表名,筛选条件所在行号,列无效 第一行
        positionMap.put("tablename",new String[]{"0","B"});//表名位置
        positionMap.put("condition",new String[]{"0","C"});//筛选你条件位置
        positionMap.put("title",new String[]{"0","D"});//标题位置
        positionMap.put("rowB",new String[]{"1","99"});//报表参数所在行 第二行
        positionMap.put("rowC",new String[]{"2","99"});//表字段所在行 第三行
        /*
          配置
        */
        positionMap.put("validcolumn",new String[]{"99","A"});//有效列所在位置 行无效,A表示第一列 不管行号
    }

上面的是配置项,单元格的索引:A1,包括列号和行号,解析每一行数据的时候,只需要列号作为key,所以有:

 /*
            c:单元格
            v:单元格中的元素
         */
        //c => 单元格
        if ("c".equals(name)) {
            //当前单元格位置
            String cellIndex = attributes.getValue("r");
            //说明是第一列,将行号去掉,只要列号
            //if(cellIndex.indexOf("A")!=-1){
            cellIndex = cellIndex.replaceAll("\\d+","");
           // }
            //前一个单元格的位置
            if (preRef == null) {
                preRef = cellIndex;
            } else {
                preRef = ref;
            }
            //当前单元格的位置
            ref = cellIndex;
            //设定单元格类型
            this.setNextDataType(attributes);
        }

至此,列号和字段名称以及字段值就相互对应上了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值