Current section

Files

Jump to
xlsx_reader lib xlsx_reader parsers shared_strings_parser.ex
Raw

lib/xlsx_reader/parsers/shared_strings_parser.ex

defmodule XlsxReader.Parsers.SharedStringsParser do
@moduledoc false
# Parses SpreadsheetML shared strings definitions.
#
# The parser builds a list of shared strings.
#
# Worksheets only contain numbers: the value of cells containing text is
# numeric index to the array of shared strings.
@behaviour Saxy.Handler
alias XlsxReader.Parsers.Utils
defmodule State do
@moduledoc false
defstruct current_string: nil,
strings: [],
expect_chars: false,
preserve_space: false
end
def parse(xml) do
Saxy.parse_string(xml, __MODULE__, %State{})
end
@impl Saxy.Handler
def handle_event(:start_document, _prolog, state) do
{:ok, state}
end
@impl Saxy.Handler
def handle_event(:end_document, _data, state) do
{:ok, Enum.reverse(state.strings)}
end
@impl Saxy.Handler
def handle_event(:start_element, {"si", _attributes}, state) do
{:ok, %{state | current_string: ""}}
end
@impl Saxy.Handler
def handle_event(:start_element, {"t", attributes}, state) do
{:ok,
%{
state
| expect_chars: true,
preserve_space: Utils.get_attribute(attributes, "xml:space") == "preserve"
}}
end
@impl Saxy.Handler
def handle_event(:start_element, _element, state) do
{:ok, state}
end
@impl Saxy.Handler
def handle_event(:end_element, "t", state) do
{:ok, %{state | expect_chars: false, preserve_space: false}}
end
@impl Saxy.Handler
def handle_event(:end_element, "si", state) do
{:ok, %{state | current_string: nil, strings: [state.current_string | state.strings]}}
end
@impl Saxy.Handler
def handle_event(:end_element, _name, state) do
{:ok, state}
end
@impl Saxy.Handler
def handle_event(:characters, chars, %{expect_chars: true} = state) do
{:ok, %{state | current_string: state.current_string <> preserve_space(state, chars)}}
end
@impl Saxy.Handler
def handle_event(:characters, _chars, %{expect_chars: false} = state) do
{:ok, state}
end
##
defp preserve_space(%{preserve_space: true}, string), do: string
defp preserve_space(%{preserve_space: false}, string), do: String.trim(string)
end