java-POI事件模式(SAX)解析execl,每一个标签的含义及原理

作者在 2019-05-13 17:59:12 发布以下内容

前言:

    之所以前面做了一个POI的用户模式解析execl的介绍,是因为该模式对于开发时的灵活性,可操作性上较为方便,且该模式对于复杂的EXECL操作有明显的优势。POI用户模式对于EXECL的写操作(创建固定格式的复杂的交叉报表),可以轻松完成,因此会先简单介绍。但是,凡事都有例外,有优点固然也会有缺点。例如:当对于一个开发系统有性能上的要求时,尤其是对于大数据量的性能要求时,POI的用户模式,显然会比较吃力,下面就可以采用SAX——POI事件模式替代。

    下面进入正文,依然采用的是MAVEN+SPRING BOOT+MYBATIS jdk1.8软件环境,WINDOW系统

一,需要导的MAVEN SAX包

<dependency>
		    <groupId>sax</groupId>
		    <artifactId>sax</artifactId>
		    <version>2.0.1</version>
		</dependency>
		
		<!-- SAX驱动 -->
		<dependency>
		    <groupId>xerces</groupId>
		    <artifactId>xercesImpl</artifactId>
		    <version>2.10.0</version>
		</dependency>
下面先贴代码,再做说明:



public class SaxCell {
	/**
	 * 
	 * 记录当前循环行的每一个单元格的值的开始列和字符长度
	 * 
	 */
	private int start;
	private int length;
	private CellDataType nextDataType;
	private char[] ch;
	private String lastIndex;
	
	public String getLastIndex(){
		return lastIndex;
	}
	
	public void setLastIndex(String lastIndex){
		this.lastIndex = lastIndex;
	}
	
	public char[] getCh(){
		return ch;
	}
	
	public void setCh(char[] ch){
		this.ch = ch;
	}
	
	public CellDataType getCellDataType(){
		return nextDataType;
	}
	
	public void setCextDataType(CellDataType nextDataType){
		this.nextDataType = nextDataType;
	}
	public int getStart() {
		return start;
	}
	public void setStart(int start) {
		this.start = start;
	}
	public int getLength() {
		return length;
	}
	public void setLength(int length) {
		this.length = length;
	}
	
	public SaxCell(){}
	
	//改构造方法会将execl中的每一行的具体信息一同存储下来
	public SaxCell(int start,int lengxth,CellDataType nextDataType,char[] ch,String lastIndex){
		this.start = start;
		this.length = lengxth;
		this.nextDataType = nextDataType;
		this.ch = ch;
		this.lastIndex = lastIndex;
	}
	
	//改构造方法只会存储当前单元格的开始列,指的索引索引位置,单元格的格式,单元格的值的长度
	public SaxCell(int start,int lengxth,CellDataType nextDataType,String lastIndex){
		this.start = start;
		this.length = lengxth;
		this.nextDataType = nextDataType;
		this.lastIndex = lastIndex;
	}
}
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.ss.usermodel.BuiltinFormats;
import org.apache.poi.ss.usermodel.DataFormatter;
import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.model.SharedStringsTable;
import org.apache.poi.xssf.model.StylesTable;
import org.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;

import cn.stylefeng.roses.core.util.ToolUtil;

import com.nssolsh.boot.modular.system.model.CellDataType;
import com.nssolsh.boot.modular.system.model.ExeclDataSiteAndValue;
import com.nssolsh.boot.modular.system.model.SaxCell;
 
/**
 * @author qjwyss
 * @date 2018/12/19
 * @description 读取EXCEL辅助类
 */
public class ExcelXlsxReaderWithDefaultHandler extends DefaultHandler {
    
    public ExcelXlsxReaderWithDefaultHandler() {}
 
 
    /**
     * 共享字符串表
     */
    private SharedStringsTable sst;
 
    /**
     * 上一次的索引值
     */
    private String lastIndex;
 
    /**
     * 文件的绝对路径
     */
    private String filePath = "";
 
    /**
     * 工作表索引
     */
    private int sheetIndex = 0;
 
    /**
     * sheet名
     */
    private String sheetName = "";
 
    /**
     * 总行数
     */
    private int totalRows = 0;
    
    /**
     * 存放第7含的列数
     * 
     */
    private int tempTotalCells = 0;
    /**
     * 一行内cell集合
     */
    private List<String> cellList = new ArrayList<String>();
    
    /**
     * 判断整行是否为空行的标记
     */
    private boolean flag = false;
 
    /**
     * 当前行
     */
    private int curRow = 1;
 
    /**
     * 当前列
     */
    private int curCol = 0;
    
    /**
     * 临时list下标
     */
    private int tempCurCol = 0;
 
    /**
     * T元素标识
     */
    private boolean isTElement;
 
    /**
     * 单元格数据类型,默认为字符串类型
     */
    private CellDataType nextDataType = CellDataType.SSTINDEX;
    
    private CellDataType tempNextDataType;
    
    private final DataFormatter formatter = new DataFormatter();
 
    /**
     * 单元格日期格式的索引
     */
    private short formatIndex;
 
    /**
     * 日期格式字符串
     */
    private String formatString;
 
    //定义前一个元素和当前元素的位置,用来计算其中空的单元格数量,如A6和A8等
    private String preRef = null, ref = null;
    
    //记录每行第一个单元格
    private String tempFirstRef=null;
    //定义该文档一行最大的单元格数,用来补全一行最后可能缺失的单元格
    private String maxRef = null;
 
    /**
     * 单元格
     */
    private StylesTable stylesTable;
 
    /**
     * 总行号
     */
    private Integer totalRowCount;
    
    private static Map<String,List<String>> map = new ConcurrentHashMap<String, List<String>>();
	List<String> list = new ArrayList<String>();
    /**
     * 时间范围
     */
    List<String> dateList = new ArrayList<String>();
    
    private String tempCellStr = "";
    
    private String tempLastIndex;
    
    private static List<String> regxList = new ArrayList<>();
    static{
    	regxList.add("(");
    	regxList.add(")");
    	regxList.add("\"");
    }
    //临时存一行中的每一个单元的开始位置以及单元格中的字符的长度
    private List<SaxCell> saxCellList = new ArrayList<SaxCell>();
    /**
     * 遍历工作簿中所有的电子表格
     * 并缓存在mySheetList中
     *
     * @param filename
     * @throws Exception
     */
    public Map<String,List<String>> process(String filename) throws Exception {
        filePath = filename;
        OPCPackage pkg = OPCPackage.open(filename);
        XSSFReader xssfReader = new XSSFReader(pkg);
        stylesTable = xssfReader.getStylesTable();
        SharedStringsTable sst = xssfReader.getSharedStringsTable();
        XMLReader parser = XMLReaderFactory.createXMLReader("org.apache.xerces.parsers.SAXParser");
        this.sst = sst;
        parser.setContentHandler(this);
        XSSFReader.SheetIterator sheets = (XSSFReader.SheetIterator) xssfReader.getSheetsData();
        InputStream psiDataSheet = null;
        while (sheets.hasNext()) { //遍历sheet
            curRow = 1; //标记初始行为第一行
            sheetIndex++;
            psiDataSheet = sheets.next(); //sheets.next()和sheets.getSheetName()不能换位置,否则sheetName报错
        	sheetName = sheets.getSheetName();
        	if("PSI Data".equals(sheetName)){
        		InputSource sheetSource = new InputSource(psiDataSheet);
        		parser.parse(sheetSource); //解析excel的每条记录,在这个过程中startElement()、characters()、endElement()这三个函数会依次执行
        	}
        	psiDataSheet.close();
        }
       //由于是全局变量,下次请求数据可能还在,所以这里清除掉所有全局变量的值
       cellList = new ArrayList<String>();
       sst = new SharedStringsTable();
       lastIndex = null;
       filePath = "";
       sheetIndex = 0;
       sheetName = "";
       totalRows = 0;
       tempTotalCells = 0;
       flag = false;
       curRow = 1;
       curCol = 0;
       tempCurCol = 0;
       formatString = "";
       preRef = null;
       ref = null;
       tempFirstRef=null;
       maxRef = null;
       totalRowCount = null;
       list = new ArrayList<String>();
       dateList = new ArrayList<String>();
       tempCellStr = "";
       tempLastIndex = "";
       regxList = new ArrayList<>();
       saxCellList = new ArrayList<SaxCell>();
       Map<String,List<String>> returnMap = map;
       map = new ConcurrentHashMap<String, List<String>>();
       return returnMap; //返回已经读取的一整行数据
    }
    public static int excelColStrToNum(String colStr, int length) {
        int num = 0;
        int result = 0;
        for(int i = 0; i < length; i++) {
            char ch = colStr.charAt(length - i - 1);
            num = (int)(ch - 'A' + 1);
            num *= Math.pow(26, i);
            result += num;
        }
        return result;
    }
    
    /**
     * 第一个执行
     *
     * @param uri
     * @param localName
     * @param name
     * @param attributes
     * @throws SAXException
     */
    @Override
    public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {
 
        // 获取总行号  格式: A1:B5    取最后一个值即可
        if("dimension".equals(name)) {
            String dimensionStr = attributes.getValue("ref");
            String colNum = dimensionStr.substring(dimensionStr.lastIndexOf(":")+1);
            
            try {
            	//获取总行数
            	totalRowCount = Integer.parseInt(StringUtil.getIndexEndStr(colNum));
            	
			} catch (Exception e) {
				System.out.println(dimensionStr);
				// TODO: handle exception
			}
         
        }
 
        //c => 单元格
        if ("c".equals(name)) {
            //前一个单元格的位置
            if (preRef == null) {
                preRef = attributes.getValue("r");
            } else {
            	if(!ToolUtil.isEmpty(lastIndex)){
            		preRef = ref;
            	}
            }
 
            //当前单元格的位置
            ref = attributes.getValue("r");
            //设定单元格类型
            this.setNextDataType(attributes);
        }
        
        //当元素为t时
        if ("t".equals(name)) {
            isTElement = true;
        } else {
            isTElement = false;
        }
        //置空
        lastIndex = "";
        tempLastIndex = "";
        
        if("H43".equals(ref)){
        	System.out.println("ref:"+ref);
        }
    }
 
 
    /**
     * 第二个执行
     * 得到单元格对应的索引值或是内容值
     * 如果单元格类型是字符串、INLINESTR、数字、日期,lastIndex则是索引值
     * 如果单元格类型是布尔值、错误、公式,lastIndex则是内容值
     *
     * @param ch
     * @param start
     * @param length
     * @throws SAXException
     */
    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
    	if(start == 0){
    		//标记每一行的开始,清空saxCellList,tempCurCol是想saxCellList插入值时的集合下标
    		saxCellList = new ArrayList<SaxCell>();
    		saxCellList.clear();
    		tempCurCol = 0;
    	}
    	
    	lastIndex += new String(ch, start, length);
    	
    	SaxCell sc = new SaxCell(start,length, nextDataType,ch,lastIndex);
    	saxCellList.add(tempCurCol,sc);
    	
    	SaxCell tempSc = null;
    	if(saxCellList.size()>1){
    		/**
    		 * 数组下标比数组长度小1,取倒数第二个值就减去2,倒数第二个就是上一个非空单元格的值的索引
    		 */
    		tempSc = saxCellList.get(saxCellList.size()-2); 
    		int tempStart = tempSc.getStart();
    		int tempLength = tempSc.getLength();
    		char[] tempCh = tempSc.getCh();
    		String tempLastIndex1 = tempSc.getLastIndex();
    		
    		tempNextDataType = tempSc.getCellDataType();
    		tempLastIndex += tempLastIndex1;
    	}
    	tempCurCol++;
    }
 
    public void getCellList(){
    	//用空字符串补充前面缺失的单元格
        if(!ToolUtil.isEmpty(ref)&&cellList.size()==0){
        	String tempRef = StringUtil.getStartIndexStr(ref, 0);
        	String firstCell = "A"+curRow;
        	int len = countNullCell(ref ,firstCell);
        	this.tempFirstRef = ref;
        	for(int i=0;i<len+1;i++){
        		cellList.add(curCol,"");
        		curCol++;
        	}
        }
    }
 
    /**
     * 第三个执行
     *
     * @param uri
     * @param localName
     * @param name
     * @throws SAXException
     */
    @Override
    public void endElement(String uri, String localName, String name) throws SAXException {
    	ExeclDataSiteAndValue edsav = null;
    	
    	//t元素也包含字符串
        if (isTElement) {//这个程序没经过
            //将单元格内容加入rowlist中,在这之前先去掉字符串前后的空白符
            String value = lastIndex.trim();
            
            value = value == null?"":String.valueOf(value);
            
            cellList.add(value == null?"":String.valueOf(value));
            curCol++;
            isTElement = false;
            //如果里面某个单元格含有值,则标识该行不为空行
            if (value != null && !"".equals(value)) {
                flag = true;
            }
        } else if ("v".equals(name)) {
            //v => 单元格的值,如果单元格是字符串,则v标签的值为该字符串在SST中的索引
        	getCellList();
        	String value = null;
			try {
				if(ToolUtil.isEmpty(cellList)){
					
					//设置需要强制修改单元格取值类型为字符串的单元格
					String tempPer = cellList.get(cellList.size()-1);
					switch(tempPer){
					case "Period":
						nextDataType = CellDataType.SSTINDEX;
						break;
					}
				}
				value = this.getDataValue(lastIndex.trim(), "");
			} catch (Exception e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
			
			//首次循环获取单元格值时tempLastIndex 为空,curRow 时当前行的索引,对7行包含7行之下的所有单元格,空白单元格使用空字符串代替
			if(ToolUtil.isEmpty(tempLastIndex)||curRow>=7) {
    			tempCellStr = "";
			}else {
				//根据索引值获取对应的单元格值
	        	//单单元格列标不一致时,取上一个不为空的单元格的值,赋值给临时存储字符串
	        	if(!ref.equals(preRef)){
        			try{
        				if(ToolUtil.isNum(tempLastIndex)){
        					try {
        						nextDataType = tempNextDataType;
								tempCellStr = this.getDataValue(tempLastIndex.trim(), "");
								
							} catch (Exception e) {
								
								e.printStackTrace();
								
							}
        				}else{
        					tempCellStr = value;
        				}
        			}catch(java.lang.NumberFormatException e){
        				e.printStackTrace();
        			}
	        	}
			}
			
            //在向空单元格填充值时,使用临时字段
            //补全单元格之间的空单元格
        	//补全单元格时,第一个单元格不需要补
            if (!ref.equals(preRef)&&!tempFirstRef.equals(ref)) {
                int len = countNullCell(ref, preRef);
                
                for (int i = 0; i < len; i++) {
                    cellList.add(curCol, tempCellStr);
                    curCol++;
                }
            }
            
            cellList.add(curCol, value);
            curCol++;
            //如果里面某个单元格含有值,则标识该行不为空行
            if (value != null && !"".equals(value)) {
                flag = true;
            }
        } else {
            //如果标签名称为row,这说明已到行尾,调用optRows()方法
            if ("row".equals(name)) {
                //默认第一行为表头,以该行单元格数目为最大数目
                if (curRow == 1) {
                    maxRef = ref;
                }
                //补全一行尾部可能缺失的单元格
                if (maxRef != null) {
                    int len = countNullCell(maxRef, ref);
                    for (int i = 0; i <= len; i++) {
                    	
                    	//edsav = new ExeclDataSiteAndValue(ref,value);
                        cellList.add(curCol, cellList.get(curCol-1));
                        curCol++;
                    }
                }
                
                
                //当7行一下的列数和第7行的列数不一致时,少的用空格补齐
                if(curRow > 7 && cellList.size()<tempTotalCells) {
                	int tempCountCell = tempTotalCells - cellList.size();
                	for(int i = curCol;i<tempCountCell ; i++) {
                		cellList.add(i,"");
                	}
                }
                
                //记录第7行的列数
                if( curRow == 7) {
                	tempTotalCells = cellList.size();
                	List<String> tempFiveRow = map.get("5");
                	addList(tempFiveRow,"5");
                	List<String> tempSixRow = map.get("6");
                	addList(tempSixRow,"6");
                	
                }
                
                if (flag) { //该行不为空行且该行不是第一行,则发送(第一行为列名,不需要)
                	if(!map.containsKey(curRow)){
                		map.put(String.valueOf(curRow), cellList);
                		cellList = new ArrayList<String>();
                	}
                    totalRows++;
                }
                cellList = new ArrayList<String>();
                saxCellList = new ArrayList<SaxCell>();
                curRow++;
                tempCellStr = null;
                tempCurCol = 0;
                curCol = 0;
                preRef = null;
                ref = null;
                flag = false;
            }
        }
    }
    
    /**
     * 更新第5行和第六行最后一列的合并单元格缺少的值
     * @param list
     * @param row
     */
    public void addList(List<String> list,String row){
    	
    	String tempCellValue = list.get(list.size()-1);
    	int cz = tempTotalCells - list.size();
    	for(int i=0;i<cz;i++) {
    		list.add(list.size(),tempCellValue);
    		curCol ++;
    	}
    	map.put(row,list);
    }
    /** 
     * 处理数据类型
     *
     * @param attributes
     */
    public void setNextDataType(Attributes attributes) {
        nextDataType = CellDataType.NUMBER; //cellType为空,则表示该单元格类型为数字
        formatIndex = -1;
        formatString = null;
        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)) {
            nextDataType = CellDataType.INLINESTR;
        } else if ("s".equals(cellType)) { //处理字符串
            nextDataType = CellDataType.SSTINDEX;
        } else if ("str".equals(cellType)) {
            nextDataType = CellDataType.FORMULA;
        }
 
        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") || formatString.contains("yyyy/mm/dd") || formatString.contains("yyyy/m/d")) {
                nextDataType = CellDataType.DATE;
                formatString = "yyyy-MM-dd hh:mm:ss";
            }
 
            if (formatString == null) {
                nextDataType = CellDataType.NULL;
                formatString = BuiltinFormats.getBuiltinFormat(formatIndex);
            }
        }
    }
 
    /**
     * 对解析出来的数据进行类型处理
     *
     * @param value   单元格的值,
     *                value代表解析:BOOL的为0或1, ERROR的为内容值,FORMULA的为内容值,INLINESTR的为索引值需转换为内容值,
     *                SSTINDEX的为索引值需转换为内容值, NUMBER为内容值,DATE为内容值
     * @param thisStr 一个空字符串
     * @return
     */
    @SuppressWarnings("deprecation")
    public String getDataValue(String value, String thisStr) throws Exception {
        switch (nextDataType) {
            // 这几个的顺序不能随便交换,交换了很可能会导致数据错误
            case BOOL: //布尔值
                char first = value.charAt(0);
                thisStr = first == '0' ? "FALSE" : "TRUE";
                break;
            case ERROR: //错误
                thisStr = "\"ERROR:" + value.toString() + '"';
                break;
            case FORMULA: //公式
                thisStr = "" + value.toString() + "";
                break;
            case INLINESTR:
                XSSFRichTextString rtsi = new XSSFRichTextString(value.toString());
                thisStr = rtsi.toString();
                rtsi = null;
                break;
            case SSTINDEX: //字符串
                String sstIndex = value.toString();
                int idx = 0 ;
                XSSFRichTextString rtss = null;
                try {
                    idx = Integer.parseInt(sstIndex);
                    rtss = new XSSFRichTextString(sst.getEntryAt(idx));//根据idx索引值获取内容值
                    thisStr = StringUtil.replaceStr(rtss.toString(), regxList);
                    rtss = null;
                } catch (Exception ex) {
                    thisStr = value.toString();
                }
                break;
            case NUMBER: //数字
                thisStr = value;
                break;
            case DATE: //日期
                thisStr = formatter.formatRawCellContents(Double.parseDouble(value), formatIndex, formatString);
                // 对日期字符串作特殊处理,去掉T
                thisStr = thisStr.replace("T", " ");
                break;
            default:
                thisStr = " ";
                break;
        }
        return thisStr;
    }
 
    public int countNullCell(String ref, String preRef) {
        //excel2007最大行数是1048576,最大列数是16384,最后一列列名是XFD
        String xfd = ref.replaceAll("\\d+", "");
        String xfd_1 = preRef.replaceAll("\\d+", "");
 
        xfd = fillChar(xfd, 3, '@', true);
        xfd_1 = fillChar(xfd_1, 3, '@', true);
 
        char[] letter = xfd.toCharArray();
        char[] letter_1 = xfd_1.toCharArray();
        int res = (letter[0] - letter_1[0]) * 26 * 26 + (letter[1] - letter_1[1]) * 26 + (letter[2] - letter_1[2]);
        return res - 1;
    }
 
    public String fillChar(String str, int len, char let, boolean isPre) {
        int len_1 = str.length();
        if (len_1 < len) {
            if (isPre) {
                for (int i = 0; i < (len - len_1); i++) {
                    str = let + str;
                }
            } else {
                for (int i = 0; i < (len - len_1); i++) {
                    str = str + let;
                }
            }
        }
        return str;
    }
 
}


import java.util.List;
import java.util.Map;
 
/**
 * @author qjwyss
 * @date 2018/12/19
 * @description 读取EXCEL工具类
 */
public class ExcelReaderUtil {
 
 
    public static Map<String,List<String>> readExcel(String filePath) throws Exception {
    	Map<String,List<String>> map = null;
        if (filePath.endsWith(ExcelConstant.EXCEL07_EXTENSION)) {
            ExcelXlsxReaderWithDefaultHandler excelXlsxReader = new ExcelXlsxReaderWithDefaultHandler();
            map = excelXlsxReader.process(filePath);
        } else {
            throw new Exception("文件格式错误,fileName的扩展名只能是xlsx!");
        }
        return map;
    }
 
}
说明:


        EXECL原始文件的说明:

        1. 随机创建一个EXECL原文件,右键重命名,将后缀改为rar,然后解压,发现可以解压出三个文件夹(_rels、docProps、xl)和一个同目录的xml([Content_Types].xml),这里我们需要关心文件在xl文件夹中,所以对该文件进行详细说明。

        1.1 xl文件夹包含的文件也是有多层的分别是文件夹(_rels、drawings、theme、worksheets)和同级的xml文件(comments1.xml、sharedStrings.xml、styles.xml、workbook.xml)

        1.2 主要文件所对应的execl中的数据

        1.2.1 sharedStrings.xml

        对应的是execl中的所有字符串型数据

        1.2.2 styles.xml

        对应的是execl中的所有样式

        1.2.4 workbook.xml

        对应的是execl中的所有sheet的名称,位置以及某个sheet引用的外部数据的位置

        1.2.5 xl中文件夹中的文件说明

        1.2.5.1 worksheets文件夹

        打开文件夹,发现里面还是由文件夹和xml文件构成,这里直接说明主体,多个xml就是我们创建的EXECL中所包含的sheet数量(说白了就是你创建了几个sheet,这里就会有几个xml文件),然后我们的EXECL数据就存在这几个xml中。

        2. 当采用SAX解析EXECL时,需要知道的是该模式通过继承DefaultHandler,然后实现其的startElement、characters、endElement,三个方法,SAX API会一次按顺序执行该三个方法,该事件模式读取EXECL方式是将EXECL压缩成压缩包,然后再解压,获取EXECL的XML下的实际内容,然后按照XML标签按照对应的标签获取不同的数据

        2.1 下面对不同的标签包含的对应的信息简要说明一下

        下面以实际xml的格式简要说明xml中的标签及对应的作用


<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 <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>
		<pageSetUpPr fitToPage="1"/>
	</sheetPr>
	<dimension ref="A1:CD43"/>
	 <sheetViews>
	  <sheetView showGridLines="0" tabSelected="1" zoomScale="90" zoomScaleNormal="90" workbookViewId="0">
		  <pane xSplit="15" ySplit="7" topLeftCell="P8" activePane="bottomRight" state="frozen"/>
		  <selection/><selection pane="topRight"/><selection pane="bottomLeft"/><selection pane="bottomRight" activeCell="K2" sqref="K2"/>
	  </sheetView>
	</sheetViews>
	<sheetFormatPr defaultColWidth="9" defaultRowHeight="12.75" customHeight="1"/>
	<cols>
	  <col min="1" max="1" width="1.36666666666667" style="197" customWidth="1" outlineLevel="1"/>
	  <col min="2" max="2" width="1.36666666666667" style="197" customWidth="1"/>
	 </cols>
	 <sheetData>
		<row r="1" ht="5.15" customHeight="1" spans="34:82"><c r="AH1" s="201"/><c r="AI1" s="201"/><c r="AJ1" s="201"/><c r="AL1" s="200"/><c r="AM1" s="200"/><c r="AN1" s="200"/><c r="BC1" s="201"/><c r="BD1" s="201"/><c r="BE1" s="201"/><c r="BG1" s="200"/><c r="BH1" s="200"/><c r="BI1" s="200"/><c r="BX1" s="201"/><c r="BY1" s="201"/><c r="BZ1" s="201"/><c r="CB1" s="200"/><c r="CC1" s="200"/><c r="CD1" s="200"/></row>	
		<row r="2" ht="20.15" customHeight="1" spans="4:82">
		  <c r="D2" s="202" t="s"><v>0</v></c>
		  <c r="E2" s="203" t="s"><v>1</v></c>
		  <c r="F2" s="202" t="s"><v>2</v></c>
		  <c r="G2" s="204" t="s"><v>3</v></c>
		  <c r="H2" s="205" t="s"><v>4</v></c>
		  <c r="I2" s="241" t="s"><v>5</v></c>
		  <c r="J2" s="242" t="s"><v>6</v></c>
		  <c r="K2" s="243" t="s"><v>7</v></c>
		  <!-- 其他内容忽略 -->
		</row>
		<row r="3" ht="20.15" customHeight="1" spans="4:82">
		  <c r="D3" s="202" t="s"><v>9</v></c>
		  <c r="E3" s="203" t="s"><v>10</v></c>
		  <c r="F3" s="202" t="s"><v>11</v></c>
		  <c r="G3" s="206"><v>43565</v></c>
		  <c r="H3" s="202" t="s"><v>12</v></c>
		  <c r="I3" s="206" t="s"><v>13</v></c>
		  <!--其他单元格忽略-->
		</row>
		<row r="5" ht="20.15" customHeight="1" spans="2:82">
		  <c r="B5" s="208"/>
		  <c r="C5" s="209" t="s"><v>19</v></c>
		  <c r="D5" s="210"/>
		  <c r="E5" s="209" t="s"><v>20</v></c>
		  <!--其他单元和那个忽略-->
		  <c r="T5" s="256" t="s"><v>24</v></c><c r="U5" s="256"/><c r="V5" s="256"/>
		  <c r="W5" s="256" t="s"><v>24</v></c><c r="X5" s="256"/><c r="Y5" s="256"/>
		</row>
 		<row r="7" ht="21.75" customHeight="1" spans="2:82">
		  <c r="T7" s="260" t="s"><v>56</v></c>
		</row>
		</row>
 		<row r="8" s="196" customFormat="1" customHeight="1" spans="2:82">
		  <c r="T8" s="260" t="s"><v>0</v></c>
		</row>
		<row r="9" s="196" customFormat="1" customHeight="1" spans="2:82">
		  <c r="T9" s="260" t="s"><v>21280</v></c>
		</row>
		<!--其他行忽略-->
	 	<row r="28" s="196" customFormat="1" customHeight="1" spans="2:82">
			<c r="T28" s="268"><f t="shared" ref="T28:BI28" si="5">SUM(T9:T27)</f><v>345480</v></c>
		</row>
		<row r="29" s="196" customFormat="1" customHeight="1" spans="2:82">
		  	<c r="W29" s="270"><f>T29+W8-W28</f><v>289720</v></c>
		</row>
	 </sheetData>
	 <mergeCells count="42">
	   <mergeCell ref="T5:V5"/><mergeCell ref="W5:Y5"/><mergeCell ref="Z5:AB5"/><mergeCell ref="AC5:AE5"/>
	 </mergeCells>
	 <dataValidations count="18">
	   <dataValidation type="list" allowBlank="1" showInputMessage="1" showErrorMessage="1" sqref="E2">
		<formula1>&quot;TELS,TMAL&quot;</formula1>
	   </dataValidation>
	 </dataValidations>
	<pageMargins left="0.708661417322835" right="0.708661417322835" top="0.748031496062992" 
		bottom="0.748031496062992" header="0.31496062992126" footer="0.31496062992126"/>
	<pageSetup paperSize="8" fitToHeight="0" orientation="landscape"/><headerFooter/><legacyDrawing r:id="rId2"/>
</worksheet>
       2.2结合上面的xml对其中的几个关键标签说明:


       2.2.1  该xml会以worksheet标签开始结束

       2.2.2  sheetData标签用于包含execl的主体数据

       2.2.2.1 sheetData的子标签row

        说明:该标签用于标记一整行

        属性说明:r(行号)

       2.2.2.1.1 row 子标签 c 

        说明:该标签表示每一个单元格

        属性:r(单元格在EXECL中的编号),t(单元格数据类型),s()

        2.2.2.1.1.1 c标签的子标签 v

        说明:该标签表示每一个单元格的值

        2.2.2.1.1.2 c标签的字标签 f 

        说明:该标签表示单元格为公式型单元格

        属性:t(值权限:shared表示值共享)、ref(有效单元格范围)、

        2.2.3 mergeCells标签

        说明:sheet中所有合并单元格

        属性:count合并单元格数量

        2.2.3.1 mergeCells 的子标签 mergeCell

        说明:每一个合并单元格的设置

        属性:ref(合并的单元格:将T5/U5/V5合并,ref的值为“T5:V5”),有多个合并单元格参考上面的XML

        2.2.4 dataValidations标签

        说明:表示execl中的所有下拉款

        属性:count(下拉框单元格的数量)

        2.2.4.1 dataValidations 标签的子标签dataValidation

        说明:表示每一个下拉框单元格

        属性:type(数据类型)、sqref(单元格位置)

        2.2.4.1.1 dataValidation标签的子标签formula1

        说明:表示下拉框的值

        2.3 对于不同单元格数据类型的处理

        2.3.1 当c标签的属性t为s时表示字符串,此时c标签的字标签v中的值表示的是位置索引(既当v的值是6时,该单元格的值对应的是sharedStrings.xml文件中的第7个si标签的子标签的t的值)

*******************************时间原因,待完善,有好的建议还望提出****************************

java | 阅读 3063 次
文章评论,共0条
游客请输入验证码