[racket] (no subject)

From: Greg Hendershott (greghendershott at gmail.com)
Date: Mon May 13 10:29:06 EDT 2013

The following is a bit of a brain dump and hopefully others will jump
in with corrections or with differing opinons.

Many web services give you a choice of getting the data as XML or as JSON.

In this case, you're asking for JSON. But it's a JSON alternative
representation of an Atom feed. Atom feeds natively are XML.

In a language like JavaScript, it might be easier to deal with this as
JSON. But in Racket, although you can certainly work with JSON just
fine, it might be easier to deal with it as XML. Because there's a
deep similarity between XML and s-expressions.

<foo><bar>"hi"</bar></foo>  ;; HTML or XML

is a more tedious way of saying:

'(foo (bar "hi"))   ;; a variety of s-expression called an x-expression

- - -

As Sean pointed out, you want to handle exceptions. `call-input/url`
is your friend here.

To keep our options open (about JSON vs. XML), let's define this helper:

(require net/url)
(define (get-yt uri read-func)
  (call/input-url (string->url uri) get-pure-port read-func))

Now if you want JSON, you can say:

(require json)
(define js
  (get-yt "http://gdata.youtube.com/feeds/api/videos/?alt=json&v=2&category=Movies&q=Inception"
          read-json))
(pretty-print js)

Or if you want XML, you can say:

(require xml)
(define xm
  (get-yt "http://gdata.youtube.com/feeds/api/videos/?v=2&category=Movies&q=Inception"
          read-xml))
(pretty-print xm)

Note that the "alt=json" query parameter is deleted from the request
URI in this example. We're asking YouTube for the primary format, XML,
not the JSON alternative.

Now, this will give you a bunch of Racket structs representing XML.
Instead of those structs, you may want an "x-expression", which is a
representation like when I described above:

    <foo> <bar> "hi" </bar> </foo>

    is a more tedious way of saying:

    '(foo (bar "hi"))  ;; <-- this

For that, let's define a "read-xml->xexpr" function:

(define (read-xml->xexpr in)
  (xml->xexpr (document-element (read-xml in)))
;; Or: (define read-xml->xexpr (compose1 xml->xexpr document-element read-xml))

So now we can say:

;; (require xml)
(define x
  (get-yt "http://gdata.youtube.com/feeds/api/videos/?v=2&category=Movies&q=Inception"
          read-xml->xexpr))
(pretty-print x)

This is an x-expression for the Atom feed. Each of the `(entry ...)`
sub-lists is one of the search results.

(feed
  ...
  (entry ...)
  (entry ...)
  ...)

There are a variety of ways you could parse this, for example using
`match`, but hopefully this is enough to get you going?


On Mon, May 13, 2013 at 5:45 AM, Cody Goodman
<codygman.consulting at gmail.com> wrote:
> Hello, can anyone offer an idiom/thinking process/approach critique on my
> code below? I'm new to racket and trying to program in racket, not program
> python in racket syntax ;)
>
> #lang racket
> (require json)
> (require net/url)
>
> (define data-set
>   (let* (
>          ;; Turn url into a net/url-struct so you can allow a different
> search query as well as other customizations
>          ;; easily.
>          [api-url (string->url
> "http://gdata.youtube.com/feeds/api/videos/?alt=json&v=2&category=Movies&q=Inception")]
>          ;; figure out how to use call/input url
>          [in (get-pure-port api-url #:redirections 2)]
>          [json-blob (read-json in)])
>     (close-input-port in)
>     json-blob))
>
> (struct movie (title price link))
> (define movies (hash-ref (hash-ref data-set 'feed) 'entry))
>
> (define (make-movie movie-result)
>   (let* (
>          [title (hash-ref (hash-ref movie-result 'title) '$t)]
>          [price (with-handlers ([exn:fail? (lambda (exn) 0)])
>                   (hash-ref (car (hash-ref (hash-ref movie-result
> 'media$group) 'media$price)) 'price))]
>          [link (hash-ref (car (hash-ref movie-result 'link)) 'href)]
>          [movie-to-return (movie title price link)])
>     movie-to-return))
>
> (define (make-movie-listing movie)
>   (list (movie-title movie) (movie-price movie) (movie-link movie)))
>
> (define (show-all-movie-listings)
> (map make-movie-listing (map make-movie movies)))
>
> (define (get-relevant-movie-listings movie)
>   ;; TODO: Figure out how to pass paramters into a function with map. Maybe
> lambda?
>   (cond
>     [(string=? (movie-title movie) "Inception") movie]))
>
> ;; TODO: Make this into a function after figuring out how to pass parameters
> into a function with map.
> (define find-movie
>   (car(map get-relevant-movie-listings (map make-movie movies))))
>
> (define inception-movie find-movie)
> (movie-title inception-movie)
>
> ____________________
>   Racket Users list:
>   http://lists.racket-lang.org/users
>

Posted on the users mailing list.