OpenLayers OpenLayers

Ticket #1259: kml_styling_v1.diff

File kml_styling_v1.diff, 26.5 kB (added by rdewit, 1 year ago)

Removed 2 console.infos that slipped in. Btw: current tests pass. Will create new tests once patch is approved.

  • lib/OpenLayers/Format/KML.js

    old new  
    5151     */ 
    5252    extractAttributes: true, 
    5353     
     54    /* Property: reverseFeatures  
     55     * {Boolean} Reverse drawing order of features. Default is false, but 
     56     *           it seems like it should be true. 
     57     * */ 
     58    reverseFeatures: false, 
     59 
    5460    /** 
    5561     * Property: internalns 
    5662     * {String} KML Namespace to use -- defaults to the namespace of the 
    5763     *     Placemark node being parsed, but falls back to kmlns.  
    5864     */ 
    59     internalns: null
     65    internalns: "*"
    6066 
    6167    /** 
     68     * Property: features 
     69     * {Array} Array of features 
     70     *      
     71     */ 
     72    features: [], 
     73 
     74    /** 
     75     * Property: styles 
     76     * {Object} Storage of style objects 
     77     *      
     78     */ 
     79    styles: {}, 
     80 
     81    /** 
     82     * Property: fetched 
     83     * {Object} Storage of KML URLs that have been fetched before 
     84     *     in order to prevent reloading them. 
     85     */ 
     86    fetched: {}, 
     87 
     88    /** 
     89     * APIProperty: maxDepth 
     90     * {Integer} Maximum depth for recursive loading external KML URLs  
     91     *           Defaults to 1: fetch 1 level deep  
     92     *           To disable any external fetching: set this to 0 
     93     */ 
     94    maxDepth: 1, 
     95 
     96    /** 
    6297     * Constructor: OpenLayers.Format.KML 
    6398     * Create a new parser for KML. 
    6499     * 
     
    72107            trimSpace: (/^\s*|\s*$/g), 
    73108            removeSpace: (/\s*/g), 
    74109            splitSpace: (/\s+/), 
    75             trimComma: (/\s*,\s*/g) 
     110            trimComma: (/\s*,\s*/g), 
     111            kmlColor: (/(\w{2})(\w{2})(\w{2})(\w{2})/), 
     112            kmlIconPalette: (/root:\/\/icons\/palette-(\d+)(\.\w+)/), 
     113            straightBracket: (/\$\[(.*?)\]/g) 
    76114        }; 
    77115        OpenLayers.Format.XML.prototype.initialize.apply(this, [options]); 
    78116    }, 
     
    87125     * Returns: 
    88126     * {Array(<OpenLayers.Feature.Vector>)} List of features. 
    89127     */ 
    90     read: function(data) { 
     128    read: function(data, depth) { 
    91129        if(typeof data == "string") { 
    92130            data = OpenLayers.Format.XML.prototype.read.apply(this, [data]); 
    93131        } 
     132 
     133        // Set initial recursion level 
     134        if (!depth) { 
     135            depth = 0; 
     136        } 
     137 
     138        // Fetch external links <NetworkLink> and <Link> 
     139        // Don't do anything if we have reached our maximum depth for recursion 
     140        if (depth < this.maxDepth) { 
     141            this.fetchLinks(data, depth); 
     142        } 
     143 
     144        // Parse internal Style information 
     145        this.parseStyles(data); 
     146 
     147        // Parse placemarks (features) 
     148        this.parseFeatures(data); 
     149 
     150        // Reverse drawing order of features (this seems to be standard in KML) 
     151        // Only do this on highest recursion level 
     152        if (this.reverseFeatures && depth == 0) { 
     153            this.features.reverse(); 
     154        } 
     155 
     156        return this.features; 
     157    }, 
     158 
     159    /** 
     160     * Method: fetchLinks 
     161     * Finds URLs of linked KML documents and fetches them 
     162     *  
     163     * Parameters:  
     164     * data  - {DOMElement} data to read/parse. 
     165     * depth - {Integer} current recursion level 
     166     *  
     167     */ 
     168   fetchLinks: function(data, depth) { 
     169         
     170        var urlNodes = this.getElementsByTagNameNS(data, 
     171                                                       this.internalns, 
     172                                                       "NetworkLink"); 
     173        var numurls = urlNodes.length; 
     174        var urls = new Array(numurls); 
     175        for(var i=0; i<numurls; i++) { 
     176            var hrefNode = this.getElementsByTagNameNS(urlNodes[i],  
     177                                   this.internalns,  
     178                                   "href")[0]; 
     179            if(hrefNode) { 
     180                var href = OpenLayers.Util.getXmlNodeValue(hrefNode); 
     181 
     182                if (this.fetched[href]) {  
     183                    continue; 
     184                } 
     185 
     186                if (OpenLayers.ProxyHost  
     187                        && OpenLayers.String.startsWith(href, "http")) { 
     188                    href = OpenLayers.ProxyHost + escape(href); 
     189                } 
     190                var request = new OpenLayers.Ajax.Request(href,  
     191                              {method: 'get', asynchronous: false }); 
     192                this.fetched[href] = true; // prevent reloading the same urls 
     193                if (request && request.transport) { 
     194                    this.read(request.transport.responseText, depth + 1); 
     195                } 
     196            }  
     197        } 
     198 
     199        var linkNodes = this.getElementsByTagNameNS(data, 
     200                                                       this.internalns, 
     201                                                       "Link"); 
     202        var numlinks = linkNodes.length; 
     203        var links = new Array(numlinks); 
     204        for(var i=0; i<numlinks; i++) { 
     205            var hrefNode = this.getElementsByTagNameNS(linkNodes[i],  
     206                                   this.internalns,  
     207                                   "href")[0]; 
     208            if(hrefNode) { 
     209                var href = OpenLayers.Util.getXmlNodeValue(hrefNode); 
     210 
     211                if (this.fetched[href]) {  
     212                    continue; 
     213                } 
     214 
     215                if (OpenLayers.ProxyHost 
     216                        && OpenLayers.String.startsWith(href, "http")) { 
     217                    href = OpenLayers.ProxyHost + escape(href); 
     218                } 
     219                var request = new OpenLayers.Ajax.Request(href,  
     220                              {method: 'get', asynchronous: false }); 
     221                this.fetched[href] = true; // prevent reloading the same urls 
     222                if (request && request.transport) { 
     223                    this.read(request.transport.responseText, depth + 1); 
     224                } 
     225            }  
     226        } 
     227    }, 
     228 
     229    /** 
     230     * Method: getStyle 
     231     * Retrieves a style from a style hash using styleUrl as the key 
     232     * If the styleUrl doesn't exist yet, we try to fetch it  
     233     * Internet 
     234     *  
     235     * Parameters:  
     236     * styleUrl  - {String} URL of style 
     237     *  
     238     */ 
     239    getStyle: function(styleUrl) { 
     240          
     241        // Fetch remote Style URLs (if not fetched before)  
     242        if (!this.styles[styleUrl]  
     243                && !OpenLayers.String.startsWith(styleUrl, "#")  
     244                && !this.fetched[baseUrl] ) { 
     245 
     246            var baseUrl = OpenLayers.Util.removeTail(styleUrl); 
     247            var href = baseUrl; 
     248 
     249            if (OpenLayers.String.startsWith(styleUrl, "http")) { 
     250                href = OpenLayers.ProxyHost + escape(baseUrl); 
     251            } 
     252                     
     253            var request = new OpenLayers.Ajax.Request(href,  
     254                              {method: 'get', asynchronous: false }); 
     255            if (request && request.transport) { 
     256                this.fetched[baseUrl] = true; // prevent loading more than once 
     257                var data = request.transport.responseText; 
     258                if(typeof data == "string") { 
     259                    data = OpenLayers.Format.XML.prototype.read.apply(this,  
     260                              [data]); 
     261                } 
     262                if (data) { 
     263                    this.parseStyles(data, baseUrl); 
     264                } 
     265            } 
     266 
     267        } 
     268 
     269        // return requested style 
     270        var style = this.styles[styleUrl]; 
     271        return style; 
     272    }, 
     273     
     274 
     275    /** 
     276     * Method: parseStyles 
     277     * Looks for <Style> nodes in the data and parses them 
     278     * Also parses <StyleMap> nodes, but only uses the 'normal' key 
     279     *  
     280     * Parameters:  
     281     * data     - {DOMElement} data to read/parse. 
     282     * baseUrl  - {String} base URL of style 
     283     *  
     284     */ 
     285    parseStyles: function(data, baseUrl) { 
     286        // Parse Style nodes first 
     287        var styleNodes = this.getElementsByTagNameNS(data, 
     288                                                       this.internalns, 
     289                                                       "Style"); 
     290        var numNodes = styleNodes.length; 
     291        var styles = {}; 
     292        for(var i=0; i<numNodes; i++) { 
     293            var style = this.parseStyle(styleNodes[i]); 
     294            if(style) { 
     295                styleName = (baseUrl || "") + "#" + style.name; 
     296                styles[styleName] = style; 
     297            } 
     298        } 
     299 
     300        // Parse StyleMaps afterwards 
     301        // Only the default or "normal" part of the StyleMap is processed now 
     302        // To do the select or "highlight" bit, we'd need to change lots more 
     303        var styleMapNodes = this.getElementsByTagNameNS(data, 
     304                                                       this.internalns, 
     305                                                       "StyleMap"); 
     306 
     307        var numNodes = styleMapNodes.length; 
     308 
     309        for(var i=0; i<numNodes; i++) { 
     310            var node = styleMapNodes[i]; 
     311            var pairs = this.getElementsByTagNameNS(node, this.internalns,  
     312                            "Pair"); 
     313 
     314            var id = node.getAttribute("id"); 
     315            for (var j=0; j<pairs.length; j++) { 
     316                var pair = pairs[j]; 
     317         
     318                // Use the shortcut in the SLD format to quickly retrieve the  
     319                // value of a node. Maybe it's good to have a method in Util  
     320                // to do this 
     321                var key = OpenLayers.Format.SLD.prototype.parseProperty(pair, 
     322                          this.internalns, "key"); 
     323                var styleUrl = OpenLayers.Format.SLD.prototype.parseProperty(pair,  
     324                          this.internalns, "styleUrl"); 
     325 
     326                if (key == "normal") { 
     327                    styles[(baseUrl || "") + "#" + id] = styles[(baseUrl || "") 
     328                                                            + styleUrl]; 
     329                } 
     330 
     331                if (key == "highlight") { 
     332                    // TODO: implement the "select" part 
     333                } 
     334 
     335            } 
     336        } 
     337 
     338        OpenLayers.Util.extend(this.styles, styles); 
     339 
     340    }, 
     341 
     342    /** 
     343     * Method: parseStyle 
     344     * Parses the children of a <Style> node and builds the style hash 
     345     * accordingly 
     346     *  
     347     * Parameters:  
     348     * node - {DOMElement} <Style> node 
     349     *  
     350     */ 
     351    parseStyle: function(node) { 
     352        var style = {}; 
     353         
     354        var types = ["LineStyle", "PolyStyle", "IconStyle", "BalloonStyle"]; 
     355        var type, nodeList, geometry, parser; 
     356        for(var i=0; i<types.length; ++i) { 
     357            type = types[i]; 
     358            //this.internalns = node.namespaceURI ?  
     359                    //node.namespaceURI : this.kmlns; 
     360            styleTypeNode = this.getElementsByTagNameNS(node,  
     361                                                   this.internalns, type)[0]; 
     362            if(!styleTypeNode) {  
     363                continue; 
     364            } 
     365 
     366            // only deal with first geometry of this type 
     367            switch (type.toLowerCase()) { 
     368                case "linestyle": 
     369                    var colorNode = this.getElementsByTagNameNS(styleTypeNode,  
     370                                               this.internalns,  
     371                                               "color")[0]; 
     372                    if (colorNode) { 
     373                        var colorNodeValue = OpenLayers.Util.getXmlNodeValue( 
     374                                                  colorNode); 
     375                        var matches = colorNodeValue.match( 
     376                                          this.regExes.kmlColor); 
     377 
     378                        // transparency 
     379                        var alpha = matches[1]; 
     380                        style["strokeOpacity"] = parseInt(alpha, 16) / 255; 
     381 
     382                        // rgb colors (google uses bgr) 
     383                        var b = matches[2];  
     384                        var g = matches[3];  
     385                        var r = matches[4];  
     386                        style["strokeColor"] = "#" + r + g + b; 
     387                    } 
     388                     
     389                    var widthNode = this.getElementsByTagNameNS(styleTypeNode,  
     390                                               this.internalns, 
     391                                               "width")[0]; 
     392                    if (widthNode) { 
     393                        style["strokeWidth"] = OpenLayers.Util.getXmlNodeValue( 
     394                                                    widthNode); 
     395                    } 
     396 
     397                case "polystyle": 
     398                    var colorNode = this.getElementsByTagNameNS(styleTypeNode,  
     399                                               this.internalns,  
     400                                               "color")[0]; 
     401                    if (colorNode) { 
     402                        var colorNodeValue = OpenLayers.Util.getXmlNodeValue( 
     403                                                  colorNode); 
     404                        var matches = colorNodeValue.match( 
     405                                          this.regExes.kmlColor); 
     406 
     407                        // transparency 
     408                        var alpha = matches[1]; 
     409                        style["fillOpacity"] = parseInt(alpha, 16) / 255; 
     410 
     411                        // rgb colors (google uses bgr) 
     412                        var b = matches[2];  
     413                        var g = matches[3];  
     414                        var r = matches[4];  
     415                        style["fillColor"] = "#" + r + g + b; 
     416                    } 
     417                     
     418                    break; 
     419                case "iconstyle": 
     420                    var iconNode = this.getElementsByTagNameNS(styleTypeNode,  
     421                                               this.internalns,  
     422                                               "Icon")[0]; 
     423 
     424                    // set default width and height of icon 
     425                    style["graphicWidth"] = 32; 
     426                    style["graphicHeight"] = 32; 
     427 
     428                    if (iconNode) { 
     429                        var hrefNode = this.getElementsByTagNameNS(iconNode,  
     430                                               this.internalns,  
     431                                               "href")[0]; 
     432                        if (hrefNode) {                                                    
     433                            href = OpenLayers.Util.getXmlNodeValue(hrefNode); 
     434 
     435                            // support for internal icons  
     436                            //    (/root://icons/palette-x.png) 
     437                            // x and y tell the position on the palette: 
     438                            // - in pixels 
     439                            // - starting from the left bottom 
     440                            // We need to translate that to a position in the  
     441                            // list and request the appropriate icon from the  
     442                            // google maps website 
     443                            var matches = href.match(this.regExes.kmlIconPalette); 
     444                            if (matches)  { 
     445                                var palette = matches[1]; 
     446                                var file_extension = matches[2]; 
     447 
     448                                var xNode = this.getElementsByTagNameNS(iconNode,  
     449                                                       this.internalns,  
     450                                                       "x")[0]; 
     451                                var x = OpenLayers.Util.getXmlNodeValue(xNode); 
     452 
     453                                var yNode = this.getElementsByTagNameNS(iconNode,  
     454                                                       this.internalns,  
     455                                                       "y")[0]; 
     456                                var y = OpenLayers.Util.getXmlNodeValue(yNode); 
     457 
     458                                var posX = x ? x/32 : 0; 
     459                                var posY = y ? (7 - y/32) : 7; 
     460 
     461                                var pos = posY * 8 + posX; 
     462                                var href = "http://maps.google.com/mapfiles/kml/pal"  
     463                                     + palette + "/icon" + pos + file_extension; 
     464                            } 
     465 
     466 
     467                            var wNode = this.getElementsByTagNameNS(iconNode,  
     468                                                   this.internalns,  
     469                                                   "w")[0]; 
     470                            var w = OpenLayers.Util.getXmlNodeValue(wNode); 
     471 
     472                            var hNode = this.getElementsByTagNameNS(iconNode,  
     473                                                   this.internalns,  
     474                                                   "h")[0]; 
     475                            var h = OpenLayers.Util.getXmlNodeValue(hNode); 
     476 
     477                            if (w) { 
     478                                style["graphicWidth"] = parseInt(w); 
     479                            } 
     480 
     481                            if (h) { 
     482                                style["graphicHeight"] = parseInt(h); 
     483                            } 
     484 
     485                            style["graphicOpacity"] = 1; 
     486                            style["externalGraphic"] = href; 
     487                        } 
     488 
     489                    } 
     490 
     491 
     492                    // hotSpots define the offset for an Icon 
     493                    var hotSpotNode = this.getElementsByTagNameNS(styleTypeNode,  
     494                                               this.internalns,  
     495                                               "hotSpot")[0]; 
     496                    if (hotSpotNode) { 
     497                        var x = hotSpotNode.getAttribute("x"); 
     498                        var y = hotSpotNode.getAttribute("y"); 
     499 
     500                        var xUnits = hotSpotNode.getAttribute("xunits"); 
     501                        if (xUnits == "pixels") { 
     502                            style["graphicXOffset"] = parseInt(x); 
     503                        } 
     504                        else if (xUnits == "insetPixels") { 
     505                            style["graphicXOffset"] = style["graphicWidth"]  
     506                                                          - parseInt(x); 
     507                        } 
     508                        else if (xUnits == "fraction") { 
     509                            style["graphicXOffset"] = style["graphicWidth"]  
     510                                                          * parseFloat(x); 
     511                        } 
     512 
     513                        var yUnits = hotSpotNode.getAttribute("yunits"); 
     514                        if (yUnits == "pixels") { 
     515                            style["graphicYOffset"] = parseInt(y); 
     516                        } 
     517                        else if (yUnits == "insetPixels") { 
     518                            style["graphicYOffset"] = style["graphicHeight"]  
     519                                                          - parseInt(y); 
     520                        } 
     521                        else if (yUnits == "fraction") { 
     522                            style["graphicYOffset"] = style["graphicHeight"]  
     523                                                          * parseFloat(y); 
     524                        } 
     525                    } 
     526                    break; 
     527                case "balloonstyle": 
     528                    var balloonStyle = OpenLayers.Util.getXmlNodeValue( 
     529                                            styleTypeNode); 
     530                    if (balloonStyle) { 
     531                        style["balloonStyle"] = balloonStyle.replace( 
     532                                       this.regExes.straightBracket, "${$1}"); 
     533                    } 
     534                    break; 
     535                default: 
     536            } 
     537        } 
     538 
     539 
     540        // Some polygons have no line color, so we use that 
     541        if (!style["strokeColor"]) { 
     542            style["strokeColor"] = style["fillColor"]; 
     543        } 
     544 
     545        // Give the style a name 
     546        style["name"] =  node.getAttribute("id"); 
     547 
     548        return style; 
     549    }, 
     550 
     551    /** 
     552     * Method: parseFeatures 
     553     * Loop through all Placemark nodes and parse them. 
     554     * Will create a list of features 
     555     *  
     556     * Parameters:  
     557     * data - {DOMElement} data to read/parse. 
     558     *  
     559     */ 
     560    parseFeatures: function(data) { 
    94561        var featureNodes = this.getElementsByTagNameNS(data, 
    95                                                        '*'
     562                                                       this.internalns
    96563                                                       "Placemark"); 
    97564        var numFeatures = featureNodes.length; 
    98565        var features = new Array(numFeatures); 
     566 
    99567        for(var i=0; i<numFeatures; i++) { 
    100             var feature = this.parseFeature(featureNodes[i]); 
     568            //var feature = this.parseFeature(featureNodes[i]); 
     569            var featureNode = featureNodes[i]; 
     570            var feature = this.parseFeature.apply(this,[featureNode]) ; 
     571 
    101572            if(feature) { 
     573                // give feature default style 
     574                feature.style = OpenLayers.Util.extend({},  
     575                                    OpenLayers.Feature.Vector.style["default"]); 
     576                  
     577                if (feature.attributes.styleUrl) { 
     578                    var newStyle = this.getStyle(feature.attributes.styleUrl); 
     579                    if (newStyle) { 
     580                        feature.style = OpenLayers.Util.extend(feature.style,  
     581                                            newStyle); 
     582                    } 
     583                } 
     584 
     585                // Make sure that <Style> nodes within a placemark are  
     586                // processed as well: add a styleUrl attribute to the feature. 
     587                var styleNode = this.getElementsByTagNameNS(featureNode, 
     588                                                       this.internalns, 
     589                                                       "Style")[0]; 
     590                if (styleNode) { 
     591                    var style = this.parseStyle(styleNode); 
     592                    if (style) { 
     593                        feature.style = OpenLayers.Util.extend(feature.style,  
     594                                            style); 
     595                    } 
     596                } 
     597 
     598                // add feature to list of features 
    102599                features[i] = feature; 
    103600            } else { 
    104601                throw "Bad Placemark: " + i; 
    105602            } 
    106603        } 
    107         return features; 
     604 
     605        // add new features to existing feature list 
     606        this.features = this.features.concat(features); 
    108607    }, 
    109608 
    110609    /** 
     
    334833     */ 
    335834    parseAttributes: function(node) { 
    336835        var attributes = {}; 
    337         // assume attribute nodes are type 1 children with a type 3 child 
     836        // assume attribute nodes are type 1 children with a type 3 or 4 child 
    338837        var child, grandchildren, grandchild; 
    339838        var children = node.childNodes; 
    340839        for(var i=0; i<children.length; ++i) { 
    341840            child = children[i]; 
    342841            if(child.nodeType == 1) { 
    343842                grandchildren = child.childNodes; 
    344                 if(grandchildren.length == 1) { 
    345                     grandchild = grandchildren[0]; 
     843                if(grandchildren.length == 1 || grandchildren.length == 3) { 
     844                    var grandchild; 
     845                    switch (grandchildren.length) { 
     846                        case 1: 
     847                            grandchild = grandchildren[0]; 
     848                            break; 
     849                        case 3: 
     850                        default: 
     851                            grandchild = grandchildren[1]; 
     852                            break; 
     853                    } 
    346854                    if(grandchild.nodeType == 3 || grandchild.nodeType == 4) { 
    347855                        var name = (child.prefix) ? 
    348856                                child.nodeName.split(":")[1] : 
    349857                                child.nodeName; 
    350                         var value = grandchild.nodeValue.replace( 
    351                                                 this.regExes.trimSpace, ""); 
    352                         attributes[name] = value; 
     858                        var value = OpenLayers.Util.getXmlNodeValue(grandchild) 
     859                        if (value) { 
     860                            value = value.replace(this.regExes.trimSpace, ""); 
     861                            attributes[name] = value; 
     862                        } 
    353863                    } 
    354                 } 
     864                }  
    355865            } 
    356866        } 
    357867        return attributes; 
  • examples/proxy.cgi

    old new  
    1212import urllib2 
    1313import cgi 
    1414import sys, os 
     15import zipfile, re, StringIO #for KMZ support 
    1516 
     17 
    1618# Designed to prevent Open Proxy type stuff. 
    1719 
     20 
    1821allowedHosts = ['www.openlayers.org', 'openlayers.org',  
    1922                'labs.metacarta.com', 'world.freemap.in',  
    20                 'prototype.openmnnd.org', 'geo.openplans.org'] 
     23                'prototype.openmnnd.org', 'geo.openplans.org', 
     24                'geo.openplans.org:8080', 'wight.demos.galdosinc.com', 
     25                'code.google.com', 'maps.google.com', 'bbs.keyhole.com', 
     26                'press.jrc.it' ] 
    2127 
    2228method = os.environ["REQUEST_METHOD"] 
    2329 
    24 if method == "POST": 
    25     qs = os.environ["QUERY_STRING"] 
    26     d = cgi.parse_qs(qs) 
    27     if d.has_key("url"): 
    28         url = d["url"][0] 
    29     else: 
    30         url = "http://www.openlayers.org" 
     30qs = os.environ["QUERY_STRING"] 
     31if method == "GET": 
     32    qs = qs.replace('+', '%2B') 
     33d = cgi.parse_qs(qs) 
     34if d.has_key("url"): 
     35    url = d["url"][0] 
    3136else: 
    32     fs = cgi.FieldStorage() 
    33     url = fs.getvalue('url', "http://www.openlayers.org") 
     37    url = "http://www.openlayers.org" 
    3438 
    3539try: 
    3640    host = url.split("/")[2] 
    37     if allowedHosts and not host in allowedHosts: 
     41    isLocalHost = (os.environ["SERVER_NAME"] == "localhost") or (os.environ["HTTP_HOST"] == "localhost") 
     42    #isLocalHost = False 
     43    if not isLocalHost and allowedHosts and not host in allowedHosts: 
    3844        print "Status: 502 Bad Gateway" 
    3945        print "Content-Type: text/plain" 
    4046        print 
    41         print "This proxy does not allow you to access that location." 
     47        print "This proxy does not allow you to access that location: ", host 
    4248        print  
    4349        print os.environ 
    4450   
     
    6066        else: 
    6167            print "Content-Type: text/plain" 
    6268        print 
     69 
     70        # Handle KMZ files 
     71        # First put content in StringIO object, so ZipFile can handle it 
     72        fileObject = StringIO.StringIO() 
     73        fileObject.write(y.read()) 
     74 
     75        # Now try to handle it as a ZIP file 
     76        try: 
     77            zipObject = zipfile.ZipFile(fileObject, "r") 
     78 
     79        # if not, print the contents (most cases) 
     80        except zipfile.BadZipfile: 
     81            fileObject.seek(0) # reset pointer to start of file 
     82            print fileObject.read() 
     83 
     84        # It *is* a ZIP! Now loop through all files in ZIP 
     85        # and only print the ones ending in .kml 
     86        else: 
     87            for info in zipObject.infolist(): 
     88                if re.search(r'''\.kml$''', info.filename): 
     89                  print zipObject.read(info.filename) 
     90            zipObject.close() 
    6391         
    64         print y.read() 
    65          
     92        fileObject.close() 
    6693        y.close() 
    6794    else: 
    6895        print "Content-Type: text/plain"