Search code examples
xmlgoogle-mapsinfowindow

Google maps infowindow from nested xml list


I need to populate a Google maps infowindow from nested items('title') in a xml file. I can create the markers fine and add a 'placeandsitename' in the infowindow.

Here is a snapshot of my xml (the full xml has multiple 'location' elements each with their respective 'movie' elements:

<locations>
<location lat="35.9027" lng="14.5179">
    <siteid>2</siteid>
    <placeandsitename>Valletta, Fort St Elmo</placeandsitename>
    <movie>
        <titleid>1</titleid>
        <title>13 Hours: The Secret Soldiers of Benghazi</title>
    </movie>
    <movie>
        <titleid>7</titleid>
        <title>Clash of the Titans</title>
    </movie>
    <movie>
        <titleid>9</titleid>
        <title>Cutthroat Island</title>
    </movie>
    <movie>
        <titleid>10</titleid>
        <title>A Different Loyalty</title>
    </movie>
    <movie>
        <titleid>25</titleid>
        <title>Midnight Express</title>
    </movie>
    <movie>
        <titleid>64</titleid>
        <title>World War Z</title>
    </movie>
</location>
<locations>

Here is my code:

function initMap() {
    var map = new google.maps.Map(document.getElementById('map'), {
        center: new google.maps.LatLng(35.933134, 14.3768843),  
          zoom: 11
    });
    var infoWindow = new google.maps.InfoWindow;

    downloadUrl('/data/locations_movies.xml', function (data) {
        var xml = data.responseXML;

        var markers = xml.documentElement.getElementsByTagName('location');
        Array.prototype.forEach.call(markers, function (markerElem) {

            var placeandsitename = markerElem.getElementsByTagName('placeandsitename')[0].childNodes[0];
            var point = new google.maps.LatLng(
                parseFloat(markerElem.getAttribute('lat')),
                parseFloat(markerElem.getAttribute('lng')));               

           // header for infowindow works fine!               
            var infowincontent = '<strong>' + placeandsitename.nodeValue + '</strong>'; 

// TODO: Create loop in Movie element and build list<li> element for infowindow (infowincontent)                

            var marker = new google.maps.Marker({
                map: map,
                position: point,
                title: placeandsitename.nodeValue                
            });          

            marker.addListener('click', function () {
                infoWindow.setContent(infowincontent);
                infoWindow.open(map, marker);
            });
        }); 
    });
}

in the 'TODO' part i think i need to create a second loop for the 'title' element for the current location which i'm not sure how to go about


Solution

  • Parse the movie titles out of the XML the same way you are parsing placeandsitename (just instead of only using the first, [0], process through the whole array):

      // header for infowindow              
      var infowincontent = '<strong>' + placeandsitename.nodeValue + '</strong>'; // + movieList;
      // movie titles
      var movies = markerElem.getElementsByTagName('movie');
      if (movies.length > 0)
        infowincontent += "<table border=1>";
      for (var i=0; i<movies.length; i++) {
        infowincontent += "<tr><td>"+movies[i].getElementsByTagName('title')[0].childNodes[0].nodeValue+"</td></tr>";
      }
      if (movies.length > 0)
        infowincontent += "</table>";
    

    proof of concept fiddle

    screenshot of resulting map

    code snippet:

    function initMap() {
      var map = new google.maps.Map(document.getElementById('map'), {
        center: new google.maps.LatLng(35.933134, 14.3768843),
        zoom: 11
      });
      var infoWindow = new google.maps.InfoWindow();
    
      // downloadUrl('/data/locations_movies.xml', function(data) {
      //    var xml = data.responseXML;
      var xml = parseXml(xmlStr);
    
      var markers = xml.documentElement.getElementsByTagName('location');
      Array.prototype.forEach.call(markers, function(markerElem) {
    
        var placeandsitename = markerElem.getElementsByTagName('placeandsitename')[0].childNodes[0];
        var point = new google.maps.LatLng(
          parseFloat(markerElem.getAttribute('lat')),
          parseFloat(markerElem.getAttribute('lng')));
    
        // header for infowindow works fine!               
        var infowincontent = '<strong>' + placeandsitename.nodeValue + '</strong>'; // + movieList;
        var movies = markerElem.getElementsByTagName('movie');
        if (movies.length > 0)
          infowincontent += "<table border=1>";
        for (var i = 0; i < movies.length; i++) {
          infowincontent += "<tr><td>" + movies[i].getElementsByTagName('title')[0].childNodes[0].nodeValue + "</td></tr>";
        }
        if (movies.length > 0)
          infowincontent += "</table>";
        // TODO: Create loop in Movie element and build list<li> element for infowindow (infowincontent)                
    
        var marker = new google.maps.Marker({
          map: map,
          position: point,
          title: placeandsitename.nodeValue
        });
    
        marker.addListener('click', function() {
          infoWindow.setContent(infowincontent);
          infoWindow.open(map, marker);
        });
        google.maps.event.trigger(marker, 'click');
      });
      //  });
    }
    google.maps.event.addDomListener(window, "load", initMap);
    
    function parseXml(str) {
      if (window.ActiveXObject) {
        var doc = new ActiveXObject('MicrosoftXMLDOM');
        doc.loadXML(str);
        return doc;
      } else if (window.DOMParser) {
        return (new DOMParser).parseFromString(str, 'text/xml');
      }
    };
    var xmlStr = '<locations><location lat="35.9027" lng="14.5179"><siteid>2</siteid><placeandsitename>Valletta, Fort St Elmo</placeandsitename><movie><titleid>1</titleid><title>13 Hours: The Secret Soldiers of Benghazi</title></movie><movie><titleid>7</titleid><title>Clash of the Titans</title></movie><movie><titleid>9</titleid><title>Cutthroat Island</title></movie><movie><titleid>10</titleid><title>A Different Loyalty</title></movie><movie><titleid>25</titleid><title>Midnight Express</title></movie><movie><titleid>64</titleid><title>World War Z</title></movie></location><locations>';
    html,
    body,
    #map {
      height: 100%;
      width: 100%;
      margin: 0px;
      padding: 0px
    }
    <script src="https://maps.googleapis.com/maps/api/js"></script>
    <div id="map"></div>