none
Infobox from GeoXML with HTML formatting RRS feed

  • Question

  • Hello,

    I've been working my way through updating a map from v6.3 to v8 and having some trouble with the infobox pop ups displaying properly.  The map has some toggle buttons that load data from GeoXML files, including the data for the box itself in HTML.  In the old map, there would be a nice looking pop up with information in it (contact data, a link to a page for the site etc).  In the new system, the infobox pop up when clicked, but it's just showing the html code itself (ie, <p>SomeHTML</p>).

    Based on what I've read I suspect I need to do some sort of formatting to tell it it's html content but I can't figure out where to do the call.  I have seen documentation on formatting infoboxes and that GeoXMLLayer can use "infoboxoptions" but I am not sure where to place this in the code.

    Here is the code for the function that loads each layer.  ID is an integer corresponding to the type of facility from the button pressed.

    function loadLayer(id) {   
        
        Microsoft.Maps.loadModule('Microsoft.Maps.GeoXml', function () {
                //Create an instance of the GeoXmlLayer.
                pinLayer = new Microsoft.Maps.GeoXmlLayer();
                pinLayer.setDataSource('images/bingmap/' + id + '.xml', true);
                           
                //Add the layer to the map.
                map.layers.insert(pinLayer);
                
                });
    }
    I'm not super familiar with working with Bing Maps or Javascript as I took over maintaining the website from other people, however the v6.3 map stopped working last week so I've been updating the code.  For the most part I've gotten most of it working except for this bit.

    Josh Miller

    Thursday, September 21, 2017 2:19 PM

Answers

  • Thanks, that is what I expected. Because it i escaped it is much easier for it to include code that does script injection. The GeoXml module won't unescape this to be safe since a lot of the time the XML files that users will be loading my not be one's they control, so higher security risk. If you trust the source of the XML file, simple loop through the shapes and do the following to convert this into true HTML:

    function loadLayer(id) {  
       
        Microsoft.Maps.loadModule('Microsoft.Maps.GeoXml', function () {
                //Create an instance of the GeoXmlLayer.
                pinLayer = new Microsoft.Maps.GeoXmlLayer();
                pinLayer.setDataSource('images/bingmap/' + id + '.xml', true);
       //Get the data set in the GeoXmlLayer.
       var dataSet = pinLayer.getDataSet();
       //Loop through all shapes and layers and decode the HTML of the description.
       if (dataSet.shapes) {
                    for (var i = 0; i < dataSet.shapes.length; i++) {
                        if (dataSet.shapes[i].metadata && dataSet.shapes[i].metadata.description && dataSet.shapes[i].metadata.description.indexOf("&lt;") >= 0) {
                            dataSet.shapes[i].metadata.description = HtmlDecode(dataSet.shapes[i].metadata.description);
                        }
                    }
                }
                if (dataSet.layers) {
                    for (var j = 0; j < dataSet.layers.length; j++) {
                        if (dataSet.layers[j] instanceof Microsoft.Maps.Layer) {
                            var shapes = dataSet.layers[j].getPrimitives();

                            for (var i = 0; i < shapes.length; i++) {
                                if (shapes[i].metadata && shapes[i].metadata.description && shapes[i].metadata.description.indexOf("&lt;") >= 0) {
                                    shapes[i].metadata.description = HtmlDecode(shapes[i].metadata.description);
                                }
                            }
                        }
                    }
                }

      //Add the layer to the map.
      map.layers.insert(pinLayer);  
     });
    }

     function HtmlDecode(encodedHtml){
    var el = document.createElement("div");
    el.innerHTML = encodedHtml;
    return el.innerText;
    }
     


    [Blog] [twitter] [LinkedIn]





    Thursday, September 21, 2017 3:50 PM
  • You code above will require you to do a lot more work as you are essentially pulling the data out of the GeoXmlLayer and adding it as individual shapes/layers which you would need to add events too.

    The unescaping/decoding of your HTML isn't as easy as it should be. Many docs say to use unescape or decode functions, but testing these, I find they aren't doing as what is expected. Looking into this deeper you have to manually convert the encoded HTML parts. I've created a simple function to do this and added it to the code sample. 

    Here is a simple example that uses the XML you provided along with the code I provided to do what you are trying to do. Note that I added values to LAT and LON in your XML since there wasn't in your example, assume those were just placeholders. I also removed the icon tag from the XML as I don't have an image at that URL and thus would run into errors. Here is the code sample:

    <!DOCTYPE html>
    <html>
    <head>
        <title></title>
        <meta charset="utf-8" />
        <script type='text/javascript'>
        var map;
    	
    	//This is your original GeoRSS data, just with new line charaters and extra spaces removed so I could store this as a simple string.
        var georss = '<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml" xmlns:mappoint="http://virtualearth.msn.com/apis/annotate#"><channel><mappointIntlCode>cht </mappointIntlCode><item><title>SiteName </title><description>&lt;p&gt;SITEID &lt;/p&gt; &lt;p&gt;123 Street Road&lt;br /&gt;New York, NY 12345&lt;/p&gt; &lt;p&gt;Eastern Time Zone&lt;/p&gt; &lt;div style="border: 1px solid silver;padding: 6px"&gt; &lt;p&gt;&lt;b&gt;Architecture&lt;/b&gt; &lt;span style="color:black;font-weight:bold"&gt;SITETYPE&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;b&gt;Launched&lt;/b&gt; &lt;span style="color:black;font-weight:bold"&gt;01/01/1900&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;b&gt;Channels&lt;/b&gt;&lt;br /&gt; &lt;table class="tableGray"&gt; &lt;tr&gt; &lt;th&gt;&amp;nbsp;&lt;/th&gt;&lt;th&gt;ItemA&lt;/th&gt;&lt;th&gt;ItemB&lt;/th&gt;&lt;th&gt;All&lt;/th&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;TYPEA&lt;/td&gt;&lt;td&gt;18&lt;/td&gt;&lt;td&gt;55&lt;/td&gt;&lt;td&gt;55&lt;/td&gt; &lt;/tr&gt; &lt;tr class="shade"&gt; &lt;td&gt;TYPEB&lt;/td&gt;&lt;td&gt;353&lt;/td&gt;&lt;td&gt;100&lt;/td&gt;&lt;td&gt;100&lt;/td&gt; &lt;/tr&gt; &lt;tr style="font-weight:bold"&gt; &lt;td&gt;Totals&lt;/td&gt;&lt;td&gt;200&lt;/td&gt;&lt;td&gt;200&lt;/td&gt;&lt;td&gt;200&lt;/td&gt; &lt;/tr&gt; &lt;/table&gt;&lt;br /&gt; &lt;b&gt;THING-A&lt;/b&gt; &lt;span style="color:black;font-weight:bold"&gt;1,000&lt;/span&gt; &lt;/div&gt; &lt;div style="color:gray;background-color:silver;font-size:9px;padding:2px 1px;text-align:right"&gt;updated 0/01/1900&lt;/div&gt; &lt;/p&gt; &lt;p&gt;&lt;a href="locate.cfm?page=location&amp;loc=01"&gt;view details&lt;/a&gt;&lt;/p&gt; </description><georss:point>45 -110</georss:point></item></channel></rss>';
    
        function GetMap() {
            map = new Microsoft.Maps.Map('#myMap', {
                credentials: 'YourBingMapsKey',
                zoom: 1
            });
    
            //Load the GeoXml module.
            Microsoft.Maps.loadModule('Microsoft.Maps.GeoXml', function () {
                //Create an instance of the GeoXmlLayer.
                pinLayer = new Microsoft.Maps.GeoXmlLayer(georss, false);
    			
    			//Modified this line since I am using a local string for the data, simply comment this out and uncomment the other line to tie back into your app.
    			//pinLayer.setDataSource(georss, false);
                //pinLayer.setDataSource('images/bingmap/' + id + '.xml', true);
    						
    			//Get the data set in the GeoXmlLayer.
    			var dataSet = pinLayer.getDataSet();
    			
    			//Loop through all shapes and layers and decode the HTML of the description.
    			if (dataSet.shapes) {
                    for (var i = 0; i < dataSet.shapes.length; i++) {
                        if (dataSet.shapes[i].metadata && dataSet.shapes[i].metadata.description && dataSet.shapes[i].metadata.description.indexOf("&lt;") >= 0) {
                            dataSet.shapes[i].metadata.description = HtmlDecode(dataSet.shapes[i].metadata.description);
                        }
                    }
                }
    			
                if (dataSet.layers) {
                    for (var j = 0; j < dataSet.layers.length; j++) {
                        if (dataSet.layers[j] instanceof Microsoft.Maps.Layer) {
                            var shapes = dataSet.layers[j].getPrimitives();
                            for (var i = 0; i < shapes.length; i++) {
                                if (shapes[i].metadata && shapes[i].metadata.description && shapes[i].metadata.description.indexOf("&lt;") >= 0) {
                                    shapes[i].metadata.description = HtmlDecode(shapes[i].metadata.description);
                                }
                            }
                        }
                    }
                }
                           
                //Add the layer to the map.
                map.layers.insert(pinLayer);
            });
        }
    	
    	function HtmlDecode(encodedHtml){
    		var el = document.createElement("div");
    		el.innerHTML = encodedHtml;
    		return el.innerText;	
    	}
        </script>
        <script type='text/javascript' src='https://www.bing.com/api/maps/mapcontrol?callback=GetMap' async defer></script>
    </head>
    <body>
        <div id="myMap" style=";width:800px;height:600px;"></div>
    </body>
    </html>


    [Blog] [twitter] [LinkedIn]

    Saturday, September 30, 2017 3:52 PM
  • I have gotten it working properly but I still had trouble getting the XML file to read and format using the above code.  I tried using the "dummy xml" data from the code within the file as well and things would not display at all.  Instead I added a bit at the start that reads the file into the georss variable and everything works as expected now.  I have some other relatively minor issues elsewhere still but they are unrelated to this issues.  The code I ended up with is below.

    function loadLayer(id) {
    
    		var data = null;
    		var georss = null;
    		
    		$.get('images/bingmap/' + id + '.xml', function(data) {
    		georss=data;
    		
    		
            //Load the GeoXml module.
            Microsoft.Maps.loadModule('Microsoft.Maps.GeoXml', function () {
                //Create an instance of the GeoXmlLayer.
                pinLayer = new Microsoft.Maps.GeoXmlLayer();
    			
    			pinLayer.setDataSource(georss, false);
            	
    			//Get the data set in the GeoXmlLayer.
    			var dataSet = pinLayer.getDataSet();
    
    			//Loop through all shapes and layers and decode the HTML of the description.
    			if (dataSet.shapes) {
                    for (var i = 0; i < dataSet.shapes.length; i++) {
                        if (dataSet.shapes[i].metadata && dataSet.shapes[i].metadata.description && dataSet.shapes[i].metadata.description.indexOf("&lt;") >= 0) {
                            dataSet.shapes[i].metadata.description = HtmlDecode(dataSet.shapes[i].metadata.description);
                        }
                    }
                }
    			
                if (dataSet.layers) {
                    for (var j = 0; j < dataSet.layers.length; j++) {
                        if (dataSet.layers[j] instanceof Microsoft.Maps.Layer) {
                            var shapes = dataSet.layers[j].getPrimitives();
                            for (var i = 0; i < shapes.length; i++) {
                                if (shapes[i].metadata && shapes[i].metadata.description && shapes[i].metadata.description.indexOf("&lt;") >= 0) {
                                    shapes[i].metadata.description = HtmlDecode(shapes[i].metadata.description);
                                }
                            }
                        }
                    }
                }
                
    			
                //Add the layer to the map.
                map.layers.insert(pinLayer);
            });
    		}, 'text');
        }
        
    	
    	function HtmlDecode(encodedHtml){
    		var el = document.createElement("div");
    		el.innerHTML = encodedHtml;
    		return el.innerText;	
    	}


    Josh Miller

    Wednesday, October 11, 2017 8:57 PM

All replies

  • Can you provide a sample of the description html in your file. There are certain cases where the html is not processed to prevent script injections.

    [Blog] [twitter] [LinkedIn]

    Thursday, September 21, 2017 2:23 PM
  • The xml looks something like this, I've made everything generic but it's the basic format, there are any number of entries in each item.

    <?xml version="1.0" encoding="UTF-8"?>
    <rss version="2.0" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml" xmlns:mappoint="http://virtualearth.msn.com/apis/annotate#">
                                <channel>
                                    <mappointIntlCode>
                                        cht 
                                    </mappointIntlCode>
                                    
                                        <item>
                                            
                                                <title>
                                                    SiteName 
                                                </title>
                                                <description>
                                                    &lt;p&gt;SITEID 
                                                    &lt;/p&gt; &lt;p&gt;123 Street Road&lt;br /&gt;New York, NY 12345&lt;/p&gt; &lt;p&gt;Eastern Time Zone&lt;/p&gt; 
                                                    
                                                        &lt;div style="border: 1px solid silver;padding: 6px"&gt; &lt;p&gt;&lt;b&gt;Architecture&lt;/b&gt; &lt;span style="color:black;font-weight:bold"&gt;SITETYPE&lt;/span&gt;&lt;/p&gt; 
                                                        
                                                            &lt;p&gt;&lt;b&gt;Launched&lt;/b&gt; &lt;span style="color:black;font-weight:bold"&gt;01/01/1900&lt;/span&gt;&lt;/p&gt; 
                                                        
                                                            &lt;p&gt;&lt;b&gt;Channels&lt;/b&gt;&lt;br /&gt; &lt;table class="tableGray"&gt; &lt;tr&gt; &lt;th&gt;&amp;nbsp;&lt;/th&gt;&lt;th&gt;ItemA&lt;/th&gt;&lt;th&gt;ItemB&lt;/th&gt;&lt;th&gt;All&lt;/th&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;TYPEA&lt;/td&gt;&lt;td&gt;18&lt;/td&gt;&lt;td&gt;55&lt;/td&gt;&lt;td&gt;55&lt;/td&gt; &lt;/tr&gt; &lt;tr class="shade"&gt; &lt;td&gt;TYPEB&lt;/td&gt;&lt;td&gt;353&lt;/td&gt;&lt;td&gt;100&lt;/td&gt;&lt;td&gt;100&lt;/td&gt; &lt;/tr&gt; &lt;tr style="font-weight:bold"&gt; &lt;td&gt;Totals&lt;/td&gt;&lt;td&gt;200&lt;/td&gt;&lt;td&gt;200&lt;/td&gt;&lt;td&gt;200&lt;/td&gt; &lt;/tr&gt; &lt;/table&gt;&lt;br /&gt; &lt;b&gt;THING-A&lt;/b&gt; &lt;span style="color:black;font-weight:bold"&gt;1,000&lt;/span&gt; &lt;/div&gt; &lt;div style="color:gray;background-color:silver;font-size:9px;padding:2px 1px;text-align:right"&gt;updated 0/01/1900&lt;/div&gt; &lt;/p&gt; 
                                                        
                                                    &lt;p&gt;&lt;a href="locate.cfm?page=location&amp;loc=01"&gt;view details&lt;/a&gt;&lt;/p&gt; 
                                                </description>
                                                <georss:point>LAT LON</georss:point>
                                                <icon>imagelinkurl.jpg</icon>
                                            
                                        </item>
                                    
                                       
                                    
                                </channel>
                            </rss>
    



    Josh Miller

    Thursday, September 21, 2017 2:33 PM
  • Thanks, that is what I expected. Because it i escaped it is much easier for it to include code that does script injection. The GeoXml module won't unescape this to be safe since a lot of the time the XML files that users will be loading my not be one's they control, so higher security risk. If you trust the source of the XML file, simple loop through the shapes and do the following to convert this into true HTML:

    function loadLayer(id) {  
       
        Microsoft.Maps.loadModule('Microsoft.Maps.GeoXml', function () {
                //Create an instance of the GeoXmlLayer.
                pinLayer = new Microsoft.Maps.GeoXmlLayer();
                pinLayer.setDataSource('images/bingmap/' + id + '.xml', true);
       //Get the data set in the GeoXmlLayer.
       var dataSet = pinLayer.getDataSet();
       //Loop through all shapes and layers and decode the HTML of the description.
       if (dataSet.shapes) {
                    for (var i = 0; i < dataSet.shapes.length; i++) {
                        if (dataSet.shapes[i].metadata && dataSet.shapes[i].metadata.description && dataSet.shapes[i].metadata.description.indexOf("&lt;") >= 0) {
                            dataSet.shapes[i].metadata.description = HtmlDecode(dataSet.shapes[i].metadata.description);
                        }
                    }
                }
                if (dataSet.layers) {
                    for (var j = 0; j < dataSet.layers.length; j++) {
                        if (dataSet.layers[j] instanceof Microsoft.Maps.Layer) {
                            var shapes = dataSet.layers[j].getPrimitives();

                            for (var i = 0; i < shapes.length; i++) {
                                if (shapes[i].metadata && shapes[i].metadata.description && shapes[i].metadata.description.indexOf("&lt;") >= 0) {
                                    shapes[i].metadata.description = HtmlDecode(shapes[i].metadata.description);
                                }
                            }
                        }
                    }
                }

      //Add the layer to the map.
      map.layers.insert(pinLayer);  
     });
    }

     function HtmlDecode(encodedHtml){
    var el = document.createElement("div");
    el.innerHTML = encodedHtml;
    return el.innerText;
    }
     


    [Blog] [twitter] [LinkedIn]





    Thursday, September 21, 2017 3:50 PM
  • This doesn't seem to be working.  When I add the code above, the pins simply don't appear at all anymore on the map.

    Is there some sort of method for telling the boxes to simply render the code?  This is used on an internal website and the xml is created by the website itself in another area.

    I also wonder if this may be part of the issue.  The XML files were created using the v6.3 version of maps, is it possible there's something that's incompatible with v8 when rendering the map?

    The browser console gives an error "dataset is undefined", though the line "var dataSet = pinLayer.getDataSet();" is there.


    Josh Miller


    • Edited by JoshMiller Monday, September 25, 2017 4:07 PM More Info
    Monday, September 25, 2017 3:36 PM
  • Looks like I had a couple typos in the code sample. I've updated those. That's what I get for typing a response with a cell phone.

    [Blog] [twitter] [LinkedIn]

    Tuesday, September 26, 2017 4:38 AM
  • I'm still not seeing things display properly.  I've looked into some of the code you posted but the main error I get is still "dataSet is undefined".   I have tried throwing in some alert(); checks with if statements and it seems like the variable isn't getting anything back from var dataSet = pinLayer.getDataSet();  .

    You mentioned "The GeoXml module won't unescape this to be safe since a lot of the time the XML files that users will be loading my not be one's they control", the xml files are all created by another module on the server and are pretty safe as far as tampering, the website is inside the corporate network which also should be secure.  Is there something that can be added elsewhere to tell the infobox to trust the input the XML file?  Some of the resources I was reading suggested that you can use "setOptions(options: GeoXmlLayerOptions)" and ont he page for GeoXMLLayerOptions is suggests it can take "infoboxOptions".

    I'm not sure if using these is off base or anything but if it's possible I have not been able to figure out the right method of combining these in a way to tell the code that the description field is html.

    I have also tried manually replacing one of the description fields with some basic HTML which didn't change anything ie <b>This is a paragraph</b>.


    Josh Miller

    Thursday, September 28, 2017 6:11 PM
  • Ok, so after some more research, I've adjusted the code some in a way that is progress.  Mostly because the loops you added actually do something, so I know I'm working with actual data.

    The pins array onto the map just fine with the new code, but they don't interact at all anymore.

    This new method seems to add the locations as individual shapes instead of as a layer (the way the old code did).  Instead of getting undefined before though with dataset as before though I can get some output with test cases such as alert(data.shapes[i].metadata.description); 

    I guess at this point I'm looking for some suggestion or advice on either which function to look into to get the infoboxes to even pop up when clicked on each pin, or possibly some way to push the shapes of data back to a layer so I can use map.layers.insert() instead of maps.entities.push(), since adding things as a layer seemed to work before.

    I hope that makes sense.

    function loadLayer(id) {
      
    	Microsoft.Maps.loadModule('Microsoft.Maps.GeoXml', function () {
                //Create an instance of the GeoXmlLayer.
                Microsoft.Maps.GeoXml.readFromUrl('images/bingmap/' + id + '.xml', null, function (data) {
                    //Do something with the parsed XML data, in this case render it.
                    renderGeoXmlDataSet(data);
                });
     });
    }
    
    
    function renderGeoXmlDataSet(data) {
    				if (data.shapes) {
    							for (var i = 0; i < data.shapes.length; i++) {
    								if (data.shapes[i].metadata && data.shapes[i].metadata.description && data.shapes[i].metadata.description.indexOf("&lt;") >= 0) {
    									data.shapes[i].metadata.description = unescape(data.shapes[i].metadata.description);
    																}
    							}
    						};
    				if (data.layers) {
    						for (var j = 0; j < data.layers.length; j++) {
    							if (pinsdata.layers[j] instanceof Microsoft.Maps.Layer) {
    								var shapes = pinsdata.layers[j].getPrimitives();
    								for (var i = 0; i < shapes.length; i++) {
    									if (shapes[i].metadata && shapes[i].metadata.description && shapes[i].metadata.description.indexOf("&lt;") >= 0) {
    										shapes[i].metadata.description = unescape(shapes[i].metadata.description);
    									}
    								}
    							}
    						}
    					};
    
    
    						
    		
            //Add all shapes that are not in layers to the map.
            if (data.shapes) {
    		    for (var i = 0; i < data.shapes.length; i++) {
                    map.entities.push(data.shapes[i]);
                }
    			/*map.entities.push(data.shapes);*/
            }
            //Add all data layers to the map. 
            if (data.layers) {
                for (var i = 0, len = data.layers.length; i < len; i++) {
                    map.layers.insert(data.layers[i]);
                }
            }
    		
             //Add all screen overlays to the map.
            if (data.screenOverlays) {
                for (var i = 0, len = data.screenOverlays.length; i < len; i++) {
                    map.layers.insert(data.screenOverlays[i]);
                }
            }
            if (data.summary && data.summary.bounds) {
                //Set the map view to focus show the data.
                map.setView({ bounds: data.summary.bounds, padding: 30 });
            }
        }



    Josh Miller

    Friday, September 29, 2017 7:58 PM
  • You code above will require you to do a lot more work as you are essentially pulling the data out of the GeoXmlLayer and adding it as individual shapes/layers which you would need to add events too.

    The unescaping/decoding of your HTML isn't as easy as it should be. Many docs say to use unescape or decode functions, but testing these, I find they aren't doing as what is expected. Looking into this deeper you have to manually convert the encoded HTML parts. I've created a simple function to do this and added it to the code sample. 

    Here is a simple example that uses the XML you provided along with the code I provided to do what you are trying to do. Note that I added values to LAT and LON in your XML since there wasn't in your example, assume those were just placeholders. I also removed the icon tag from the XML as I don't have an image at that URL and thus would run into errors. Here is the code sample:

    <!DOCTYPE html>
    <html>
    <head>
        <title></title>
        <meta charset="utf-8" />
        <script type='text/javascript'>
        var map;
    	
    	//This is your original GeoRSS data, just with new line charaters and extra spaces removed so I could store this as a simple string.
        var georss = '<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:georss="http://www.georss.org/georss" xmlns:gml="http://www.opengis.net/gml" xmlns:mappoint="http://virtualearth.msn.com/apis/annotate#"><channel><mappointIntlCode>cht </mappointIntlCode><item><title>SiteName </title><description>&lt;p&gt;SITEID &lt;/p&gt; &lt;p&gt;123 Street Road&lt;br /&gt;New York, NY 12345&lt;/p&gt; &lt;p&gt;Eastern Time Zone&lt;/p&gt; &lt;div style="border: 1px solid silver;padding: 6px"&gt; &lt;p&gt;&lt;b&gt;Architecture&lt;/b&gt; &lt;span style="color:black;font-weight:bold"&gt;SITETYPE&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;b&gt;Launched&lt;/b&gt; &lt;span style="color:black;font-weight:bold"&gt;01/01/1900&lt;/span&gt;&lt;/p&gt; &lt;p&gt;&lt;b&gt;Channels&lt;/b&gt;&lt;br /&gt; &lt;table class="tableGray"&gt; &lt;tr&gt; &lt;th&gt;&amp;nbsp;&lt;/th&gt;&lt;th&gt;ItemA&lt;/th&gt;&lt;th&gt;ItemB&lt;/th&gt;&lt;th&gt;All&lt;/th&gt; &lt;/tr&gt; &lt;tr&gt; &lt;td&gt;TYPEA&lt;/td&gt;&lt;td&gt;18&lt;/td&gt;&lt;td&gt;55&lt;/td&gt;&lt;td&gt;55&lt;/td&gt; &lt;/tr&gt; &lt;tr class="shade"&gt; &lt;td&gt;TYPEB&lt;/td&gt;&lt;td&gt;353&lt;/td&gt;&lt;td&gt;100&lt;/td&gt;&lt;td&gt;100&lt;/td&gt; &lt;/tr&gt; &lt;tr style="font-weight:bold"&gt; &lt;td&gt;Totals&lt;/td&gt;&lt;td&gt;200&lt;/td&gt;&lt;td&gt;200&lt;/td&gt;&lt;td&gt;200&lt;/td&gt; &lt;/tr&gt; &lt;/table&gt;&lt;br /&gt; &lt;b&gt;THING-A&lt;/b&gt; &lt;span style="color:black;font-weight:bold"&gt;1,000&lt;/span&gt; &lt;/div&gt; &lt;div style="color:gray;background-color:silver;font-size:9px;padding:2px 1px;text-align:right"&gt;updated 0/01/1900&lt;/div&gt; &lt;/p&gt; &lt;p&gt;&lt;a href="locate.cfm?page=location&amp;loc=01"&gt;view details&lt;/a&gt;&lt;/p&gt; </description><georss:point>45 -110</georss:point></item></channel></rss>';
    
        function GetMap() {
            map = new Microsoft.Maps.Map('#myMap', {
                credentials: 'YourBingMapsKey',
                zoom: 1
            });
    
            //Load the GeoXml module.
            Microsoft.Maps.loadModule('Microsoft.Maps.GeoXml', function () {
                //Create an instance of the GeoXmlLayer.
                pinLayer = new Microsoft.Maps.GeoXmlLayer(georss, false);
    			
    			//Modified this line since I am using a local string for the data, simply comment this out and uncomment the other line to tie back into your app.
    			//pinLayer.setDataSource(georss, false);
                //pinLayer.setDataSource('images/bingmap/' + id + '.xml', true);
    						
    			//Get the data set in the GeoXmlLayer.
    			var dataSet = pinLayer.getDataSet();
    			
    			//Loop through all shapes and layers and decode the HTML of the description.
    			if (dataSet.shapes) {
                    for (var i = 0; i < dataSet.shapes.length; i++) {
                        if (dataSet.shapes[i].metadata && dataSet.shapes[i].metadata.description && dataSet.shapes[i].metadata.description.indexOf("&lt;") >= 0) {
                            dataSet.shapes[i].metadata.description = HtmlDecode(dataSet.shapes[i].metadata.description);
                        }
                    }
                }
    			
                if (dataSet.layers) {
                    for (var j = 0; j < dataSet.layers.length; j++) {
                        if (dataSet.layers[j] instanceof Microsoft.Maps.Layer) {
                            var shapes = dataSet.layers[j].getPrimitives();
                            for (var i = 0; i < shapes.length; i++) {
                                if (shapes[i].metadata && shapes[i].metadata.description && shapes[i].metadata.description.indexOf("&lt;") >= 0) {
                                    shapes[i].metadata.description = HtmlDecode(shapes[i].metadata.description);
                                }
                            }
                        }
                    }
                }
                           
                //Add the layer to the map.
                map.layers.insert(pinLayer);
            });
        }
    	
    	function HtmlDecode(encodedHtml){
    		var el = document.createElement("div");
    		el.innerHTML = encodedHtml;
    		return el.innerText;	
    	}
        </script>
        <script type='text/javascript' src='https://www.bing.com/api/maps/mapcontrol?callback=GetMap' async defer></script>
    </head>
    <body>
        <div id="myMap" style=";width:800px;height:600px;"></div>
    </body>
    </html>


    [Blog] [twitter] [LinkedIn]

    Saturday, September 30, 2017 3:52 PM
  • I have gotten it working properly but I still had trouble getting the XML file to read and format using the above code.  I tried using the "dummy xml" data from the code within the file as well and things would not display at all.  Instead I added a bit at the start that reads the file into the georss variable and everything works as expected now.  I have some other relatively minor issues elsewhere still but they are unrelated to this issues.  The code I ended up with is below.

    function loadLayer(id) {
    
    		var data = null;
    		var georss = null;
    		
    		$.get('images/bingmap/' + id + '.xml', function(data) {
    		georss=data;
    		
    		
            //Load the GeoXml module.
            Microsoft.Maps.loadModule('Microsoft.Maps.GeoXml', function () {
                //Create an instance of the GeoXmlLayer.
                pinLayer = new Microsoft.Maps.GeoXmlLayer();
    			
    			pinLayer.setDataSource(georss, false);
            	
    			//Get the data set in the GeoXmlLayer.
    			var dataSet = pinLayer.getDataSet();
    
    			//Loop through all shapes and layers and decode the HTML of the description.
    			if (dataSet.shapes) {
                    for (var i = 0; i < dataSet.shapes.length; i++) {
                        if (dataSet.shapes[i].metadata && dataSet.shapes[i].metadata.description && dataSet.shapes[i].metadata.description.indexOf("&lt;") >= 0) {
                            dataSet.shapes[i].metadata.description = HtmlDecode(dataSet.shapes[i].metadata.description);
                        }
                    }
                }
    			
                if (dataSet.layers) {
                    for (var j = 0; j < dataSet.layers.length; j++) {
                        if (dataSet.layers[j] instanceof Microsoft.Maps.Layer) {
                            var shapes = dataSet.layers[j].getPrimitives();
                            for (var i = 0; i < shapes.length; i++) {
                                if (shapes[i].metadata && shapes[i].metadata.description && shapes[i].metadata.description.indexOf("&lt;") >= 0) {
                                    shapes[i].metadata.description = HtmlDecode(shapes[i].metadata.description);
                                }
                            }
                        }
                    }
                }
                
    			
                //Add the layer to the map.
                map.layers.insert(pinLayer);
            });
    		}, 'text');
        }
        
    	
    	function HtmlDecode(encodedHtml){
    		var el = document.createElement("div");
    		el.innerHTML = encodedHtml;
    		return el.innerText;	
    	}


    Josh Miller

    Wednesday, October 11, 2017 8:57 PM