├── rebar.config ├── README.md ├── .gitignore ├── src ├── excel_reader.app.src ├── excel_row.erl ├── excel_sheet.erl ├── excel_string_table.erl ├── excel_cell.erl └── excel_reader.erl ├── include └── excel_reader.hrl └── LICENSE /rebar.config: -------------------------------------------------------------------------------- 1 | {erl_opts, [debug_info]}. 2 | {deps, []}. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | excel_reader 2 | ===== 3 | 4 | An OTP library 5 | 6 | Build 7 | ----- 8 | 9 | $ rebar3 compile 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .rebar3 2 | _* 3 | .eunit 4 | *.o 5 | *.beam 6 | *.plt 7 | *.swp 8 | *.swo 9 | .erlang.cookie 10 | ebin 11 | log 12 | erl_crash.dump 13 | .rebar 14 | logs 15 | _build 16 | -------------------------------------------------------------------------------- /src/excel_reader.app.src: -------------------------------------------------------------------------------- 1 | {application, excel_reader, 2 | [{description, "An OTP library"}, 3 | {vsn, "0.1.0"}, 4 | {registered, []}, 5 | {applications, 6 | [kernel, 7 | stdlib 8 | ]}, 9 | {env,[]}, 10 | {modules, []}, 11 | 12 | {maintainers, []}, 13 | {licenses, []}, 14 | {links, []} 15 | ]}. 16 | -------------------------------------------------------------------------------- /include/excel_reader.hrl: -------------------------------------------------------------------------------- 1 | %%%------------------------------------------------------------------- 2 | %%% @author jiangxiaowei@lilith.sh 3 | %%% @copyright (C) 2017, Lilith Games 4 | %%% @doc 5 | %%% 6 | %%% @end 7 | %%% Created : 09. 三月 2017 16:13 8 | %%%------------------------------------------------------------------- 9 | -author("jiangxiaowei@lilith.sh"). 10 | 11 | -include_lib("xmerl/include/xmerl.hrl"). 12 | 13 | %% Excel对象 14 | -record(excel, { 15 | sheets = [] 16 | }). 17 | 18 | %% 页 19 | -record(excel_sheet, { 20 | id = 0, 21 | name, 22 | rows 23 | }). 24 | 25 | %% 行 26 | -record(excel_row, {r, cells = []}). 27 | 28 | %% 单元格 29 | -record(excel_cell, {c, v}). 30 | -------------------------------------------------------------------------------- /src/excel_row.erl: -------------------------------------------------------------------------------- 1 | %%%------------------------------------------------------------------- 2 | %%% @author jiangxiaowei@lilith.sh 3 | %%% @copyright (C) 2017, Lilith Games 4 | %%% @doc 5 | %%% 6 | %%% @end 7 | %%% Created : 09. 三月 2017 16:27 8 | %%%------------------------------------------------------------------- 9 | -module(excel_row). 10 | -author("jiangxiaowei@lilith.sh"). 11 | 12 | -include("excel_reader.hrl"). 13 | 14 | %% API 15 | -export([new/2]). 16 | 17 | new(#xmlElement{attributes = Attrs, content = CellsXML}, StringTable) -> 18 | {value, #xmlAttribute{value = R}} = lists:keysearch(r, #xmlAttribute.name, Attrs), 19 | Cells = [excel_cell:new(CellXML, StringTable)|| CellXML <- CellsXML], 20 | #excel_row{r = list_to_integer(R), cells = Cells}. 21 | -------------------------------------------------------------------------------- /src/excel_sheet.erl: -------------------------------------------------------------------------------- 1 | %%%------------------------------------------------------------------- 2 | %%% @author jiangxiaowei@lilith.sh 3 | %%% @copyright (C) 2017, Lilith Games 4 | %%% @doc 5 | %%% 6 | %%% @end 7 | %%% Created : 09. 三月 2017 16:17 8 | %%%------------------------------------------------------------------- 9 | -module(excel_sheet). 10 | -author("jiangxiaowei@lilith.sh"). 11 | 12 | -include("excel_reader.hrl"). 13 | 14 | %% API 15 | -export([new/1]). 16 | 17 | new(#xmlElement{attributes = Attrs}) -> 18 | {value, #xmlAttribute{value = SheetName}} = lists:keysearch(name, #xmlAttribute.name, Attrs), 19 | {value, #xmlAttribute{value = SheetId}} = lists:keysearch(sheetId, #xmlAttribute.name, Attrs), 20 | #excel_sheet{id = list_to_integer(SheetId), name = SheetName}. 21 | 22 | -------------------------------------------------------------------------------- /src/excel_string_table.erl: -------------------------------------------------------------------------------- 1 | %%%------------------------------------------------------------------- 2 | %%% @author jiangxiaowei@lilith.sh 3 | %%% @copyright (C) 2017, Lilith Games 4 | %%% @doc 5 | %%% 6 | %%% @end 7 | %%% Created : 09. 三月 2017 16:18 8 | %%%------------------------------------------------------------------- 9 | -module(excel_string_table). 10 | -author("jiangxiaowei@lilith.sh"). 11 | 12 | -include("excel_reader.hrl"). 13 | 14 | %% API 15 | -export([new/1]). 16 | 17 | new(SharedStringXML) -> 18 | new(SharedStringXML, dict:new(), 0). 19 | 20 | new([], StringTable, _Index) -> {ok, StringTable}; 21 | new([#xmlElement{content = [#xmlText{value = Value}]}|T], StringTable, Index) -> 22 | NewStringTable = dict:store(Index, Value, StringTable), 23 | new(T, NewStringTable, Index + 1). 24 | -------------------------------------------------------------------------------- /src/excel_cell.erl: -------------------------------------------------------------------------------- 1 | %%%------------------------------------------------------------------- 2 | %%% @author jiangxiaowei@lilith.sh 3 | %%% @copyright (C) 2017, Lilith Games 4 | %%% @doc 5 | %%% 6 | %%% @end 7 | %%% Created : 09. 三月 2017 16:47 8 | %%%------------------------------------------------------------------- 9 | -module(excel_cell). 10 | -author("jiangxiaowei@lilith.sh"). 11 | 12 | -include("excel_reader.hrl"). 13 | 14 | %% API 15 | -export([new/2]). 16 | 17 | new(#xmlElement{attributes = Attrs, content = [#xmlElement{content = [#xmlText{value = V}]}]}, StringTable) -> 18 | {value, #xmlAttribute{value = C}} = lists:keysearch(r, #xmlAttribute.name, Attrs), 19 | case lists:keysearch(t, #xmlAttribute.name, Attrs) of 20 | false -> 21 | #excel_cell{c = C, v = V}; 22 | {value, #xmlAttribute{value = _}} -> 23 | #excel_cell{c = C, v = dict:fetch(list_to_integer(V), StringTable)} 24 | end. 25 | 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017, Anonymous . 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | 15 | * The names of its contributors may not be used to endorse or promote 16 | products derived from this software without specific prior written 17 | permission. 18 | 19 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /src/excel_reader.erl: -------------------------------------------------------------------------------- 1 | -module(excel_reader). 2 | 3 | %%%------------------------------------------------------------------- 4 | %%% @author jiangxiaowei@lilith.sh 5 | %%% @copyright (C) 2017, Lilith Games 6 | %%% @doc 7 | %%% 读取Excel文件 8 | %%% @end 9 | %%% Created : 09. 三月 2017 16:13 10 | %%%------------------------------------------------------------------- 11 | -author("jiangxiaowei@lilith.sh"). 12 | 13 | -include("excel_reader.hrl"). 14 | 15 | %% API exports 16 | -export([open/1]). 17 | 18 | %%==================================================================== 19 | %% API functions 20 | %%==================================================================== 21 | open(File) when is_list(File) -> 22 | case check_extension(File) of 23 | true -> 24 | do_open(File); 25 | false -> 26 | {error, bad_excel_file} 27 | end; 28 | open(_) -> 29 | {error, badarg}. 30 | 31 | %%==================================================================== 32 | %% Internal functions 33 | %%==================================================================== 34 | check_extension(File) -> 35 | FileExtension = filename:extension(File), 36 | FileExtension == ".xls" orelse FileExtension == ".xlsx". 37 | 38 | do_open(File) -> 39 | {ok, ExcelData} = zip:unzip(File, [memory]), 40 | 41 | % prase string table info 42 | SharedStringsBinary = proplists:get_value("xl/sharedStrings.xml", ExcelData), 43 | {SharedStringsDoc, _} = xmerl_scan:string(erlang:binary_to_list(SharedStringsBinary)), 44 | SharedStringXML = xmerl_xpath:string("/sst/si/t", SharedStringsDoc), 45 | {ok, StringTable} = excel_string_table:new(SharedStringXML), 46 | 47 | % parse sheets info 48 | WorkbookBinary = proplists:get_value("xl/workbook.xml", ExcelData), 49 | {WorkbookDoc, _} = xmerl_scan:string(erlang:binary_to_list(WorkbookBinary)), 50 | [#xmlElement{content = SheetsXML}] = xmerl_xpath:string("/workbook/sheets", WorkbookDoc), 51 | SheetInfos = [excel_sheet:new(SheetXML)||SheetXML <- SheetsXML], 52 | 53 | % load sheets data 54 | {ok, #excel{sheets = lists:foldr( 55 | fun(SheetInfo = #excel_sheet{id = SheetId}, AccIn) -> 56 | SheetDataFile = lists:concat(["xl/worksheets/sheet", erlang:integer_to_list(SheetId), ".xml"]), 57 | SheetDataBinary = proplists:get_value(SheetDataFile, ExcelData), 58 | {SheetDataDoc, _} = xmerl_scan:string(erlang:binary_to_list(SheetDataBinary)), 59 | [#xmlElement{content = RowsXML}] = xmerl_xpath:string("/worksheet/sheetData", SheetDataDoc), 60 | Rows = [excel_row:new(RowXML, StringTable) || RowXML<-RowsXML], 61 | [SheetInfo#excel_sheet{rows = Rows}|AccIn] 62 | end, [], SheetInfos)}}. 63 | 64 | --------------------------------------------------------------------------------