package rdf

  1. Overview
  2. Docs
Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source

Source file term.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
(*********************************************************************************)
(*                OCaml-RDF                                                      *)
(*                                                                               *)
(*    Copyright (C) 2012-2024 Institut National de Recherche en Informatique     *)
(*    et en Automatique. All rights reserved.                                    *)
(*                                                                               *)
(*    This program is free software; you can redistribute it and/or modify       *)
(*    it under the terms of the GNU Lesser General Public License version        *)
(*    3 as published by the Free Software Foundation.                            *)
(*                                                                               *)
(*    This program is distributed in the hope that it will be useful,            *)
(*    but WITHOUT ANY WARRANTY; without even the implied warranty of             *)
(*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the              *)
(*    GNU General Public License for more details.                               *)
(*                                                                               *)
(*    You should have received a copy of the GNU General Public License          *)
(*    along with this program; if not, write to the Free Software                *)
(*    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA                   *)
(*    02111-1307  USA                                                            *)
(*                                                                               *)
(*    Contact: Maxence.Guesdon@inria.fr                                          *)
(*                                                                               *)
(*********************************************************************************)

(** *)

let () = Random.self_init();;

type literal = {
    lit_value : string ;
    lit_language : string option ;
    lit_type : Iri.t option ;
  }
type blank_id = string

type term =
  | Iri of Iri.t
  | Literal of literal
  | Blank
  | Blank_ of blank_id

exception Invalid_date of string

let () = Printexc.register_printer
  (function
   | Invalid_date str -> Some (Printf.sprintf "Invalid date %s" str)
   | _ -> None
  )

type triple = term * Iri.t * term

type datetime =
  { stamp : Ptime.t ;
    tz: Ptime.tz_offset_s option ;
  }

let datetime_of_string str =
  match Ptime.of_rfc3339 str with
     Ok (stamp, tz, _) -> { stamp ; tz }
   | Error (`RFC3339 ((p1,p2), e)) ->
      let b = Buffer.create 256 in
      let fmt = Format.formatter_of_buffer b in
      Format.fprintf fmt "%s\n" str ;
      if p2 > p1 then
        Format.fprintf fmt "Characters %d-%d: " p1 p2
      else
        Format.fprintf fmt "Character %d: " p1;
      Ptime.pp_rfc3339_error fmt e;
      Format.pp_print_flush fmt () ;
      let err = Buffer.contents b in
      raise (Invalid_date err)

let string_of_datetime t = Ptime.to_rfc3339 ?tz_offset_s: t.tz t.stamp

let string_of_blank_id id = id;;
let blank_id_of_string str = str;;

let blank str = Blank_ (blank_id_of_string str)
let blank_ id = Blank_ id

let term_of_iri_string s = Iri (Iri.of_string s);;
let mk_literal ?typ ?lang v =
  { lit_value = v ; lit_language = lang ; lit_type = typ ; }
;;
let term_of_literal_string ?typ ?lang v =
  Literal (mk_literal ?typ ?lang v)
;;

let now () =
  match Ptime.of_float_s (Unix.gettimeofday()) with
    None -> assert false
  | Some stamp -> { stamp ; tz = None }
let mk_literal_datetime ?(d=now()) () =
  let v = string_of_datetime d in
  mk_literal ~typ: (Iri.of_string "http://www.w3.org/2001/XMLSchema#dateTime") v
;;

let term_of_datetime ?d () =
  Literal (mk_literal_datetime ?d ())
;;

let datetime_of_literal lit = datetime_of_string lit.lit_value

let mk_literal_bool b =
  let v = if b then "1" else "0" in
  mk_literal ~typ: Rdf_.xsd_boolean v
;;

let mk_literal_int ?(typ=Rdf_.xsd_integer) n =
  mk_literal ~typ (string_of_int n)
;;

let mk_literal_double f =
  mk_literal ~typ: Rdf_.xsd_double (string_of_float f)
;;

let term_of_int ?typ n = Literal (mk_literal_int ?typ n)
let term_of_double f = Literal (mk_literal_double f)
let term_of_bool b = Literal (mk_literal_bool b);;

let bool_of_literal lit =
  match lit.lit_value with
    "1" | "true" -> true
  | _ -> false
;;

(** We must not escape \u sequences used to encode UTF-8 characters.
  Since String.escaped escapes all '\\', then unescape "\\u" back to "\u".
*)
let unescape_backslash_u s =
  let len = String.length s in
  let b = Buffer.create len in
  let rec iter p =
    if p < len - 3 then
      match s.[p], s.[p+1], s.[p+2] with
        '\\', '\\', 'u' -> Buffer.add_string b "\\u" ; iter (p+3)
      | '\\', '\\', 'U' -> Buffer.add_string b "\\U" ; iter (p+3)
      | c, _, _ -> Buffer.add_char b c; iter (p+1)
    else if p < len then
        (
         Buffer.add_char b s.[p] ;
         iter (p+1)
        )
  in
  iter 0;
  Buffer.contents b
;;

let quote_str s = "\""^(Utf8.utf8_escape s)^"\"";;

let string_of_literal lit =
  (quote_str lit.lit_value) ^
    (match lit.lit_language with
       None -> ""
     | Some l -> "@" ^ l
    ) ^
    (match lit.lit_type with
       None -> ""
     | Some t -> "^^<" ^ (Iri.to_string t) ^ ">"
    )

let string_of_term = function
| Iri iri -> "<" ^ (Iri.to_string iri) ^ ">"
| Literal lit -> string_of_literal lit
| Blank -> "_"
| Blank_ id ->  "_:" ^ (string_of_blank_id id)
;;

let pp_term ppf t = Format.fprintf ppf "%s" (string_of_term t)

let int64_hash str =
  let digest = Digest.string str in
  (* use the same method as in librdf: use the 8 first bytes to
     get a 64 bits integer independant from the little/big endianness *)
  let hash = ref Int64.zero in
  for i = 0 to 7 do
    hash := Int64.add !hash (Int64.shift_left (Int64.of_int (Char.code digest.[i])) (i*8))
  done;
  !hash
;;

let term_hash = function
  Iri iri -> int64_hash ("R" ^ (Iri.to_string iri))
| Literal lit ->
    int64_hash (
     "L" ^
       lit.lit_value ^ "<" ^
       (Misc.string_of_opt lit.lit_language) ^ ">" ^
       (Misc.string_of_opt (Misc.map_opt Iri.to_string lit.lit_type))
    )
| Blank -> assert false
| Blank_ id -> int64_hash ("B" ^ (string_of_blank_id id))
;;

let compare term1 term2 =
  match term1, term2 with
    Iri iri1, Iri iri2 -> Iri.compare iri1 iri2
  | Iri _, _ -> 1
  | _, Iri _ -> -1
  | Literal lit1, Literal lit2 ->
      begin
        match String.compare lit1.lit_value lit2.lit_value with
          0 ->
            begin
              match Misc.opt_compare String.compare
                lit1.lit_language lit2.lit_language
              with
                0 ->
                  Misc.opt_compare Iri.compare
                    lit1.lit_type lit2.lit_type
              | n -> n
            end
        | n -> n
      end
  | Literal _, _ -> 1
  | _, Literal _ -> -1
  | Blank, Blank -> 0
  | Blank, _ -> 1
      | _, Blank -> -1
  | Blank_ id1, Blank_ id2 ->
      String.compare
        (string_of_blank_id id1)
        (string_of_blank_id id2)

let equal t1 t2 = compare t1 t2 = 0

module Ordered_term =
  struct
    type t = term
    let compare = compare
  end;;

module TSet = Set.Make (Ordered_term);;
module TMap = Map.Make (Ordered_term);;

let lit_true = mk_literal_bool true
let lit_false = mk_literal_bool false
OCaml

Innovation. Community. Security.