Last active
August 29, 2015 14:22
-
-
Save chrisschreiner/bbb86b22fbe9f652ffed to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
extension String { | |
func toDouble() -> Double? { | |
return NSNumberFormatter().numberFromString(self)?.doubleValue | |
} | |
} | |
public struct Place: Printable { | |
var name: String! | |
var phenomenon: String! | |
var tempmin: Double? | |
var tempmax: Double? | |
public var description:String { | |
var tempString: String = "" | |
if let min = tempmin { | |
tempString += "min: \(min)" | |
} | |
if let max = tempmax { | |
tempString += "max: \(max)" | |
} | |
return "\(name), \(phenomenon), Temperature \(tempString)" | |
} | |
} | |
public struct Wind: Printable { | |
var name: String! | |
var direction: String! | |
var speedmin: Double! | |
var speedmax: Double! | |
var gust: String! | |
public var description: String { | |
return "\(name), \(direction), Speed min: \(speedmin), max: \(speedmax)" | |
} | |
} | |
public struct Observation: Printable { | |
var phenomenon: String! | |
var tempmin: Double! | |
var tempmax: Double! | |
var text: String! | |
var place: [Place]? | |
var wind: [Wind]? | |
var sea: String! | |
var peipsi: String! | |
public var description: String { | |
return "\(phenomenon), Temperature min: \(tempmin), max: \(tempmax)" | |
} | |
} | |
public struct Forecast: Printable { | |
var date: NSDate! | |
var night = Observation() | |
var day = Observation() | |
private let d = NSDateFormatter() | |
public var description: String { | |
d.dateStyle = .MediumStyle | |
let formattedDate = d.stringFromDate(date) | |
return "\(formattedDate)" | |
} | |
} | |
public struct Model { | |
var forecasts: [Forecast]? // = [] | |
} | |
public class Parser: NSObject, NSXMLParserDelegate { | |
let xmlFeed = "http://www.ilmateenistus.ee/ilma_andmed/xml/forecast.php" | |
//MARK:- XML tags | |
private let kForecasts = "forecasts" | |
private let kForecast = "forecast" | |
private let kNight = "night" | |
private let kPhenomenon = "phenomenon" | |
private let kDay = "day" | |
private let kTempMin = "tempmin" | |
private let kTempMax = "tempmax" | |
private let kPlace = "place" | |
private let kName = "name" | |
private let kText = "text" | |
private let kDirection = "direction" | |
private let kSpeedMin = "speedmin" | |
private let kSpeedMax = "speedmax" | |
private let kGust = "gust" | |
private let kWind = "wind" | |
private let kSea = "sea" | |
private let kPeipsi = "peipsi" | |
//MARK:- | |
private let dateFormatter: NSDateFormatter | |
var model: Model | |
var currentDate: String! | |
var path: [String] = [] | |
var shouldFetchData:Bool = false { | |
didSet { | |
xmlStringData = "" | |
} | |
} | |
var xmlStringData = "" | |
var day = Observation(), | |
night = Observation(), | |
forecast = Forecast(), | |
forecasts = [Forecast](), | |
forecastDate = "", | |
phenomenon = "", | |
phenomenonPlace = "", | |
place = Place(), | |
wind = Wind(), | |
listOfPlace = [Place](), | |
listOfWind = [Wind]() | |
public override init() { | |
dateFormatter = NSDateFormatter() | |
dateFormatter.dateFormat = "yyyy-MM-dd" | |
dateFormatter.timeZone = NSTimeZone.localTimeZone() | |
model = Model() | |
} | |
public func parse() -> Model? { | |
var result = false | |
if let xmlURL: NSURL = NSURL(string: xmlFeed) { | |
if let parser = NSXMLParser(contentsOfURL: xmlURL) { | |
parser.delegate = self | |
result = parser.parse() | |
} | |
} | |
return model | |
} | |
//MARK:- Helpers | |
func push(name: String) { | |
path.append(name) | |
} | |
func pop() { | |
path.removeLast() | |
} | |
func previousPathPoint() -> String { | |
return path[path.count-1] | |
} | |
//MARK:- NSXMLParserDelegate | |
public func parser(parser: NSXMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [NSObject : AnyObject]) { | |
switch elementName { | |
case kForecasts: | |
push(elementName) | |
self.model.forecasts = [] | |
case kForecast: | |
push(elementName) | |
self.forecast = Forecast() | |
let dateString = attributeDict["date"] as! String | |
self.forecast.date = self.dateFormatter.dateFromString(dateString) | |
case kDay: | |
push(elementName) | |
day = Observation() | |
case kNight: | |
push(elementName) | |
night = Observation() | |
case kPlace: | |
push(elementName) | |
place = Place() | |
case kWind: | |
push(elementName) | |
wind = Wind() | |
case kPhenomenon, kTempMax, kTempMin, kName, kText, kSea, kPeipsi, kDirection, kSpeedMin, kSpeedMax, kGust: | |
shouldFetchData = true | |
default: () | |
} | |
} | |
public func parser(parser: NSXMLParser, foundCharacters string: String?) { | |
if shouldFetchData { | |
if let s = string { | |
xmlStringData += s | |
} | |
} | |
} | |
public func parser(parser: NSXMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?){ | |
let parent = previousPathPoint() | |
switch elementName { | |
case kForecasts: | |
self.model.forecasts = forecasts | |
pop() | |
case kForecast: | |
forecasts.append(self.forecast) | |
pop() | |
//--- night | |
case kNight: | |
night.place = listOfPlace.count > 0 ? listOfPlace : nil | |
night.wind = listOfWind.count > 0 ? listOfWind : nil | |
forecast.night = night | |
listOfPlace.removeAll(keepCapacity: true) | |
listOfWind.removeAll(keepCapacity: true) | |
pop() | |
case kPhenomenon where parent == kNight: | |
night.phenomenon = xmlStringData | |
case kTempMin where parent == kNight: | |
night.tempmin = xmlStringData.toDouble()! | |
case kTempMax where parent == kNight: | |
night.tempmax = xmlStringData.toDouble()! | |
case kText where parent == kNight: | |
night.text = xmlStringData | |
case kSea where parent == kNight: | |
night.sea = xmlStringData | |
case kPeipsi where parent == kNight: | |
night.peipsi = xmlStringData | |
//--- day | |
case kDay: | |
day.place = listOfPlace.count > 0 ? listOfPlace : nil | |
day.wind = listOfWind.count > 0 ? listOfWind : nil | |
forecast.day = day | |
listOfPlace.removeAll(keepCapacity: true) | |
listOfWind.removeAll(keepCapacity: true) | |
pop() | |
case kPhenomenon where parent == kDay: | |
day.phenomenon = xmlStringData | |
case kTempMin where parent == kDay: | |
day.tempmin = xmlStringData.toDouble()! | |
case kTempMax where parent == kDay: | |
day.tempmax = xmlStringData.toDouble()! | |
case kText where parent == kDay: | |
day.text = xmlStringData | |
case kSea where parent == kDay: | |
day.sea = xmlStringData | |
case kPeipsi where parent == kDay: | |
day.peipsi = xmlStringData | |
//--- place | |
case kPlace: | |
listOfPlace.append(place) | |
place = Place() | |
pop() | |
case kName where parent == kPlace: | |
place.name = xmlStringData | |
case kPhenomenon where parent == kPlace: | |
place.phenomenon = xmlStringData | |
case kTempMin where parent == kPlace: | |
place.tempmin = xmlStringData.toDouble()! | |
case kTempMax where parent == kPlace: | |
place.tempmax = xmlStringData.toDouble()! | |
//--- wind | |
case kWind: | |
listOfWind.append(wind) | |
wind = Wind() | |
pop() | |
case kName where parent == kWind: | |
wind.name = xmlStringData | |
case kDirection: | |
wind.direction = xmlStringData | |
case kSpeedMin: | |
wind.speedmin = xmlStringData.toDouble()! | |
case kSpeedMax: | |
wind.speedmax = xmlStringData.toDouble()! | |
case kGust: | |
wind.gust = xmlStringData | |
default:() | |
} | |
} | |
public func parser(parser: NSXMLParser, parseErrorOccurred parseError: NSError) { | |
println("failure error: %@", parseError) | |
} | |
} | |
class F { | |
static var indent = 0 | |
static func repeat(s:String,_ number:Int) -> String { | |
return reduce(0..<number,"") { $0.0 + s } | |
} | |
static func output(aString:String) { | |
println(repeat("\t",indent) + aString) | |
} | |
static func header(s:String, block:()->Void) { | |
output(s) | |
indent++ | |
block() | |
indent-- | |
println() | |
} | |
static func group<T:SequenceType>(s:String, data:T?) { | |
if let data = data { | |
header(s) { | |
for each in data { | |
self.output("\(each)") | |
} | |
} | |
} | |
} | |
} | |
//usage | |
func main() { | |
let stub = Parser() | |
if let | |
model = stub.parse(), | |
forecasts = model.forecasts { | |
for forecast in forecasts { | |
F.header("Date: \(forecast)") { | |
F.header("Night, \(forecast.night)") { | |
F.group("Place",data: forecast.night.place) | |
F.group("Wind",data: forecast.night.wind) | |
} | |
F.header("Day, \(forecast.day)") { | |
F.group("Place",data:forecast.day.place) | |
F.group("Wind",data:forecast.day.wind) | |
} | |
} | |
} | |
} | |
} | |
main() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment