Current section

Files

Jump to
yog_ex lib yog io graphml saxy_handler.ex
Raw

lib/yog/io/graphml/saxy_handler.ex

defmodule Yog.IO.GraphML.SaxyHandler do
@moduledoc false
@behaviour Saxy.Handler
defstruct node_folder: nil,
edge_folder: nil,
graph_type: :directed,
nodes: [],
edges: [],
current_element: nil,
current_attrs: %{},
current_data_key: nil,
current_data_value: ""
@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, state}
end
@impl Saxy.Handler
def handle_event(:start_element, {"graph", attrs}, state) do
graph_type =
case List.keyfind(attrs, "edgedefault", 0) do
{"edgedefault", "undirected"} -> :undirected
_ -> :directed
end
{:ok, %{state | graph_type: graph_type}}
end
def handle_event(:start_element, {"node", attrs}, state) do
id =
case List.keyfind(attrs, "id", 0) do
{"id", id_str} ->
case Integer.parse(id_str) do
{int, _} -> int
:error -> id_str
end
_ ->
nil
end
{:ok, %{state | current_element: :node, current_attrs: %{"_id" => id}}}
end
def handle_event(:start_element, {"edge", attrs}, state) do
source =
case List.keyfind(attrs, "source", 0) do
{"source", src} ->
case Integer.parse(src) do
{int, _} -> int
:error -> src
end
_ ->
nil
end
target =
case List.keyfind(attrs, "target", 0) do
{"target", tgt} ->
case Integer.parse(tgt) do
{int, _} -> int
:error -> tgt
end
_ ->
nil
end
{:ok,
%{
state
| current_element: :edge,
current_attrs: %{"_source" => source, "_target" => target}
}}
end
def handle_event(:start_element, {"data", attrs}, state) do
key =
case List.keyfind(attrs, "key", 0) do
{"key", k} -> k
_ -> nil
end
{:ok, %{state | current_data_key: key, current_data_value: ""}}
end
def handle_event(:start_element, _other, state) do
{:ok, state}
end
@impl Saxy.Handler
def handle_event(:end_element, "node", state) do
id = Map.get(state.current_attrs, "_id")
attrs = Map.delete(state.current_attrs, "_id")
data = state.node_folder.(attrs)
nodes = [{id, data} | state.nodes]
{:ok, %{state | nodes: nodes, current_element: nil, current_attrs: %{}}}
end
def handle_event(:end_element, "edge", state) do
source = Map.get(state.current_attrs, "_source")
target = Map.get(state.current_attrs, "_target")
attrs = state.current_attrs |> Map.delete("_source") |> Map.delete("_target")
weight = state.edge_folder.(attrs)
edges = [{source, target, weight} | state.edges]
{:ok, %{state | edges: edges, current_element: nil, current_attrs: %{}}}
end
def handle_event(:end_element, "data", state) do
key = state.current_data_key
value = state.current_data_value
new_attrs =
if key do
Map.put(state.current_attrs, key, value)
else
state.current_attrs
end
{:ok, %{state | current_attrs: new_attrs, current_data_key: nil, current_data_value: ""}}
end
def handle_event(:end_element, _other, state) do
{:ok, state}
end
@impl Saxy.Handler
def handle_event(:characters, chars, %{current_data_key: key} = state) when key != nil do
{:ok, %{state | current_data_value: state.current_data_value <> chars}}
end
def handle_event(:characters, _chars, state) do
{:ok, state}
end
end