Skip to content

Instantly share code, notes, and snippets.

@brettz9
Created December 26, 2014 21:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save brettz9/53aa246b4992846b5d1a to your computer and use it in GitHub Desktop.
Save brettz9/53aa246b4992846b5d1a to your computer and use it in GitHub Desktop.
XSLT in XHTML; allows self-contained XSLT 1.0 to be run from an XHTML page (without user JavaScript); currently works Firefox only (might work in IE with XSLTProcessor polyfill; other browsers had unknown problems transforming the XSLT)
/*global XSLTProcessor, DOMParser, XMLSerializer*/
/*jslint vars:true */
/*! https://mths.be/array-from v0.2.0 by @mathias */
if (!Array.from) {
(function() {
'use strict';
var defineProperty = (function() {
var result;
// IE 8 only supports `Object.defineProperty` on DOM elements.
try {
var object = {};
var $defineProperty = Object.defineProperty;
result = $defineProperty(object, object, object) && $defineProperty;
} catch(ignore) {}
return result || function put(object, key, descriptor) {
object[key] = descriptor.value;
};
}());
var toStr = Object.prototype.toString;
var isCallable = function(fn) {
// In a perfect world, the `typeof` check would be sufficient. However,
// in Chrome 1–12, `typeof /x/ == 'object'`, and in IE 6–8
// `typeof alert == 'object'` and similar for other host objects.
return typeof fn === 'function' || toStr.call(fn) === '[object Function]';
};
var toInteger = function(value) {
var number = Number(value);
if (isNaN(number)) {
return 0;
}
if (number === 0 || !isFinite(number)) {
return number;
}
return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number));
};
var maxSafeInteger = Math.pow(2, 53) - 1;
var toLength = function(value) {
var len = toInteger(value);
return Math.min(Math.max(len, 0), maxSafeInteger);
};
var from = function(arrayLike) {
var C = this;
if (arrayLike === null || arrayLike === undefined) {
throw new TypeError('`Array.from` requires an array-like object, not `null` or `undefined`');
}
var items = Object(arrayLike);
var mapFn, T;
if (arguments.length > 1) {
mapFn = arguments[1];
if (!isCallable(mapFn)) {
throw new TypeError('When provided, the second argument to `Array.from` must be a function');
}
if (arguments.length > 2) {
T = arguments[2];
}
}
var len = toLength(items.length);
var A = isCallable(C) ? Object(new C(len)) : new Array(len);
var k = 0;
var kValue, mappedValue;
while (k < len) {
kValue = items[k];
if (mapFn) {
mappedValue = T === undefined ? mapFn(kValue, k) : mapFn.call(T, kValue, k);
} else {
mappedValue = kValue;
}
defineProperty(A, k, {
'value': mappedValue,
'configurable': true,
'enumerable': true
});
++k;
}
A.length = len;
return A;
};
defineProperty(Array, 'from', {
'value': from,
'configurable': true,
'writable': true
});
}());
}
window.addEventListener('DOMContentLoaded', function () {'use strict';
// The following is ok for text/html, but not application/xhtml+xml (but text/html has issues with fragments of table rows not getting added properly, etc., so it can't be used for WYSIWYG templating)
// var stylesheets = Array.from(document.querySelectorAll('xsl\\:stylesheet')).concat(Array.from(document.querySelectorAll('xsl\\:transform')));
var stylesheets = Array.from(document.querySelectorAll('stylesheet')).concat(Array.from(document.querySelectorAll('transform')));
stylesheets.forEach(function (stylesheet) {
var processor = new XSLTProcessor();
var doc = new DOMParser().parseFromString(new XMLSerializer().serializeToString(stylesheet), 'application/xml');
processor.importStylesheet(doc);
var frag = processor.transformToFragment(document.createElement('dummy'), document);
stylesheet.parentNode.replaceChild(frag, stylesheet);
});
});
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<meta charset="utf-8" />
<script src="xsl-in-xhtml.js"></script>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:variable name="header">
<tr>
<th>Relationship</th>
<th>Name 1</th>
<th>Name 2</th>
</tr>
</xsl:variable>
<xsl:variable name="family">
<parent>Brett</parent>
<parent>Coco</parent>
<child>Alex</child>
<child>Mia</child>
</xsl:variable>
<xsl:variable name="familyNode" select="document('')//*[local-name() = 'variable' and @name = 'family']"/>
<xsl:variable name="parent" select="$familyNode/*[local-name() = 'parent']"/>
<xsl:variable name="child" select="$familyNode/*[local-name() = 'child']"/>
<xsl:template match="/">
<html>
<body>
<table border="1">
<xsl:copy-of select="$header"/>
<tr>
<td><xsl:value-of select="name($parent)"/></td>
<xsl:for-each select="$parent">
<td><xsl:copy-of select="."/></td>
</xsl:for-each>
</tr>
<tr>
<td><xsl:value-of select="name($child)"/></td>
<xsl:for-each select="$child">
<td><xsl:copy-of select="."/></td>
</xsl:for-each>
</tr>
</table>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment