POI事件模式读取Excel 2007(三) - 解析步骤

一. 解析步骤

这里写图片描述

二. OPCPackage

当使用POI事件模式解析Excel XLSX文档时:

  1. POI根据xlsx文档的路径path获取到文件File - file
  2. 使用java.util.zip.ZipFile打开file文件 - zip
  3. 从zip中获取到[Content_Types].xml
  4. 解析[Content_Types].xml,记录解析出Excel各个xml名称:ArrayList
  5. Excel解析成ZipPackage实例对象

首先把xlsx文档解析包装成ZipPackage实例对象

package org.apache.poi.openxml4j.opc;

public enum PackageAccess {
    READ,   // 只读
    WRITE,  // 只写
    READ_WRITE // 读写
}

// 只读取xlsx文档
OPCPackage pkg = OPCPackage.open("C:\Users\Administrator\Desktop\测试.xlsx", PackageAccess.READ)

这里写图片描述

2.1 XLSX文档组成

Excel XLSX文档是有多个xml文件组成的,name各个xml是怎么组合在一起?POI是怎么来解析的呢?
在Excel文档中,存在一个[Content_Types].xml文档,这个文档记录了整个Excel文档中所有xml:
这里写图片描述

这里写图片描述

2.2 解析[Content_Types].xml

org.apache.poi.openxml4j.opc.internal.ContentTypeManager类用于解析[Content_Types].xml文档,记录解析出的结果

// ContentTypeManager解析方法
parseContentTypesFile(InputStream in)
<?xml version="1.0" encoding="UTF-8" standalone="true"?>

-<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">

<Default ContentType="application/vnd.openxmlformats-package.relationships+xml" Extension="rels"/>

<Default ContentType="application/xml" Extension="xml"/>

<Override ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml" PartName="/docProps/app.xml"/>

<Override ContentType="application/vnd.openxmlformats-package.core-properties+xml" PartName="/docProps/core.xml"/>

<Override ContentType="application/vnd.openxmlformats-officedocument.custom-properties+xml" PartName="/docProps/custom.xml"/>

<Override ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml" PartName="/xl/styles.xml"/>

<Override ContentType="application/vnd.openxmlformats-officedocument.theme+xml" PartName="/xl/theme/theme1.xml"/>

<Override ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml" PartName="/xl/workbook.xml"/>

<Override ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml" PartName="/xl/worksheets/sheet1.xml"/>

<Override ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml" PartName="/xl/worksheets/sheet2.xml"/>

</Types>

这里写图片描述
解析结果:
这里写图片描述

2.3 解析出ZipPackage

Excel XLSX文档会被POI解析出ZipPackage实例对象:
这里写图片描述

3. XSSFReader

XSSFReader这个类可以很容易地获得OOXML .xlsx文件的各个部分,适用于低内存sax解析或类似的情况
XSSFReader构成了XSSF的事件模式的核心部分

org.apache.poi.xssf.eventusermodel.XSSFReader

// 获取当前Excel所有Sheet中字符串
public SharedStringsTable getSharedStringsTable()

// 获取当前Excel所有Sheet中单元格样式
public StylesTable getStylesTable()

// 获取sharedStrings.xml的输入流
public InputStream getSharedStringsData()

// 获取styles.xml输入流
public InputStream getStylesData()

// 获取theme1.xml输入流
public InputStream getThemesData()

// 获取workbook.xml输入流
public InputStream getWorkbookData()

// 根据Sheet的id获取Sheet输入流
public InputStream getSheet(String relId)

// 获取Excel中所有SHeet的输入流的迭代器
public Iterator<InputStream> getSheetsData()

这里写图片描述

4. SAX解析XML

使用SAX解析XML,需要实现自己的处理类,需要继承DefaultHandler

public class SheetHandler extends DefaultHandler {

    /**
     * 解析到XML的开始标签触发此方法
     * 
     * @param uri 如"http://schemas.openxmlformats.org/spreadsheetml/2006/main"
     * @param localName 当前开始标签的名字
     * @param name 标签名
     * @param attributes 当前标签的属性对象
     * */
    @Override
    public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {
        if ("row".equals(name)) {// <row>:开始处理某一行
            //
        } else if ("c".equals(name)) {// <c>:一个单元格
            //
        } else if (isTextTag(name)) {// <v>:单元格值
            // 
        } else if ("f".equals(name)) {// <f>:公式表达式标签
            //
        } else if ("is".equals(name)) {// 内联字符串外部标签
            // 
        } else if ("col".equals(name)) {// 处理隐藏列
            //
        } 
    }

    /**
     * 返回单元格的值
     * */
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
        StringBuffer sb = new StringBuffer();
        sb.append(ch, start, length);
    }

    /**
     * 解析到XML的结束标签触发此方法
     * 如:</row>
     * @param uri
     * @param localName
     * @param name
     * */
    @Override
    public void endElement(String uri, String localName, String name) throws SAXException {
        if ("c".equals(name)) {// <c>标签结束
            //
        } else if (isTextTag(name)) {// 文本单元格结束标签
            //
        } else if ("row".equals(name)) {// 行结束标签
            //
        } else if ("f".equals(name)) {// </f>标签
            //
        } else if ("is".equals(name)) {// </is>标签
            //
        } else if ("worksheet".equals(name)) {// Sheet读取完成
            // 
        }
    }
}

处理模型:

public class ExcelParser {
    public void parse () {
        OPCPackage pkg = OPCPackage.open("C:\\Users\\Administrator\\Desktop\\测试.xlsx", PackageAccess.READ);
        try {
            XSSFReader reader = new XSSFReader(pkg);
            SharedStringsTable sst = reader.getSharedStringsTable();
            StylesTable st = reader.getStylesTable();
            XMLReader parser = XMLReaderFactory.createXMLReader();
            // 处理公共属性:Sheet名,Sheet合并单元格
            parser.setContentHandler(new SheetHandler());
            /**
             * 返回一个迭代器,此迭代器会依次得到所有不同的sheet。 
             * 每个sheet的InputStream只有从Iterator获取时才会打开。 
             * 解析完每个sheet时关闭InputStream。
             * */
            XSSFReader.SheetIterator sheets = (XSSFReader.SheetIterator) reader.getSheetsData();
            while (sheets.hasNext()) {
                InputStream sheetstream = sheets.next();
                InputSource sheetSource = new InputSource(sheetstream);
                try {
                    // 解析sheet: com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl:522
                    parser.parse(sheetSource);
                } finally {
                    sheetstream.close();
                }
            }
        } finally {
            pkg.close();
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值