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 err -> 186 Format.eprintf "✗ Round-trip failed: %s\n" err) 187 | Error 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 ()