Current section
Files
Jump to
Current section
Files
lib/excelion.ex
defmodule Excelion do
# Overview
# The function returns worksheet name list of specifiled .xlsx file.
# If fail get content, return `:error`.
# Parameters
# `path` : .xlsx file path
# `zip` : An optional parameter of the zip processing module is allowed (for testing purposes).
@spec get_worksheet_names(String.t, module) :: {:ok, [String.t]} | {:error, String.t}
def get_worksheet_names(path, zip \\ :zip) do
case XlsxParser.XlsxUtil.get_raw_content(path, "xl/workbook.xml", zip) do
{:error, reason} -> {:error, reason}
{:ok, content} ->
import SweetXml
{:ok, xpath(content, ~x"//workbook/sheets/sheet/@name"l)
|> Enum.map(&List.to_string(&1))}
end
end
# Overview
# The function parse .xlsx file. If fail get content, return `:error.`
# Parameters
# `path` : .xlsx file path
# `sheet_number` : 0-based sheet number
# `start_row` : first use row number (1-based)
# `zip` : An optional parameter of the zip processing module is allowed (for testing purposes).
@spec parse(String.t, integer, integer, module) :: {:ok, [[String.t]]} | {:error, String.t}
def parse(path, sheet_number, start_row, zip \\ :zip) do
case XlsxParser.get_sheet_content(path, sheet_number + 1, zip) do
{:error, reason} -> {:error, reason}
{:ok, ret} ->
filtered = Enum.filter(ret, fn {_colname, row, _value} -> row >= start_row end)
max_col = Enum.max_by(filtered, fn {colname, _row, _value} -> colname end) |> elem(0)
max_row = Enum.max_by(filtered, fn {_colname, row, _value} -> row end) |> elem(1)
map = Enum.into(filtered, %{}, fn x -> {{elem(x, 0), elem(x, 1)}, elem(x, 2)} end)
index_list = for row <- start_row..max_row, col <- 0..alpha_to_index(max_col), do: {col, row}
padded_list = Enum.map(index_list, fn {col_index, row} ->
x = map[{index_to_alpha(col_index), row}]
if x == nil do
""
else
x
end
end)
{:ok, Enum.chunk(padded_list, alpha_to_index(max_col) + 1)}
end
end
# Overview
# The function parse .xlsx file. If fail get content, raise `File.Error` exception.
# Parameters
# `path` : .xlsx file path
# `sheet_number` : 0-based sheet number
# `start_row` : first use row number (1-based)
# `zip` : An optional parameter of the zip processing module is allowed (for testing purposes).
@spec parse!(String.t, integer, integer, module) :: [[String.t]] | no_return
def parse!(path, sheet_number, start_row, zip \\ :zip) do
case parse(path, sheet_number, start_row, zip) do
{:ok, ret} -> ret
{:error, reason} -> raise File.Error, reason: reason, action: "open", path: path
end
end
@spec alphas() :: [String.t]
defp alphas do
["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"]
end
@spec alpha_to_index(String.t) :: integer
defp alpha_to_index(alpha) do
Enum.find_index(alphas, fn x -> x == alpha end)
end
@spec index_to_alpha(integer) :: String.t
defp index_to_alpha(index) do
Enum.at(alphas, index)
end
end