OCaml client for the LinkedIn Voyager API
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 89 lines 2.5 kB view raw
1type node = Soup.general Soup.node 2 3type 'a t = node -> ('a, string) result 4(** A decoder takes a DOM node (subtree root) and produces either a value or an 5 error message describing what it couldn't find. *) 6 7let return v _node = Ok v 8let map f dec node = match dec node with Ok v -> Ok (f v) | Error _ as e -> e 9 10let both a b node = 11 match a node with 12 | Error _ as e -> e 13 | Ok av -> ( match b node with Error _ as e -> e | Ok bv -> Ok (av, bv)) 14 15let apply fd ad node = 16 match fd node with 17 | Error _ as e -> e 18 | Ok f -> ( match ad node with Error _ as e -> e | Ok v -> Ok (f v)) 19 20let ( let+ ) x f = map f x 21let ( and+ ) = both 22let default v dec node = match dec node with Ok _ as r -> r | Error _ -> Ok v 23 24let fallback decs node = 25 let rec loop = function 26 | [] -> Error "fallback: all decoders failed" 27 | dec :: rest -> ( 28 match dec node with Ok _ as r -> r | Error _ -> loop rest) 29 in 30 loop decs 31 32(** {1 Leaf decoders} *) 33 34let text node = 35 match Soup.trimmed_texts node with 36 | [] -> Ok "" 37 | parts -> Ok (String.concat " " parts) 38 39let attr_opt name node = 40 match Soup.element node with 41 | None -> Ok None 42 | Some el -> Ok (Soup.attribute name el) 43 44let attr name node = 45 match attr_opt name node with 46 | Ok (Some v) -> Ok v 47 | Ok None -> Error (Fmt.str "missing attribute %S" name) 48 | Error _ as e -> e 49 50let html node = Ok (Soup.to_string node) 51 52(** {1 Navigation} *) 53 54let coerce_soup (el : Soup.element Soup.node) : node = (Soup.coerce el : node) 55 56let query_opt selector dec node = 57 match Soup.( $? ) node selector with 58 | None -> Ok None 59 | Some el -> ( 60 match dec (coerce_soup el) with 61 | Ok v -> Ok (Some v) 62 | Error e -> Error (Fmt.str "in %S: %s" selector e)) 63 64let query selector dec node = 65 match Soup.( $? ) node selector with 66 | None -> Error (Fmt.str "no match for selector %S" selector) 67 | Some el -> ( 68 match dec (coerce_soup el) with 69 | Ok _ as r -> r 70 | Error e -> Error (Fmt.str "in %S: %s" selector e)) 71 72let query_all selector dec node = 73 let nodes = Soup.( $$ ) node selector |> Soup.to_list in 74 let rec loop acc = function 75 | [] -> Ok (List.rev acc) 76 | el :: rest -> ( 77 match dec (coerce_soup el) with 78 | Error e -> Error (Fmt.str "in %S: %s" selector e) 79 | Ok v -> loop (v :: acc) rest) 80 in 81 loop [] nodes 82 83(** {1 Running} *) 84 85let run_on_soup dec (soup : Soup.soup Soup.node) = dec (Soup.coerce soup) 86 87let of_string dec html = 88 let soup = Soup.parse html in 89 run_on_soup dec soup