我正在使用xmerl_sax_parser
并且我使用的XML结构是深度嵌套的,所以我最终得到了很多回调函数,它们只适用于作用域堆栈,如下所示:
defmodule Parser do
defstruct acc: [], scope: []
def parse(xml_string) do
event_state = %Parser{}
event_fun = &callback/3
{:ok, state, _} = :xmerl_sax_parser.stream(xml_string, event_fun: event_fun, event_state: event_state)
state
end
defp callback({:startElement, _, 'car', _, _}, _, state) do
Map.update!(state, :scope, &([:car | &1]))
end
defp callback({:endElement, _, 'car', _}, _, %{scope: [:car]} = state) do
%{state | scope: []}
end
defp callback({:startElement, _, 'detail', _, _}, _, %{scope: [:car] = scope} = state) do
%{state | scope: [:detail | scope]}
end
defp callback({:endElement, _, 'detail', _}, _, %{scope: [:detail | [:car] = scope_tail]} = state) do
%{state | scope: scope_tail}
end
defp callback({:startElement, _, 'engine', _, _}, _, %{scope: [:detail, :car] = scope} = state) do
%{state | scope: [:engine | scope]}
end
defp callback({:endElement, _, 'engine', _}, _, %{scope: [:engine | [:detail, :car] = scope_tail]} = state) do
%{state | scope: scope_tail}
end
defp callback({:characters, engine}, _, %{scope: [:engine, :detail, :car], acc: acc} = state) do
%{state | acc: [engine | acc]}
end
end
因此,为了获得car -> detail -> engine
范围内的值,我必须编写7个函数,并且我需要一遍又一遍地重复我需要获得的每个值。因此,显而易见的决定是提出一些宏观魔法以避免所有这些,它可能看起来像这样:
scope [:car, :detail] do
text :engine, fn(state, value) -> #some logic end
end
但是当调用text
时,我找不到一种方法来访问定义它的范围,所以我不知道如何去做。
所以问题是,实现这种适用于范围的DSL的方法是什么?或者有更好的方法来解决这个问题吗?
谢谢