Changeset 9664

Show
Ignore:
Timestamp:
09/11/09 22:48:56 (12 months ago)
Author:
tschaub
Message:

Adding more complete WMS capabilities parsing. Thanks trondmm for the comprehensive patch. Some minor changes by me - including leaving the srs member value an object. r=me (closes #2164)

Location:
trunk/openlayers
Files:
4 modified

Legend:

Unmodified
Added
Removed
  • trunk/openlayers/lib/OpenLayers/Format/WMSCapabilities/v1_1.js

    r9571 r9664  
    6565     
    6666    /** 
     67     * Method: read_cap_Service 
     68     */ 
     69    read_cap_Service: function(capabilities, node) { 
     70        var service = {}; 
     71        this.runChildNodes(service, node); 
     72        capabilities.service = service; 
     73    }, 
     74 
     75    /** 
     76     * Method: read_cap_Fees 
     77     */ 
     78    read_cap_Fees: function(service, node) { 
     79        var fees = this.getChildValue(node); 
     80        if (fees && fees.toLowerCase() != "none") { 
     81            service.fees = fees; 
     82        } 
     83    }, 
     84 
     85    /** 
     86     * Method: read_cap_AccessConstraints 
     87     */ 
     88    read_cap_AccessConstraints: function(service, node) { 
     89        var constraints = this.getChildValue(node); 
     90        if (constraints && constraints.toLowerCase() != "none") { 
     91            service.accessConstraints = constraints; 
     92        } 
     93    }, 
     94 
     95    /** 
     96     * Method: read_cap_ContactInformation 
     97    */ 
     98    read_cap_ContactInformation: function(service, node) { 
     99        var contact = {}; 
     100        this.runChildNodes(contact, node); 
     101        service.contactInformation = contact; 
     102    }, 
     103 
     104 
     105    /** 
     106     * Method: read_cap_ContactPersonPrimary 
     107     */ 
     108    read_cap_ContactPersonPrimary: function(contact, node) { 
     109        var personPrimary = {}; 
     110        this.runChildNodes(personPrimary, node); 
     111        contact.personPrimary = personPrimary; 
     112    }, 
     113 
     114    /** 
     115     * Method: read_cap_ContactPerson 
     116     */ 
     117    read_cap_ContactPerson: function(primaryPerson, node) { 
     118        var person = this.getChildValue(node); 
     119        if (person) { 
     120            primaryPerson.person = person; 
     121        } 
     122    }, 
     123 
     124    /** 
     125     * Method: read_cap_ContactOrganization 
     126     */ 
     127    read_cap_ContactOrganization: function(primaryPerson, node) { 
     128        var organization = this.getChildValue(node); 
     129        if (organization) { 
     130            primaryPerson.organization = organization; 
     131        } 
     132    }, 
     133 
     134    /** 
     135     * Method: read_cap_ContactPosition 
     136     */ 
     137    read_cap_ContactPosition: function(contact, node) { 
     138        var position = this.getChildValue(node); 
     139        if (position) { 
     140            contact.position = position; 
     141        } 
     142    }, 
     143 
     144    /** 
     145     * Method: read_cap_ContactAddress 
     146     */ 
     147    read_cap_ContactAddress: function(contact, node) { 
     148        var contactAddress = {}; 
     149        this.runChildNodes(contactAddress, node); 
     150        contact.contactAddress = contactAddress; 
     151    }, 
     152 
     153    /** 
     154     * Method: read_cap_AddressType 
     155     */ 
     156    read_cap_AddressType: function(contactAddress, node) { 
     157        var type = this.getChildValue(node); 
     158        if (type) { 
     159            contactAddress.type = type; 
     160        } 
     161    }, 
     162 
     163    /** 
     164     * Method: read_cap_Address 
     165     */ 
     166    read_cap_Address: function(contactAddress, node) { 
     167        var address = this.getChildValue(node); 
     168        if (address) { 
     169            contactAddress.address = address; 
     170        } 
     171    }, 
     172 
     173    /** 
     174     * Method: read_cap_City 
     175     */ 
     176    read_cap_City: function(contactAddress, node) { 
     177        var city = this.getChildValue(node); 
     178        if (city) { 
     179            contactAddress.city = city; 
     180        } 
     181    }, 
     182 
     183    /** 
     184     * Method: read_cap_StateOrProvince 
     185     */ 
     186    read_cap_StateOrProvince: function(contactAddress, node) { 
     187        var stateOrProvince = this.getChildValue(node); 
     188        if (stateOrProvince) { 
     189            contactAddress.stateOrProvince = stateOrProvince; 
     190        } 
     191    }, 
     192 
     193    /** 
     194     * Method: read_cap_PostCode 
     195     */ 
     196    read_cap_PostCode: function(contactAddress, node) { 
     197        var postcode = this.getChildValue(node); 
     198        if (postcode) { 
     199            contactAddress.postcode = postcode; 
     200        } 
     201    }, 
     202 
     203    /** 
     204     * Method: read_cap_Country 
     205     */ 
     206    read_cap_Country: function(contactAddress, node) { 
     207        var country = this.getChildValue(node); 
     208        if (country) { 
     209            contactAddress.country = country; 
     210        } 
     211    }, 
     212 
     213    /** 
     214     * Method: read_cap_ContactVoiceTelephone 
     215     */ 
     216    read_cap_ContactVoiceTelephone: function(contact, node) { 
     217        var phone = this.getChildValue(node); 
     218        if (phone) { 
     219            contact.phone = phone; 
     220        } 
     221    }, 
     222 
     223    /** 
     224     * Method: read_cap_ContactFacsimileTelephone 
     225     */ 
     226    read_cap_ContactFacsimileTelephone: function(contact, node) { 
     227        var fax = this.getChildValue(node); 
     228        if (fax) { 
     229            contact.fax = fax; 
     230        } 
     231    }, 
     232 
     233    /** 
     234     * Method: read_cap_ContactElectronicMailAddress 
     235     */ 
     236    read_cap_ContactElectronicMailAddress: function(contact, node) { 
     237        var email = this.getChildValue(node); 
     238        if (email) { 
     239            contact.email = email; 
     240        } 
     241    }, 
     242 
     243    /** 
    67244     * Method: read_cap_Capability 
    68245     */ 
     
    95272    }, 
    96273     
     274    /** 
     275     * Method: read_cap_GetCapabilities 
     276     */ 
     277    read_cap_GetCapabilities: function(request, node) { 
     278        var getcapabilities = { 
     279            formats: [] 
     280        }; 
     281        this.runChildNodes(getcapabilities, node); 
     282        request.getcapabilities = getcapabilities; 
     283    }, 
     284 
     285    /** 
     286     * Method: read_cap_GetFeatureInfo 
     287     */ 
     288    read_cap_GetFeatureInfo: function(request, node) { 
     289        var getfeatureinfo = { 
     290            formats: [] 
     291        }; 
     292        this.runChildNodes(getfeatureinfo, node); 
     293        request.getfeatureinfo = getfeatureinfo; 
     294    }, 
     295 
     296    /** 
     297     * Method: read_cap_DescribeLayer 
     298     */ 
     299    read_cap_DescribeLayer: function(request, node) { 
     300        var describelayer = { 
     301            formats: [] 
     302        }; 
     303        this.runChildNodes(describelayer, node); 
     304        request.describelayer = describelayer; 
     305    }, 
     306 
     307    /** 
     308     * Method: read_cap_GetLegendGraphic 
     309     */ 
     310    read_cap_GetLegendGraphic: function(request, node) { 
     311        var getlegendgraphic = { 
     312            formats: [] 
     313        }; 
     314        this.runChildNodes(getlegendgraphic, node); 
     315        request.getlegendgraphic = getlegendgraphic; 
     316    }, 
     317 
     318    /** 
     319     * Method: read_cap_GetStyles 
     320     */ 
     321    read_cap_GetStyles: function(request, node) { 
     322        var getstyles = { 
     323            formats: [] 
     324        }; 
     325        this.runChildNodes(getstyles, node); 
     326        request.getstyles = getstyles; 
     327    }, 
     328 
     329    /** 
     330     * Method: read_cap_PutStyles 
     331     */ 
     332    read_cap_PutStyles: function(request, node) { 
     333        var putstyles = { 
     334            formats: [] 
     335        }; 
     336        this.runChildNodes(putstyles, node); 
     337        request.putstyles = putstyles; 
     338    }, 
     339 
    97340    /** 
    98341     * Method: read_cap_Format 
     
    120363 
    121364    /** 
    122      * Method: read_cap_Service 
    123      */ 
    124     read_cap_Service: function(capabilities, node) { 
    125         var service = {}; 
    126         this.runChildNodes(service, node); 
    127         capabilities.service = service; 
     365     * Method: read_cap_Exception 
     366     */ 
     367    read_cap_Exception: function(capability, node) { 
     368        var exception = { 
     369            formats: [] 
     370        }; 
     371        this.runChildNodes(exception, node); 
     372        capability.exception = exception; 
     373    }, 
     374 
     375    /** 
     376     * Method: read_cap_UserDefinedSymbolization 
     377     */ 
     378    read_cap_UserDefinedSymbolization: function(capability, node) { 
     379        var userSymbols = { 
     380            supportSLD: parseInt(node.getAttribute("SupportSLD")) == 1, 
     381            userLayer: parseInt(node.getAttribute("UserLayer")) == 1, 
     382            userStyle: parseInt(node.getAttribute("UserStyle")) == 1, 
     383            remoteWFS: parseInt(node.getAttribute("RemoteWFS")) == 1 
     384        }; 
     385        capability.userSymbols = userSymbols; 
    128386    }, 
    129387 
     
    135393            formats: capability.request.getmap.formats || [], 
    136394            styles: [], 
     395            srs: {}, 
     396            bbox: {}, 
     397            dimensions: {}, 
    137398            metadataURLs: [], 
    138             keywords: [], 
    139             queryable: (node.getAttribute("queryable") === "1"  
    140                         || node.getAttribute("queryable") === "true") 
    141         }; 
     399            authorityURLs: {}, 
     400            identifiers: {}, 
     401            keywords: [] 
     402        }; 
     403 
    142404        // deal with property inheritance 
    143405        if(parentLayer) { 
    144406            // add style 
    145407            layer.styles = layer.styles.concat(parentLayer.styles); 
    146             // use llbbox 
    147             layer.llbbox = parentLayer.llbbox; 
    148             // use min/maxScale 
    149             layer.minScale = parentLayer.minScale; 
    150             layer.maxScale = parentLayer.maxScale; 
     408 
     409            var attributes = ["queryable", 
     410                              "cascaded", 
     411                              "fixedWidth", 
     412                              "fixedHeight", 
     413                              "opaque", 
     414                              "noSubsets", 
     415                              "llbbox", 
     416                              "minScale", 
     417                              "maxScale", 
     418                              "attribution"]; 
     419 
     420            var complexAttr = ["srs", 
     421                               "bbox", 
     422                               "dimensions", 
     423                               "authorityURLs"]; 
     424             
     425            var key; 
     426            for (var i=0; i<attributes.length; i++) { 
     427                key = attributes[i]; 
     428                if (key in parentLayer) { 
     429                    layer[key] = parentLayer[key]; 
     430                } 
     431            } 
     432 
     433            for (var i=0; i<complexAttr.length; i++) { 
     434                key = complexAttr[i]; 
     435                layer[key] = OpenLayers.Util.extend( 
     436                    layer[key], parentLayer[key] 
     437                ); 
     438            } 
     439 
     440        } 
     441 
     442        var intAttr = ["cascaded", "fixedWidth", "fixedHeight"]; 
     443        var boolAttr = ["queryable", "opaque", "noSubsets"]; 
     444 
     445        for (var i=0; i<intAttr.length; i++) { 
     446            var attr = intAttr[i]; 
     447            var attrNode = node.getAttributeNode(attr); 
     448            if (attrNode && attrNode.specified) { 
     449                // if attribute is present, override inherited value 
     450                layer[attr] = parseInt(attrNode.value); 
     451            } else if (! (attr in layer)) { 
     452                // if attribute isn't present, and we haven't 
     453                // inherited anything from a parent layer 
     454                // set to default value 
     455                layer[attr] = 0; 
     456            } 
     457        } 
     458        for (var i=0; i<boolAttr.length; i++) { 
     459            var attr = boolAttr[i]; 
     460            var attrNode = node.getAttributeNode(attr); 
     461            if (attrNode && attrNode.specified) { 
     462                // if attribute is present, override inherited value 
     463                var value = attrNode.value; 
     464                layer[attr] = ( value === "1" || value === "true" ); 
     465            } else if (! (attr in layer)) { 
     466                // if attribute isn't present, and we haven't 
     467                // inherited anything from a parent layer 
     468                // set to default value 
     469                layer[attr] = false; 
     470            } 
    151471        } 
    152472        var children = node.childNodes; 
     
    164484            } 
    165485        } 
     486 
    166487        if(layer.name) { 
    167488            var index = layer.name.indexOf(":"); 
     
    253574     
    254575    /** 
     576     * Method: read_cap_DataURL 
     577     */ 
     578    read_cap_DataURL: function(layer, node) { 
     579        layer.dataURL = {}; 
     580        this.runChildNodes(layer.dataURL, node); 
     581    }, 
     582 
     583    /** 
     584     * Method: read_cap_FeatureListURL 
     585     */ 
     586    read_cap_FeatureListURL: function(layer, node) { 
     587        layer.featureListURL = {}; 
     588        this.runChildNodes(layer.featureListURL, node); 
     589    }, 
     590 
     591    /** 
     592     * Method: read_cap_AuthorityURL 
     593     */ 
     594    read_cap_AuthorityURL: function(layer, node) { 
     595        var name = node.getAttribute("name"); 
     596        if (! (name in layer.authorityURLs)) { 
     597            var authority = {}; 
     598            this.runChildNodes(authority, node); 
     599            layer.authorityURLs[name] = authority.href; 
     600        } else { 
     601            // A child Layer SHALL NOT define an AuthorityURL with the 
     602            // same name attribute as one inherited from a parent 
     603            return; 
     604        } 
     605    }, 
     606 
     607    /** 
     608     * Method: read_cap_Identifier 
     609    */ 
     610    read_cap_Identifier: function(layer, node) { 
     611        var authority = node.getAttribute("authority"); 
     612 
     613        if (authority in layer.authorityURLs) { 
     614            layer.identifiers[authority] = this.getChildValue(node); 
     615        } else { 
     616            // A layer SHALL NOT declare an Identifier unless a 
     617            // corresponding authorityURL has been declared or 
     618            // inherited earlier in the Capabilities XML 
     619            return; 
     620        } 
     621 
     622    }, 
     623 
     624    /** 
    255625     * Method: read_cap_KeywordList 
    256626     */ 
     
    282652     
    283653    /** 
     654     * Method: read_cap_BoundingBox 
     655     */ 
     656    read_cap_BoundingBox: function(layer, node) { 
     657        var bbox = {}; 
     658        bbox.srs  = node.getAttribute("SRS"); 
     659        bbox.bbox = [ 
     660            parseFloat(node.getAttribute("minx")), 
     661            parseFloat(node.getAttribute("miny")), 
     662            parseFloat(node.getAttribute("maxx")), 
     663            parseFloat(node.getAttribute("maxy")) 
     664        ]; 
     665        var res = { 
     666            x: parseFloat(node.getAttribute("resx")), 
     667            y: parseFloat(node.getAttribute("resy")) 
     668        }; 
     669 
     670        if (! (isNaN(res.x) && isNaN(res.y))) { 
     671            bbox.res = res; 
     672        } 
     673        layer.bbox[bbox.srs] = bbox; 
     674    }, 
     675 
     676    /** 
    284677     * Method: read_cap_Style 
    285678     */ 
     
    291684 
    292685    /** 
     686     * Method: read_cap_Dimension 
     687     */ 
     688    read_cap_Dimension: function(layer, node) { 
     689        var name = node.getAttribute("name").toLowerCase(); 
     690 
     691        if (name in layer["dimensions"]) { 
     692            // "A child SHALL NOT redefine a Dimension with the same 
     693            // name attribute as one that was inherited" 
     694            return; 
     695        } 
     696 
     697        var dim = { 
     698            name: name, 
     699            units: node.getAttribute("units"), 
     700            unitsymbol: node.getAttribute("unitSymbol") 
     701        }; 
     702 
     703        layer.dimensions[dim.name] = dim; 
     704    }, 
     705 
     706    /** 
     707     * Method: read_cap_Extent 
     708     */ 
     709    read_cap_Extent: function(layer, node) { 
     710        var name   = node.getAttribute("name").toLowerCase(); 
     711 
     712        if (name in layer["dimensions"]) { 
     713            var extent = layer.dimensions[name]; 
     714 
     715            extent.nearestVal = node.getAttribute("nearestValue") === "1"; 
     716            extent.multipleVal = node.getAttribute("multipleValues") === "1"; 
     717            extent.current = node.getAttribute("current") === "1"; 
     718            extent["default"] = node.getAttribute("default") || ""; 
     719            var values = this.getChildValue(node); 
     720            extent.values = values.split(","); 
     721        } else { 
     722            // A layer SHALL NOT declare an Extent unless a Dimension 
     723            // with the same name has been declared or inherited 
     724            // earlier in the Capabilities XML 
     725            return; 
     726        } 
     727 
     728    }, 
     729 
     730    /** 
    293731     * Method: read_cap_LegendURL 
    294732     */ 
  • trunk/openlayers/lib/OpenLayers/Format/WMSCapabilities/v1_1_0.js

    r9212 r9664  
    3333    }, 
    3434 
     35    /** 
     36     * Method: read_cap_SRS 
     37     */ 
     38    read_cap_SRS: function(layer, node) { 
     39        var srs = this.getChildValue(node); 
     40        var values = srs.split(/ +/); 
     41        for (var i=0, len=values.length; i<len; i++) { 
     42            layer.srs[values[i]] = true; 
     43        } 
     44    }, 
     45 
    3546    CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1_0"  
    3647 
  • trunk/openlayers/lib/OpenLayers/Format/WMSCapabilities/v1_1_1.js

    r9288 r9664  
    3333    }, 
    3434 
     35    /** 
     36     * Method: read_cap_SRS 
     37     */ 
     38    read_cap_SRS: function(layer, node) { 
     39        var srs = this.getChildValue(node); 
     40        if (srs.indexOf(" ")) { 
     41            // v1.1.0 style SRS 
     42            var values = srs.split(/ +/); 
     43            for (var i=0, len=values.length; i<len; i++) { 
     44                layer.srs[values[i]] = true; 
     45            } 
     46        } else { 
     47            layer.srs[srs] = true; 
     48        } 
     49    }, 
     50 
    3551    CLASS_NAME: "OpenLayers.Format.WMSCapabilities.v1_1_1"  
    3652 
  • trunk/openlayers/tests/Format/WMSCapabilities/v1_1_1.html

    r9571 r9664  
    5252        t.eq(layer.queryable, true, "[2] correct queryable attribute"); 
    5353         
     54 
     55    } 
     56 
     57    function test_layers(t) { 
     58 
     59        t.plan(22); 
     60 
     61        var xml = document.getElementById("ogcsample").firstChild.nodeValue; 
     62        var doc = new OpenLayers.Format.XML().read(xml); 
     63 
     64        var obj = new OpenLayers.Format.WMSCapabilities().read(doc); 
     65        var capability = obj.capability; 
     66 
     67        var layers = {}; 
     68        for (var i=0, len=capability.layers.length; i<len; i++) { 
     69            if ("name" in capability.layers[i]) { 
     70                layers[ capability.layers[i].name ] = capability.layers[i]; 
     71            } 
     72        } 
     73 
     74        var rootlayer = capability.layers[ capability.layers.length - 1]; 
     75 
     76        t.eq(rootlayer.srs,  
     77             {"EPSG:4326": true}, 
     78             "SRS parsed correctly for root layer"); 
     79        t.eq(layers["ROADS_RIVERS"].srs, 
     80             {"EPSG:4326": true, "EPSG:26986": true}, 
     81             "Inheritance of SRS handled correctly when adding SRSes"); 
     82        t.eq(layers["Temperature"].srs, 
     83             {"EPSG:4326": true}, 
     84             "Inheritance of SRS handled correctly when redeclaring an inherited SRS"); 
     85 
     86        var bbox = layers["ROADS_RIVERS"].bbox["EPSG:26986"]; 
     87        t.eq(bbox.bbox, 
     88             [189000, 834000, 285000, 962000], 
     89             "Correct bbox from BoundingBox"); 
     90        t.eq(bbox.res, {x: 1, y: 1}, "Correct resolution"); 
     91 
     92        bbox = layers["ROADS_1M"].bbox["EPSG:26986"]; 
     93        t.eq(bbox.bbox, 
     94             [189000, 834000, 285000, 962000], 
     95             "Correctly inherited bbox"); 
     96        t.eq(bbox.res, {x: 1, y: 1}, "Correctly inherited resolution"); 
     97 
     98 
     99        var identifiers = layers["ROADS_RIVERS"].identifiers; 
     100        var authorities = layers["ROADS_RIVERS"].authorityURLs; 
     101 
     102        t.ok(identifiers, "got identifiers from layer ROADS_RIVERS"); 
     103        t.ok("DIF_ID" in identifiers, 
     104             "authority attribute from Identifiers parsed correctly"); 
     105        t.eq(identifiers["DIF_ID"], 
     106             "123456", 
     107             "Identifier value parsed correctly"); 
     108        t.ok("DIF_ID" in authorities, 
     109             "AuthorityURLs parsed and inherited correctly"); 
     110        t.eq(authorities["DIF_ID"], 
     111             "http://gcmd.gsfc.nasa.gov/difguide/whatisadif.html", 
     112             "OnlineResource in AuthorityURLs parsed correctly"); 
     113 
     114        var featurelist = layers["ROADS_RIVERS"].featureListURL; 
     115        t.ok(featurelist, "layer has FeatureListURL"); 
     116        t.eq(featurelist.format, 
     117             "application/vnd.ogc.se_xml", 
     118             "FeatureListURL format parsed correctly"); 
     119        t.eq(featurelist.href, 
     120             "http://www.university.edu/data/roads_rivers.gml", 
     121             "FeatureListURL OnlineResource parsed correctly"); 
     122 
     123        t.eq(layers["Pressure"].queryable, 
     124             true, 
     125             "queryable property inherited correctly"); 
     126        t.eq(layers["ozone_image"].queryable, 
     127             false, 
     128             "queryable property has correct default value"); 
     129        t.eq(layers["population"].cascaded, 
     130             1, 
     131             "cascaded property parsed correctly"); 
     132        t.eq(layers["ozone_image"].fixedWidth, 
     133             512, 
     134             "fixedWidth property correctly parsed"); 
     135        t.eq(layers["ozone_image"].fixedHeight, 
     136             256, 
     137             "fixedHeight property correctly parsed"); 
     138        t.eq(layers["ozone_image"].opaque, 
     139             true, 
     140             "opaque property parsed correctly"); 
     141        t.eq(layers["ozone_image"].noSubsets, 
     142             true, 
     143             "noSubsets property parsed correctly"); 
     144 
     145 
     146    } 
     147 
     148    function test_dimensions(t) { 
     149 
     150        t.plan(8); 
     151 
     152        var xml = document.getElementById("ogcsample").firstChild.nodeValue; 
     153        var doc = new OpenLayers.Format.XML().read(xml); 
     154 
     155        var obj = new OpenLayers.Format.WMSCapabilities().read(doc); 
     156        var capability = obj.capability; 
     157 
     158        var layers = {}; 
     159        for (var i=0, len=capability.layers.length; i<len; i++) { 
     160            if ("name" in capability.layers[i]) { 
     161                layers[ capability.layers[i].name ] = capability.layers[i]; 
     162            } 
     163        } 
     164 
     165        var time = layers["Clouds"].dimensions.time; 
     166        t.eq(time["default"], "2000-08-22", "Default time value parsed correctly"); 
     167        t.eq(time.values.length, 1, "Currect number of time extent values/periods"); 
     168        t.eq(time.values[0], "1999-01-01/2000-08-22/P1D", "Time extent values parsed correctly"); 
     169 
     170        var elevation = layers["Pressure"].dimensions.elevation; 
     171        t.eq(elevation.units, "EPSG:5030", "Dimension units parsed correctly"); 
     172        t.eq(elevation["default"], "0", "Default elevation value parsed correctly"); 
     173        t.eq(elevation.nearestVal, true, "NearestValue parsed correctly"); 
     174        t.eq(elevation.multipleVal, false, "Absense of MultipleValues handled correctly"); 
     175        t.eq(elevation.values, 
     176             ["0","1000","3000","5000","10000"], 
     177             "Parsing of comma-separated values done correctly"); 
     178 
     179 
     180    } 
     181 
     182    function test_contactinfo(t) { 
     183        t.plan(15); 
     184 
     185        var xml = document.getElementById("ogcsample").firstChild.nodeValue; 
     186        var doc = new OpenLayers.Format.XML().read(xml); 
     187 
     188        var obj = new OpenLayers.Format.WMSCapabilities().read(doc); 
     189        var service = obj.service; 
     190 
     191        var contactinfo = service.contactInformation; 
     192        t.ok(contactinfo, "object contains contactInformation property"); 
     193 
     194        var personPrimary = contactinfo.personPrimary; 
     195        t.ok(personPrimary, "object contains personPrimary property"); 
     196 
     197        t.eq(personPrimary.person, "Jeff deLaBeaujardiere", "ContactPerson parsed correctly"); 
     198        t.eq(personPrimary.organization, "NASA", "ContactOrganization parsed correctly"); 
     199 
     200        t.eq(contactinfo.position, 
     201             "Computer Scientist", 
     202             "ContactPosition parsed correctly"); 
     203 
     204 
     205        var addr = contactinfo.contactAddress; 
     206        t.ok(addr, "object contains contactAddress property"); 
     207 
     208        t.eq(addr.type, "postal", "AddressType parsed correctly"); 
     209        t.eq(addr.address, 
     210             "NASA Goddard Space Flight Center, Code 933", 
     211             "Address parsed correctly"); 
     212        t.eq(addr.city, "Greenbelt", "City parsed correctly"); 
     213        t.eq(addr.stateOrProvince, "MD", "StateOrProvince parsed correctly"); 
     214        t.eq(addr.postcode, "20771", "PostCode parsed correctly"); 
     215        t.eq(addr.country, "USA", "Country parsed correctly"); 
     216 
     217        t.eq(contactinfo.phone, 
     218             "+1 301 286-1569", 
     219             "ContactVoiceTelephone parsed correctly"); 
     220        t.eq(contactinfo.fax, 
     221             "+1 301 286-1777", 
     222             "ContactFacsimileTelephone parsed correctly"); 
     223        t.eq(contactinfo.email, 
     224             "delabeau@iniki.gsfc.nasa.gov", 
     225             "ContactElectronicMailAddress parsed correctly"); 
    54226    } 
    55227     
     228    function test_feesAndConstraints(t) { 
     229        t.plan(2); 
     230 
     231        var obj = new OpenLayers.Format.WMSCapabilities().read(doc); 
     232        var service = obj.service; 
     233 
     234        t.ok(! ("fees" in service), "Fees=none handled correctly"); 
     235        t.ok(! ("accessConstraints" in service), "AccessConstraints=none handled correctly"); 
     236    } 
     237 
     238    function test_requests(t) { 
     239        t.plan(13); 
     240 
     241        var obj = new OpenLayers.Format.WMSCapabilities().read(doc); 
     242        var request = obj.capability.request; 
     243 
     244        t.ok(request, "request property exists"); 
     245        t.ok("getmap" in request, "got GetMap request"); 
     246 
     247        t.ok("getfeatureinfo" in request, "got GetFeatureInfo request"); 
     248        t.eq(request.getfeatureinfo.formats, 
     249             ["text/plain", "text/html", "application/vnd.ogc.gml"], 
     250             "GetFeatureInfo formats correctly parsed"); 
     251 
     252        t.ok("describelayer" in request, "got DescribeLayer request"); 
     253 
     254        t.ok("getlegendgraphic" in request, "got GetLegendGraphic request"); 
     255 
     256        var exception = obj.capability.exception; 
     257        t.ok(exception, "exception property exists"); 
     258        t.eq(exception.formats, 
     259             ["application/vnd.ogc.se_xml"], 
     260             "Exception Format parsed"); 
     261 
     262        var userSymbols = obj.capability.userSymbols; 
     263        t.ok(userSymbols, "userSymbols property exists"); 
     264        t.eq(userSymbols.supportSLD, true, "supportSLD parsed"); 
     265        t.eq(userSymbols.userLayer,  true, "userLayer parsed"); 
     266        t.eq(userSymbols.userStyle,  true, "userStyle parsed"); 
     267        t.eq(userSymbols.remoteWFS,  true, "remoteWFS parsed"); 
     268 
     269    } 
    56270    function test_ogc(t) { 
    57271        t.plan(14) 
     
    251465  <UserDefinedSymbolization SupportSLD="1" UserLayer="1" UserStyle="1" 
    252466    RemoteWFS="1" /> 
     467 
    253468  <Layer> 
    254  
    255469    <Title>Acme Corp. Map Server</Title> 
    256470    <SRS>EPSG:4326</SRS> 
     
    259473       xlink:href="http://gcmd.gsfc.nasa.gov/difguide/whatisadif.html" /> 
    260474    </AuthorityURL> 
     475 
     476 
    261477    <Layer> 
    262478      <Name>ROADS_RIVERS</Name>  
     
    283499      <Identifier authority="DIF_ID">123456</Identifier> 
    284500      <FeatureListURL> 
    285         <Format>application/vnd.ogc.se_xml"</Format> 
     501        <Format>application/vnd.ogc.se_xml</Format> 
    286502        <OnlineResource xmlns:xlink="http://www.w3.org/1999/xlink" xlink:type="simple" 
    287503         xlink:href="http://www.university.edu/data/roads_rivers.gml" /> 
     
    308524 
    309525      <ScaleHint min="4000" max="35000"></ScaleHint> 
     526 
     527 
    310528      <Layer queryable="1"> 
    311529    <Name>ROADS_1M</Name>  
     
    321539    <MetadataURL type="FGDC"> 
    322540          <Format>text/plain</Format> 
    323  
    324541          <OnlineResource xmlns:xlink="http://www.w3.org/1999/xlink" 
    325542           xlink:type="simple" 
     
    366583      <Dimension name="time" units="ISO8601" /> 
    367584      <Extent name="time" default="2000-08-22">1999-01-01/2000-08-22/P1D</Extent> 
     585 
    368586      <Layer> 
    369  
    370587    <Name>Clouds</Name>  
    371588    <Title>Forecast cloud cover</Title> 
    372589      </Layer> 
     590 
    373591      <Layer> 
    374592    <Name>Temperature</Name>  
    375593    <Title>Forecast temperature</Title> 
    376594      </Layer> 
     595 
    377596      <Layer> 
    378  
    379597    <Name>Pressure</Name>  
    380598    <Title>Forecast barometric pressure</Title> 
     
    383601         <Extent name="time" default="2000-08-22">1999-01-01/2000-08-22/P1D</Extent> 
    384602         <Extent name="elevation" default="0" nearestValue="1">0,1000,3000,5000,10000</Extent> 
    385  
    386603      </Layer> 
     604 
    387605    </Layer> 
     606 
    388607    <Layer opaque="1" noSubsets="1" fixedWidth="512" fixedHeight="256"> 
    389608      <Name>ozone_image</Name> 
     
    391610      <LatLonBoundingBox minx="-180" miny="-90" maxx="180" maxy="90" /> 
    392611      <Extent name="time" default="1992">1992</Extent> 
    393  
    394612    </Layer> 
     613 
    395614    <Layer cascaded="1"> 
    396615      <Name>population</Name> 
     
    398617      <LatLonBoundingBox minx="-180" miny="-90" maxx="180" maxy="90" /> 
    399618      <Extent name="time" default="2000">1990/2000/P1Y</Extent> 
    400  
    401619    </Layer> 
     620 
    402621  </Layer> 
     622 
     623 
    403624</Capability> 
    404625</WMT_MS_Capabilities>