OCaml library for JSONfeed parsing and creation
1(** Example: Parsing and analyzing JSON Feeds
2
3 This demonstrates:
4 - Parsing feeds from files
5 - Analyzing feed metadata
6 - Iterating over items
7 - Working with dates and content *)
8
9open Jsonfeed
10
11(* Helper to read feed from file *)
12let of_file filename =
13 let content = In_channel.with_open_text filename In_channel.input_all in
14 Jsonfeed.of_string content
15
16let print_feed_info feed =
17 Format.printf "Feed Information:\n";
18 Format.printf " Title: %s\n" (Jsonfeed.title feed);
19 Format.printf " Version: %s\n" (Jsonfeed.version feed);
20
21 (match Jsonfeed.home_page_url feed with
22 | Some url -> Format.printf " Home Page: %s\n" url
23 | None -> ());
24
25 (match Jsonfeed.feed_url feed with
26 | Some url -> Format.printf " Feed URL: %s\n" url
27 | None -> ());
28
29 (match Jsonfeed.description feed with
30 | Some desc -> Format.printf " Description: %s\n" desc
31 | None -> ());
32
33 (match Jsonfeed.language feed with
34 | Some lang -> Format.printf " Language: %s\n" lang
35 | None -> ());
36
37 (match Jsonfeed.authors feed with
38 | Some authors ->
39 Format.printf " Authors:\n";
40 List.iter (fun author ->
41 match Author.name author with
42 | Some name -> Format.printf " - %s" name;
43 (match Author.url author with
44 | Some url -> Format.printf " (%s)" url
45 | None -> ());
46 Format.printf "\n"
47 | None -> ()
48 ) authors
49 | None -> ());
50
51 Format.printf " Items: %d\n\n" (List.length (Jsonfeed.items feed))
52
53let print_item_details item =
54 Format.printf "Item: %s\n" (Item.id item);
55
56 (match Item.title item with
57 | Some title -> Format.printf " Title: %s\n" title
58 | None -> Format.printf " (No title - microblog entry)\n");
59
60 (match Item.url item with
61 | Some url -> Format.printf " URL: %s\n" url
62 | None -> ());
63
64 (* Print content info *)
65 (match Item.content item with
66 | `Html html ->
67 Format.printf " Content: HTML only (%d chars)\n"
68 (String.length html)
69 | `Text text ->
70 Format.printf " Content: Text only (%d chars)\n"
71 (String.length text)
72 | `Both (html, text) ->
73 Format.printf " Content: Both HTML (%d chars) and Text (%d chars)\n"
74 (String.length html) (String.length text));
75
76 (* Print dates *)
77 (match Item.date_published item with
78 | Some date ->
79 Format.printf " Published: %s\n"
80 (Jsonfeed.format_rfc3339 date)
81 | None -> ());
82
83 (match Item.date_modified item with
84 | Some date ->
85 Format.printf " Modified: %s\n"
86 (Jsonfeed.format_rfc3339 date)
87 | None -> ());
88
89 (* Print tags *)
90 (match Item.tags item with
91 | Some tags when tags <> [] ->
92 Format.printf " Tags: %s\n" (String.concat ", " tags)
93 | _ -> ());
94
95 (* Print attachments *)
96 (match Item.attachments item with
97 | Some attachments when attachments <> [] ->
98 Format.printf " Attachments:\n";
99 List.iter (fun att ->
100 Format.printf " - %s (%s)\n"
101 (Attachment.url att)
102 (Attachment.mime_type att);
103 (match Attachment.size_in_bytes att with
104 | Some size ->
105 let mb = Int64.to_float size /. (1024. *. 1024.) in
106 Format.printf " Size: %.2f MB\n" mb
107 | None -> ());
108 (match Attachment.duration_in_seconds att with
109 | Some duration ->
110 let mins = duration / 60 in
111 let secs = duration mod 60 in
112 Format.printf " Duration: %dm%ds\n" mins secs
113 | None -> ())
114 ) attachments
115 | _ -> ());
116
117 Format.printf "\n"
118
119let analyze_feed feed =
120 let items = Jsonfeed.items feed in
121
122 Format.printf "\n=== Feed Analysis ===\n\n";
123
124 (* Count content types *)
125 let html_only = ref 0 in
126 let text_only = ref 0 in
127 let both = ref 0 in
128
129 List.iter (fun item ->
130 match Item.content item with
131 | `Html _ -> incr html_only
132 | `Text _ -> incr text_only
133 | `Both _ -> incr both
134 ) items;
135
136 Format.printf "Content Types:\n";
137 Format.printf " HTML only: %d\n" !html_only;
138 Format.printf " Text only: %d\n" !text_only;
139 Format.printf " Both: %d\n\n" !both;
140
141 (* Find items with attachments *)
142 let with_attachments = List.filter (fun item ->
143 match Item.attachments item with
144 | Some att when att <> [] -> true
145 | _ -> false
146 ) items in
147
148 Format.printf "Items with attachments: %d\n\n" (List.length with_attachments);
149
150 (* Collect all unique tags *)
151 let all_tags = List.fold_left (fun acc item ->
152 match Item.tags item with
153 | Some tags -> acc @ tags
154 | None -> acc
155 ) [] items in
156 let unique_tags = List.sort_uniq String.compare all_tags in
157
158 if unique_tags <> [] then (
159 Format.printf "All tags used: %s\n\n" (String.concat ", " unique_tags)
160 )
161
162let main () =
163 (* Parse from example_feed.json file *)
164 Format.printf "=== Parsing JSON Feed from example_feed.json ===\n\n";
165
166 (try
167 match of_file "example/example_feed.json" with
168 | Ok feed ->
169 print_feed_info feed;
170
171 Format.printf "=== Items ===\n\n";
172 List.iter print_item_details (Jsonfeed.items feed);
173
174 analyze_feed feed;
175
176 (* Demonstrate round-trip parsing *)
177 Format.printf "\n=== Round-trip Test ===\n\n";
178 let json = Jsonfeed.to_string feed in
179 (match Jsonfeed.of_string json with
180 | Ok feed2 ->
181 if Jsonfeed.equal feed feed2 then
182 Format.printf "✓ Round-trip successful: feeds are equal\n"
183 else
184 Format.printf "✗ Round-trip failed: feeds differ\n"
185 | Error (`Msg err) ->
186 Format.eprintf "✗ Round-trip failed: %s\n" err)
187 | Error (`Msg err) ->
188 Format.eprintf "Error parsing feed: %s\n" err
189 with
190 | Sys_error msg ->
191 Format.eprintf "Error reading file: %s\n" msg)
192
193let () = main ()