; Modules to be included (require (lib "xml.ss" "xml")) (require (lib "url.ss" "net")) (require (lib "13.ss" "srfi")) ; ---- Data Types ---- (define-struct Prediction (datestr temperature)) (define-struct forecast (date predictions)) ; ---- Constants ---- (define current-date (seconds->date (current-seconds))) (define weatherURL (string->url "http://www1.wrh.noaa.gov/cgi-bin/dwf?outFormat=xml&duration=120hr&interval=12&citylist=SLC+Airport%2C40.785%2C-111.9277&city=Go&siteID=SLC")) ; ---- Main Function ---- ; Write the forecast information into a file ; string -> void # (define (write-forecast filename) (let ((outP (open-output-file filename 'append))) (write-xml/content (forecast->element (make-forecast (forecast-time weather-element) (get-forecast weather-element))) outP) (flush-output outP) (close-output-port outP))) ; Get forecast information from the weather forecase element ; Element -> List-of-Prediction (define (get-forecast e) (cond [(not (eq? (element-name e) '|griddedForecast|)) empty] [else (map get-prediction (get-sub-elements e '|forecastDay|))])) ; Get the subelements of e with specified element name ; element string -> list-of-element (define (get-sub-elements e name) (cond [(empty? e) empty] [(eq? (element-name e) name) (cons e (filter-not-empty (apply append (map (lambda (ele) (get-sub-elements ele name)) (filter element? (element-content e))))))] [else (filter-not-empty (apply append (map (lambda (elee) (get-sub-elements elee name)) (filter element? (element-content e)))))])) ; Filter a list to remove those empty ; list-of-X -> list-of-X (define (filter-not-empty l) (cond [(empty? l) empty] [(empty? (car l)) (filter-not-empty (cdr l))] [else (cons (car l) (filter-not-empty (cdr l)))])) ; Get the element if its name is the same with the argument ; Element string -> Element (define (select-element e name) (cond [(empty? e) empty] [(eq? (element-name e) name) e] [else empty])) ; Get the prediction information including "validDate" "maxTemp" "minTemp" from the element ; Element -> Prediction (define (get-prediction e) (cond [(empty? e) empty] [else (make-prediction (get-date e) (get-temperature e '|temperature|))])) ; Get the "validDate" information from element ; Element -> string (define (get-date e) (cond [(empty? e) empty] [(get-info (car (get-sub-elements e '|validDate|)))])) ; Get the information from an element ; Element -> string (define (get-info e) (cond [(empty? e) ""] [else (get-content-info (car (element-content e)))])) ; Get the information from a content ; Content -> string (define (get-content-info c) (cond [(Pcdata? c) (Pcdata-string c)] [(Entity? c) (Entity-text c)] [(Element? c) (get-info c)] [else ""])) ; Get the min or max temperature information from an element ; Element string -> number (define (get-temperature e s) (cond [(empty? e) 0] [else (let* ((els (get-sub-elements e '|period|)) (temp (filter-not-empty (apply append (map (lambda (ele) (get-sub-elements ele s)) els))))) (cond [(empty? temp) 0] [(get-average (map get-info temp))]))])) ; Get the average value of a string list ; list-of-string -> number (define (get-average el) (let iter ((counter 0) (tp 0) (inList el)) (cond [(empty? el) 0] [else (if (eq? inList '()) (cond [(= counter 0) tp] [else (/ tp counter)]) (iter (+ counter 1) (+ tp (string->number (string-trim (car inList)))) (cdr inList) ))]))) ; Make an element from a prediction ; prediction -> element (define (prediction->element p) (cond [(empty? p) empty] [else (make-element 'x 'x 'prediction (list (make-attribute 'x 'x 'date (prediction-datestr p)) (make-attribute 'x 'x 'temperature (number->string(prediction-temperature p)))) (list))])) ; Make an element from a forecast ; forecast -> element (define (forecast->element f) (cond [(empty? f) empty] [else (make-element 'x 'x 'forecast (list (make-attribute 'x 'x 'date (forecast-date f))) (map prediction->element (forecast-predictions f)))])) ; Get the forecastCreationTime from an element ; element -> string (define (forecast-time e) (get-info (car (get-sub-elements e '|forecastCreationTime|)))) ; Define the weather forecast element ; Url -> Element (define weather-element (document-element (read-xml (get-pure-port weatherURL)))) ; ---- Test Cases ---- (write-forecast "test0203.xml")