aboutsummaryrefslogtreecommitdiff
path: root/src/odf/odfLoader.ml
diff options
context:
space:
mode:
Diffstat (limited to 'src/odf/odfLoader.ml')
-rwxr-xr-xsrc/odf/odfLoader.ml130
1 files changed, 130 insertions, 0 deletions
diff --git a/src/odf/odfLoader.ml b/src/odf/odfLoader.ml
new file mode 100755
index 0000000..9420fdd
--- /dev/null
+++ b/src/odf/odfLoader.ml
@@ -0,0 +1,130 @@
+module NS = Odf_ns
+
+type tree =
+ | Data of string
+ | Cell of {repetition: int; cell_width: int; expression: Expression.t}
+ | Unit
+
+let memoization cache key f = begin
+ try
+ Hashtbl.find cache key
+ with Not_found ->
+ let value = f key in
+ Hashtbl.add cache key value;
+ value
+end
+
+let load_content cache content = begin function
+ | "float" -> Expression.Basic (
+ ScTypes.number (
+ DataType.Num.of_float (float_of_string content)
+ ))
+ | "date" -> Expression.Basic (
+ ScTypes.date (
+ DataType.Num.of_float (float_of_string content)
+ ))
+ | _ ->
+ (* If the same text is present many times, use the same string instead of creating a new one *)
+ memoization cache content (fun content ->
+ Expression.Basic (
+ ScTypes.string (
+ UTF8.from_utf8string content)))
+end
+
+let load_formula formula =
+ let lineBuffer = Lexing.from_string formula in
+ try
+ Expression.Formula (
+ Expression.Expression (
+ Odf_ExpressionParser.value Odf_ExpressionLexer.read lineBuffer))
+ with e ->
+ print_endline formula;
+ raise e
+
+
+let build_cell cache (attributes:Xmlm.attribute list) (childs:tree list) = begin
+
+ (* Check if the content is repeated *)
+ let repetition =
+ try int_of_string @@ List.assoc NS.number_columns_repeat_attr attributes
+ with Not_found -> 1
+
+ (* cell width *)
+ and cell_width =
+ try int_of_string @@ List.assoc NS.number_columns_spanned_attr attributes
+ with Not_found -> 1
+
+ and expression =
+ try
+ load_formula @@ List.assoc NS.formula_attr attributes
+ with Not_found -> (
+ let vtype =
+ try List.assoc NS.ovalue_type_attr attributes
+ with Not_found -> "" in
+
+ try
+ load_content cache (List.assoc NS.value_attr attributes) vtype
+ with Not_found -> (
+ (* This is not a formula, neither a value ? *)
+ try
+ let value = Tools.List.find_map (function | Data x -> Some x | _ -> None) childs in
+ load_content cache value vtype
+ with Not_found -> Expression.Undefined
+ )
+ ) in
+
+ Cell {repetition; cell_width; expression}
+
+end
+
+let build_p (attributes:Xmlm.attribute list) = begin function
+ | Data x::_ -> Data x
+ | _ -> Data ""
+end
+
+
+let build_row (sheet:Sheet.Raw.t ref) (row_num:int ref) (attributes:Xmlm.attribute list) (childs:tree list) = begin
+
+ let repetition =
+ try int_of_string @@ List.assoc (NS.table, "number-rows-repeated") attributes
+ with Not_found -> 1 in
+
+ for i = 1 to repetition do
+ let cell_num = ref 1 in
+ List.iter (function
+ | Cell cell ->
+ for i = 1 to cell.repetition do
+ sheet := snd @@ Sheet.Raw.add (!cell_num, !row_num) cell.expression !sheet;
+ cell_num := !cell_num + cell.cell_width
+ done;
+ | _ -> ()
+ ) childs;
+ incr row_num
+ done;
+ Unit
+end
+
+let data str = Data str
+
+let load source = begin
+
+ (* Mutable datas *)
+ let sheet = ref Sheet.Raw.empty in
+ let cache = Hashtbl.create 10 in
+
+ let table = Base.String_dict.of_alist_exn [
+ ((NS.text ^ "p"), build_p);
+ ((NS.table ^ "table-cell"), build_cell cache);
+ ((NS.table ^ "table-row"), build_row sheet (ref 1))
+ ] in
+
+ let el (((ns, name), attributes):Xmlm.tag) childs = begin
+ match Base.String_dict.find table (ns ^ name) with
+ | Some f -> f attributes childs
+ | None -> Unit
+ end in
+
+ match Xmlm.input_doc_tree ~el ~data source with
+ | _, Unit -> !sheet
+ | _ -> raise Not_found
+end