summaryrefslogtreecommitdiff
path: root/graphmlReader.ml
diff options
context:
space:
mode:
authorJohannes Schauer <josch@debian.org>2015-07-29 10:10:38 +0200
committerJohannes Schauer <josch@debian.org>2015-07-29 10:10:38 +0200
commitb7afae3851eec233d2bc8ab816a77d0e00c6e587 (patch)
tree006351fe759a37358bbef704690e1695e8d6855e /graphmlReader.ml
botch (0.14-1) unstable; urgency=medium
* New upstream release * refresh patch send-keepalive * botch binary: add dependency on python3-pydot, zutils and suggest libgraph-easy-perl, jq * update debian/tests/* with --drop-b-d-indep argument and correct locale environment variable export * make debian/tests/* more readable by splitting long lines * update debian/tests/* with workaround for random segmentation faults see http://bugs.python.org/issue24605 # imported from the archive
Diffstat (limited to 'graphmlReader.ml')
-rw-r--r--graphmlReader.ml205
1 files changed, 205 insertions, 0 deletions
diff --git a/graphmlReader.ml b/graphmlReader.ml
new file mode 100644
index 0000000..d053ddf
--- /dev/null
+++ b/graphmlReader.ml
@@ -0,0 +1,205 @@
+(**************************************************************************)
+(* *)
+(* Copyright (C) 2012 Johannes 'josch' Schauer <j.schauer@email.de> *)
+(* *)
+(* This library is free software: you can redistribute it and/or modify *)
+(* it under the terms of the GNU Lesser General Public License as *)
+(* published by the Free Software Foundation, either version 3 of the *)
+(* License, or (at your option) any later version. A special linking *)
+(* exception to the GNU Lesser General Public License applies to this *)
+(* library, see the COPYING file for more information. *)
+(**************************************************************************)
+
+open ExtLib
+
+type value =
+ | Int of int
+ | Float of float
+ | String of string
+ | Bool of bool
+ | List of value_list
+and value_list = (string * value) list
+
+type tree = E of string * (string * string) list * tree list | D of string
+
+module Parse
+ (B : Graph.Builder.S)
+ (L : sig val node : value_list -> B.G.V.label
+ val edge : value_list -> B.G.E.label end) =
+struct
+ let create_graph ?(nodesort=None) ?(edgesort=None) l =
+ let nodes = Hashtbl.create 1000 in
+ let handle_node g l =
+ let n = B.G.V.create (L.node l) in
+ begin
+ try
+ let id = List.assoc "id" l in Hashtbl.add nodes id n
+ with Not_found ->
+ ()
+ end;
+ B.add_vertex g n
+ in
+ let handle_edge g l =
+ try
+ let source = List.assoc "source" l in
+ let target = List.assoc "target" l in
+ let nsource = Hashtbl.find nodes source in
+ let ntarget = Hashtbl.find nodes target in
+ let e = B.G.E.create nsource (L.edge l) ntarget in
+ B.add_edge_e g e
+ with Not_found ->
+ g
+ in
+ let g = B.empty () in
+ (* 1st pass: create the nodes *)
+ let g = match nodesort with
+ | None ->
+ List.fold_left
+ (fun g v -> match v with
+ | "node", List l -> handle_node g l
+ | _ -> g
+ ) g l
+ | Some sortfunc ->
+ let nodes = List.sort ~cmp:sortfunc
+ (List.filter_map (function | "node", List l -> Some l | _ -> None) l)
+ in
+ List.fold_left handle_node g nodes
+ in
+ (* 2nd pass: add the edges *)
+ match edgesort with
+ | None ->
+ List.fold_left
+ (fun g v -> match v with
+ | "edge", List l -> handle_edge g l
+ | _ -> g
+ ) g l
+ | Some sortfunc ->
+ let edges = List.sort ~cmp:sortfunc
+ (List.filter_map (function | "edge", List l -> Some l | _ -> None) l)
+ in
+ List.fold_left handle_edge g edges
+ let parse ?(nodesort=None) ?(edgesort=None) ic =
+ let i = Xmlm.make_input (`Channel ic) in
+ let el ((_,tag),attrs) children = E (tag, List.map (fun ((_,n),v) -> n,v) attrs, children) in
+ let data d = D d in
+ let _,doc = try Xmlm.input_doc_tree ~el ~data i
+ with
+ | Xmlm.Error ((line,col),error) ->
+ invalid_arg (Printf.sprintf "Line %d, Column %d: %s"
+ line col (Xmlm.error_message error))
+ in
+ let assoc k l = try List.assoc k l with Not_found -> invalid_arg (Printf.sprintf "Cannot find attribute %s" k) in
+ (* expect <graphml> *)
+ let graphml = match doc with
+ | E (el,_,tl) ->
+ if el = "graphml" then tl
+ else invalid_arg (Printf.sprintf "Expected <graphml>, got %s" el)
+ | D _ -> invalid_arg "Expected <graphml>, got data"
+ in
+ (* find all <graph> and <key> *)
+ let keys, graphs = List.fold_left (fun (k,g) t ->
+ match t with
+ | E (el,a,st) ->
+ begin match el with
+ | "key" -> (a,st)::k,g
+ | "graph" -> k,(a,st)::g
+ | "desc" | "data " -> k,g (* silently ignore <desc> and <data> *)
+ | _ -> invalid_arg (Printf.sprintf "Unexpected child of <graphml>: %s" el)
+ end
+ | D _ -> k,g (* silently ignore data *)
+ ) ([],[]) graphml in
+ (* extract node and edge keys for attribute types *)
+ let nkeys, ekeys =
+ List.fold_left (fun (nk,ek) (a,_) ->
+ let f = assoc "for" a in
+ let i = assoc "id" a in
+ let t = assoc "attr.type" a in
+ let n = assoc "attr.name" a in
+ match f with
+ | "node" -> (i,(t,n))::nk,ek
+ | "edge" -> nk,(i,(t,n))::ek
+ | _ -> invalid_arg (Printf.sprintf "Only support for \"node\" and \"edge\" keys, not %s" f)
+ ) ([],[]) keys
+ in
+ (* error if more than one *)
+ let graphattr,graphtree = match graphs with
+ | [] -> invalid_arg "No <graph> elements"
+ | [l] -> l
+ | _ -> invalid_arg "No support for more than one <graph>"
+ in
+ (* check whether input graph has the same directed-ness as the graph builder *)
+ let is_directed = assoc "edgedefault" graphattr = "directed" in
+ if B.G.is_directed then
+ if is_directed then () else invalid_arg "cannot read undirected graphml into directed graph builder"
+ else
+ if is_directed then invalid_arg "cannot read directed graphml into undirected graph builder" else ();
+ (* extract nodes and edges *)
+ let l = List.filter_map (function
+ | E (el,a,t) -> begin
+ match el with
+ | "node" -> begin
+ let attr = List.filter_map (function
+ | E (el,a,t) ->
+ begin match el with
+ | "data" -> begin
+ let k = assoc "key" a in
+ let d = match t with [D d] -> d | _ -> invalid_arg "Expected data" in
+ try begin match List.assoc k nkeys with
+ | ("string",n) -> Some (n, String d)
+ | ("int",n) -> Some(n, Int (int_of_string d))
+ | ("long",n) -> Some(n, Int (int_of_string d))
+ | ("float",n) -> Some(n, Float (float_of_string d))
+ | ("bool",n) -> Some(n, Bool (bool_of_string d))
+ | (t,n) -> invalid_arg (Printf.sprintf "Unsupported node type %s for attribute %s" t n)
+ end with Not_found -> invalid_arg (Printf.sprintf "Cannot find node type %s" k)
+ end
+ | "desc" -> None (* silently ignore <desc> *)
+ | "port" -> invalid_arg "No support for <port>"
+ | "graph" -> invalid_arg "No support for nested graphs"
+ | "locator" -> invalid_arg "No support for <locator>"
+ | _ -> invalid_arg (Printf.sprintf "Unexpected child of <node>: %s" el)
+ end
+ | D _ -> None (* silently ignore data *)
+ ) t in
+ let i = assoc "id" a in
+ let l = ("id",String i)::attr in
+ Some ("node", List l)
+ end
+ | "edge" -> begin
+ let attr = List.filter_map (function
+ | E (el,a,t) ->
+ begin match el with
+ | "data" -> begin
+ let k = assoc "key" a in
+ let d = match t with [D d] -> d | _ -> invalid_arg "Expected data" in
+ try begin match List.assoc k ekeys with
+ | ("string",n) -> Some (n, String d)
+ | ("int",n) -> Some(n, Int (int_of_string d))
+ | ("long",n) -> Some(n, Int (int_of_string d))
+ | ("float",n) -> Some(n, Float (float_of_string d))
+ | ("bool",n) -> Some(n, Bool (bool_of_string d))
+ | (t,n) -> invalid_arg (Printf.sprintf "Unsupported edge type %s for attribute %s" t n)
+ end with Not_found -> invalid_arg (Printf.sprintf "Cannot find edge type %s" k)
+ end
+ | "desc" -> None (* silently ignore desc *)
+ | "graph" -> invalid_arg "No support for nested graphs"
+ | _ -> invalid_arg (Printf.sprintf "Unexpected child of <edge>: %s" el)
+ end
+ | D _ -> None (* silently ignore data *)
+ ) t in
+ let source = assoc "source" a in
+ let target = assoc "target" a in
+ let l = ("source",String source)::("target",String target)::attr in
+ let l = if List.mem_assoc "id" a then ("id",String (assoc "id" a))::l else l in
+ Some ("edge", List l)
+ end
+ | "desc" | "data" -> None (* silently ignore <desc> and <data> *)
+ | "hyperedge" -> invalid_arg "No support for <hyperedge>"
+ | "locator" -> invalid_arg "No support for <locator>"
+ | _ -> invalid_arg (Printf.sprintf "Unexpected child of <graph>: %s" el)
+ end
+ | D _ -> None (* silently ignore data *)
+ ) graphtree in
+ let g = create_graph ~nodesort ~edgesort l in
+ g
+end