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
41 (fun author ->
42 match Author.name author with
43 | Some name ->
44 Format.printf " - %s" name;
45 (match Author.url author with
46 | Some url -> Format.printf " (%s)" url
47 | None -> ());
48 Format.printf "\n"
49 | None -> ())
50 authors
51 | None -> ());
52
53 Format.printf " Items: %d\n\n" (List.length (Jsonfeed.items feed))
54
55let print_item_details item =
56 Format.printf "Item: %s\n" (Item.id item);
57
58 (match Item.title item with
59 | Some title -> Format.printf " Title: %s\n" title
60 | None -> Format.printf " (No title - microblog entry)\n");
61
62 (match Item.url item with
63 | Some url -> Format.printf " URL: %s\n" url
64 | None -> ());
65
66 (* Print content info *)
67 (match Item.content item with
68 | `Html html ->
69 Format.printf " Content: HTML only (%d chars)\n" (String.length html)
70 | `Text text ->
71 Format.printf " Content: Text only (%d chars)\n" (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" (Jsonfeed.Rfc3339.format date)
80 | None -> ());
81
82 (match Item.date_modified item with
83 | Some date -> Format.printf " Modified: %s\n" (Jsonfeed.Rfc3339.format date)
84 | None -> ());
85
86 (* Print tags *)
87 (match Item.tags item with
88 | Some tags when tags <> [] ->
89 Format.printf " Tags: %s\n" (String.concat ", " tags)
90 | _ -> ());
91
92 (* Print attachments *)
93 (match Item.attachments item with
94 | Some attachments when attachments <> [] ->
95 Format.printf " Attachments:\n";
96 List.iter
97 (fun att ->
98 Format.printf " - %s (%s)\n" (Attachment.url att)
99 (Attachment.mime_type att);
100 (match Attachment.size_in_bytes att with
101 | Some size ->
102 let mb = Int64.to_float size /. (1024. *. 1024.) in
103 Format.printf " Size: %.2f MB\n" mb
104 | None -> ());
105 match Attachment.duration_in_seconds att with
106 | Some duration ->
107 let mins = duration / 60 in
108 let secs = duration mod 60 in
109 Format.printf " Duration: %dm%ds\n" mins secs
110 | None -> ())
111 attachments
112 | _ -> ());
113
114 Format.printf "\n"
115
116let analyze_feed feed =
117 let items = Jsonfeed.items feed in
118
119 Format.printf "\n=== Feed Analysis ===\n\n";
120
121 (* Count content types *)
122 let html_only = ref 0 in
123 let text_only = ref 0 in
124 let both = ref 0 in
125
126 List.iter
127 (fun item ->
128 match Item.content item with
129 | `Html _ -> incr html_only
130 | `Text _ -> incr text_only
131 | `Both _ -> incr both)
132 items;
133
134 Format.printf "Content Types:\n";
135 Format.printf " HTML only: %d\n" !html_only;
136 Format.printf " Text only: %d\n" !text_only;
137 Format.printf " Both: %d\n\n" !both;
138
139 (* Find items with attachments *)
140 let with_attachments =
141 List.filter
142 (fun item ->
143 match Item.attachments item with
144 | Some att when att <> [] -> true
145 | _ -> false)
146 items
147 in
148
149 Format.printf "Items with attachments: %d\n\n" (List.length with_attachments);
150
151 (* Collect all unique tags *)
152 let all_tags =
153 List.fold_left
154 (fun acc item ->
155 match Item.tags item with Some tags -> acc @ tags | None -> acc)
156 [] items
157 in
158 let unique_tags = List.sort_uniq String.compare all_tags in
159
160 if unique_tags <> [] then
161 Format.printf "All tags used: %s\n\n" (String.concat ", " unique_tags)
162
163let main () =
164 (* Parse from example_feed.json file *)
165 Format.printf "=== Parsing JSON Feed from example_feed.json ===\n\n";
166
167 try
168 match of_file "example/example_feed.json" with
169 | Ok feed -> (
170 print_feed_info feed;
171
172 Format.printf "=== Items ===\n\n";
173 List.iter print_item_details (Jsonfeed.items feed);
174
175 analyze_feed feed;
176
177 (* Demonstrate round-trip parsing *)
178 Format.printf "\n=== Round-trip Test ===\n\n";
179 match Jsonfeed.to_string feed with
180 | Error e ->
181 Printf.eprintf "Error serializing feed: %s\n"
182 (Jsont.Error.to_string e);
183 exit 1
184 | Ok json -> (
185 match Jsonfeed.of_string json with
186 | Ok feed2 ->
187 if Jsonfeed.equal feed feed2 then
188 Format.printf "✓ Round-trip successful: feeds are equal\n"
189 else Format.printf "✗ Round-trip failed: feeds differ\n"
190 | Error err ->
191 Format.eprintf "✗ Round-trip failed: %s\n"
192 (Jsont.Error.to_string err)))
193 | Error err ->
194 Format.eprintf "Error parsing feed: %s\n" (Jsont.Error.to_string err)
195 with Sys_error msg -> Format.eprintf "Error reading file: %s\n" msg
196
197let () = main ()