require Logger defmodule XlsxParser do @moduledoc false alias XlsxParser.XlsxUtil alias XlsxParser.XmlParser @doc """ Given a path do an .xlsx and the sheet number (1 based index), this function returns a list of values in the sheet. The values are returned as a list of {column, row, value} tuples. An optional parameter of the zip processing module is allowed (for testing purposes). """ @spec get_sheet_content(String.t(), pos_integer(), module()) :: {:ok, [XmlParser.col_row_val()]} | {:error, String.t()} def get_sheet_content(path, sheet_number, zip \\ :zip) do with {:ok, shared_strings} <- XlsxUtil.get_shared_strings(path, zip), {:ok, content} <- XlsxUtil.get_raw_content(path, "xl/worksheets/sheet#{sheet_number}.xml", zip) do ret = XmlParser.parse_xml_content(content, shared_strings) Logger.debug("Parsed xml for #{Path.rootname(path)}") {:ok, ret} else {:error, reason} -> {:error, reason} end end @doc """ Given a path to an .xlsx, a sheet number, and a path to a csv, this function writes the content of the specified sheet to the specified csv path. """ @spec write_sheet_content_to_csv(String.t(), pos_integer(), String.t(), module(), module()) :: {:ok, String.t()} | {:error, String.t()} def write_sheet_content_to_csv(xlsx_path, sheet_number, csv_path, zip \\ :zip, file \\ File) do case get_sheet_content(xlsx_path, sheet_number, zip) do {:error, reason} -> {:error, reason} {:ok, content} -> csv = XlsxUtil.col_row_vals_to_csv(content) case file.write(csv_path, csv) do {:error, reason} -> {:error, "Error writing csv file: #{inspect(reason)}"} :ok -> {:ok, csv} end end end @doc """ Given a path to an .xlsx, this function returns an array of worksheet names """ @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, content |> xpath(~x"//workbook/sheets/sheet/@name"l) |> Enum.map(&List.to_string(&1))} end end end