XSLT vs JavaScript: XSLT 3.0 REC Section 14.4 Example

by Cyril J

HTML

<div id="xslt3_0example14_4"></div>

JavaScript

/*
  Cyril Jandia (02/2016)

  Public Domain.

  NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
  
  ( See also: https://jsfiddle.net/YSharpLanguage/kj9pk8oz/10 )
*/
JSLT();

var cities = [
  { name: "Milano",  country: "Italia",      pop: 5 },
  { name: "Paris",   country: "France",      pop: 7 },
  { name: "München", country: "Deutschland", pop: 4 },
  { name: "Lyon",    country: "France",      pop: 2 },
  { name: "Venezia", country: "Italia",      pop: 1 }
];

/*
  Cf.
  XSLT 3.0 REC Section 14.4
  Example: Grouping Nodes based on Common Values
  
  https://www.w3.org/TR/xslt-30/#grouping-examples
*/
var output = "<table>\r\n\
  <tr>\r\n\
    <th>Position</th>\r\n\
    <th>Country</th>\r\n\
    <th>City List</th>\r\n\
    <th>Population</th>\r\n\
  </tr>{*}\r\n\
</table>".of
  (
    cities.select().groupBy("country")(function(byCountry, index) {
      var country = byCountry[0],
          cities = byCountry[1].select().orderBy("name");
      return "\r\n\
  <tr>\r\n\
    <td>{position}</td>\r\n\
    <td>{country}</td>\r\n\
    <td>{cities}</td>\r\n\
    <td>{population}</td>\r\n\
  </tr>".
        of({ position: index + 1, country: country,
             cities: cities.map(function(city) { return city.name; }).join(", "),
             population: cities.reduce(function(sum, city) { return sum += city.pop; }, 0)
           });
    })
  );

document.getElementById("xslt3_0example14_4").innerHTML +=
  "<xmp>" +
  output +
  "</xmp>";

/*
.
.
.
.
.
.
.
.
.
.
*/
function JSLT() {

function dataset(obj) {
  var extension = { groupBy: groupBy, orderBy: orderBy },
      extend = function(o, x) {
        for (var p in x) {
          if (x.hasOwnProperty(p) && (typeof x[p] === "function")) {
            o[p] = x[p].bind(o);
          }
        }
        return o;
      };
  return extend(obj, extension);
}

function groupBy() {
  var args = [ ].slice.call(arguments),
      spec = ((typeof args[0] === "function") || (typeof args[0] === "string") ? args[0] :...