Skip to content →

Tag: NSURLSession

Retrieving an Online XML Document

Employing NSURLSession to retrieve an online XML document was the focus of some of my recent work that led into a lager task of parsing such a document into its various elements and extracting portions of interest. Thankfully, Apple’s Foundation framework took care of most of the overhead associated with both the retrieval and parsing. In this first of a short series of posts discussing my approach to this task, I begin by looking at document retrieval.

The XML document I’ll be retrieving for this example is an OpenGIS® Web Map Service Interface Standard (WMS) Capabilities Document that represents a catalog of weather products their geoserver provides. Here is a snippet from such a document, courtesy of the great state of Oklahoma:

<Layer queryable="0" opaque="0" cascaded="1">
  <Name>ogi:0</Name>
  <Title>Observed</Title>
  <Abstract>Observed River Stages</Abstract>
  <KeywordList/>
  <SRS>EPSG:4326</SRS>
  <LatLonBoundingBox minx="-180.0" miny="-90.0" maxx="180.0" maxy="90.0"/>
  <BoundingBox SRS="EPSG:4326" minx="-180.0" miny="-90.0" maxx="180.0" maxy="90.0"/>
  <ScaleHint min="0.0" max="250000.0"/>
</Layer>

Below I employ NSURLSession in a rather bare-bones implementation that doesn’t concern itself with response errors or the validity of the document itself, but only requesting the document.

For now, the XMLElement class name isn’t terribly relevant to its functionality, but it will become moreso as I in subsequent posts expand it to represent a single XML document element, such as <Name> or <Title> from the above example, and, in fact, an entire tree of XMLElements. More on that later. For now it is only retrieving the document.

import Foundation

/**
 Provides the mechanism for retrieving an online XML document.
 */
class XMLElement {

  /**
   Attempts to retrieve an XML data object from the given `url`, calling the `completionHandler` upon success or failure.
   */
  func retrieveXmlDataForURL(url: NSURL, completionHandler: 
    (data: NSData?, response: NSURLResponse?, error: NSError?) -> Void) {
    let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
    let task = session.dataTaskWithURL(url, completionHandler: completionHandler)
    task.resume()
  }
}

As you can see, it’s fairly straightforward, with little to comment on. So let’s put it to work with the following script:

import Foundation

/// The data response.
var xmlData: NSData?

/// True once response to request is received.
var responseReceived = false

// Request the XML document
let xmlURLString = "http://ogi.state.ok.us/geoserver/wms?VERSION=1.1.1&REQUEST=GetCapabilities&SERVICE=WMS"
if let xmlURL = NSURL(string: xmlURLString) {
  let xmlElement = XMLElement()
  xmlElement.retrieveXmlDataForURL(xmlURL) {
    data, response, error in
    xmlData = data
    responseReceived = true
  }
}

// Block until response is returned
while !responseReceived {}

// Output the response
let stringData = NSString(data: xmlData!, encoding: NSUTF8StringEncoding) ?? "unable to decode"
print("Response: \(stringData)")

On line 13, I call upon the XMLElement to handle the data request, giving it a completion handler to store the response.

In the context of this test script, I use the loop on line 21 to prevent it from running to conclusion before the asynchronous request has a chance to do its thing.

If all goes well, the output should be the content of a document that begins something like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE WMT_MS_Capabilities SYSTEM "http://204.62.18.179:8080/geoserver/schemas/wms/1.1.1/WMS_MS_Capabilities.dtd">
<WMT_MS_Capabilities version="1.1.1" updateSequence="11284">
  <Service>
    <Name>OGC:WMS</Name>
    <Title>GeoServer Web Map Service</Title>

And that does it! In the next installment, I’ll look at an approach to parsing that returned document using another Foundation class, NSXMLParser.

Leave a Comment