#!MUNGERPATH

; Copyright (c) 2006, James Bailie <jimmy@mammothcheese.ca>.
; All rights reserved.
; 
; Redistribution and use in source form, with or without modification, are
; permitted provided that the following conditions are met:  
; 
;     * Redistributions of source code must retain the above copyright
; notice, this list of conditions and the following disclaimer.
;     * The name of James Bailie may not be used to endorse or promote 
; products derived from this software without specific prior written permission.
; 
; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS"
; AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
; IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
; ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
; LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
; SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
; INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
; CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
; ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
; POSSIBILITY OF SUCH DAMAGE.

; --------------------------------------------------------------------------------

; This program demonstrates retrieving data from a sqlite database
; containing an XML document, as created by the xml2sqlite.munger example
; program.  If you have not already done so, you should read the header
; comment of xml2sqlite.munger in order to understand this script.

; This program expects to find an RSS feed in a database, and prints a
; human-readable version of the feed to stdout.  The script accepts one
; command-line option, -f, to specify the filename to read from.  If the
; option is not present, it will attempt to open "document.db".

; An example of usage:

; Use fetch to retrieve a feed and pipe it to the converter.

; fetch -q -o - 'http://rss.slashdot.org/Slashdot/slashdotMain' | /usr/local/share/munger-4.88/xml2sqlite.munger

; Then feed the output of this script to more:

; /usr/local/share/munger-4.88/rss.munger | more

; The script will find the document.db file in the current directory.

; --------------------------------------------------------------------------------

; Make errors fatal to interpreter.

(fatal)

; Load helper functions.

(load (join "/" (libdir) "xmlsqlite.munger"))

; Look for the presence of the -f option.

(load (join "/" (libdir) "options.munger"))
(getopt)

(unless (setq filename (lookup options "f"))
   (setq filename "document.db"))

; Open the database.
 
(when (stringp (setq db (sqlite_open filename)))
   (die db))

; Find first non-cdata toplevel element.  It will be different for
; different versions of RSS/RDF.

(setq sql "SELECT path FROM document WHERE parent = 0 AND path NOT LIKE '%/' ")

(when (stringp (setq result (sqlite_exec db sql)))
   (die result))

(when (not result)
   (die "Badly-formed feed."))

; We only want the path text.

(setq top (caar (cdr result)))

; RDF puts the items outside the channel element.

(if (eq top "/rdf:RDF")
   (setq path (list (substring top 1 0) 1))
   (setq path (list (substring top 1 0) 1 "channel" 1)))

; Our queries are complicated by the fact that there is one less element in
; the path for RDF.  We compose them dynamically at run-time, once, and
; then "eval" them several times later in the appropriate context.

(setq count_query (cons 'count_elements (cons 'db (cons "item" path))))

(setq title_query (cons 'get_cdata (cons 'db (cons 1 (append path '("item" n "title" 1))))))
(setq link_query  (cons 'get_cdata (cons 'db (cons 1 (append path '("item" n "link" 1))))))
(setq desc_query  (cons 'get_cdata (cons 'db (cons 1 (append path '("item" n "description" 1))))))

; Process all the item elements.

(let ((print_it (lambda (x) (while x (print (caar x)) (setq x (cdr x))))))

   (for (n 1 (eval count_query))

      ; Print out the title, link, and description.  The character data may
      ; have been broken up into multiple chunks by the converter, so we need
      ; to make sure we print all returned items.

      (print_it (eval title_query))
      (newline)
      (print_it (eval link_query))

      (newline)
      (newline)

      (print_it (eval desc_query))
      (newline)
      (newline)))
   
(quit)
