Этот вопрос и явился причиной того, что я решил написать данную статью.
Итак, разрешите представить вашему вниманию «химеру» под названием Angular XSLT module. Ангулар разделяет business логику и view логику, но с модулем XSLT, view логику Angular можно вообще отдать XSLT.
Есть конечно пара подводных камней, это:
1) Результат не будет рендерится,
2) Angular команды не будут вызываться.
Но легким движением руки, эти проблемы решаются на раз-два!
Итак, начнем.
Имеет следующий код:
<html>
<body ng-app="app">
<div ng-controller="ExampleController">
<pre>{{xml | xslt:xslt}}</pre>
</div>
<script src="angular.js"></script>
<script src="ng-xslt.js"></script>
<script>
var myApp = angular.module('app', ['ngXslt']);
myApp.controller('ExampleController', ['$scope',function ($scope) {
$scope.xml ='<?xml version="1.0" encoding="UTF-8"?><root><name>Angular XSLT module!</name></root>';
$scope.xslt = '<?xml version="1.0" encoding="UTF-8"?><xsl:stylesheet xmlns:xsl= "http://www.w3.org/1999/XSL/Transform" version="1.0"><xsl:output method="html"/><xsl:template match="/"><xsl:text>Hello, my name is </xsl:text><b><xsl:value-of select="root/name"/></b></xsl:template></xsl:stylesheet>';
}
]);
</script>
</body>
</html>
(Заметьте, XSLT используется в качестве фильтра.)
Что в браузере рендерится как:
Hello, my name is < b xmlns=«www.w3.org/1999/xhtml»>Angular XSLT module!</b >
Негоже… Нет рендеринга, и выводится как текст. Добавляем одно легкое движение рукой, что называется «санитаризация (trustAsHtml(htmlCode))»:
<html>
<body ng-app="app">
<div ng-controller="ExampleController">
<div ng-bind-html="xml | xslt:xslt | sanitize"></div>
</div>
<script src="angular.js"></script>
<script src="ng-xslt.js"></script>
<script>
var myApp = angular.module('app', ['ngXslt']);
myApp.controller('ExampleController', ['$scope',function ($scope) {
$scope.xml ='<?xml version="1.0" encoding="UTF-8"?><root><name>Angular XSLT module!</name></root>';
$scope.xslt = '<?xml version="1.0" encoding="UTF-8"?><xsl:stylesheet xmlns:xsl= "http://www.w3.org/1999/XSL/Transform" version="1.0"><xsl:output method="html"/><xsl:template match="/"><xsl:text>Hello, my name is </xsl:text><b><xsl:value-of select="root/name"/></b></xsl:template></xsl:stylesheet>';
}
]);
myApp.filter("sanitize", ['$sce', function($sce) {
return function(htmlCode){
return $sce.trustAsHtml(htmlCode);
}
}]);
</script>
</body>
</html>
Что в браузере будет как:
Hello, my name is Angular XSLT module!
Где «Angular XSLT module!» рендерится в bold.
Теперь попытаемся вызвать функцию Ангулара из текста, который выдает нам XSLT модуль, для чего мы:
1) Естественно, дописываем в XSLT вызов функции «clickMyXslt()».
2) В Angular дописываем соответствующую функцию.
3) В Angular дописываем директиву(compileTemplate) для компиляции текста, который выдает нам XSLT модуль.
<html>
<body ng-app="app">
<div ng-controller="ExampleController">
<div ng-bind-html="xml | xslt:xslt | sanitize" compile-template></div>
</div>
<script src="angular.js"></script>
<script src="ng-xslt.js"></script>
<script>
var myApp = angular.module('app', ['ngXslt']);
myApp.controller('ExampleController', ['$scope',function ($scope) {
$scope.xml ='<?xml version="1.0" encoding="UTF-8"?><root><name>Angular XSLT module!</name></root>';
$scope.xslt = '<?xml version="1.0" encoding="UTF-8"?><xsl:stylesheet xmlns:xsl= "http://www.w3.org/1999/XSL/Transform" version="1.0" ><xsl:output method="html"/><xsl:template match="/"><xsl:text>Hello, my name is </xsl:text><b><xsl:value-of select="root/name"/></b><input type="button" ng-click="clickMyXslt()" value="clickMyXslt"/></xsl:template></xsl:stylesheet>';
$scope.clickMyXslt = function() {
alert("Yes, I am from clickMyXslt function!");
};
}
]);
myApp.filter("sanitize", ['$sce', function($sce) {
return function(htmlCode){
return $sce.trustAsHtml(htmlCode);
}
}]);
myApp.directive('compileTemplate', function($compile, $parse){
return {
link: function(scope, element, attr){
var parsed = $parse(attr.ngBindHtml);
function getStringValue() { return (parsed(scope) || '').toString(); }
//Recompile if the template changes
scope.$watch(getStringValue, function() {
$compile(element, null, -9999)(scope); //The -9999 makes it skip directives so that we do not recompile ourselves
});
}
}
});
</script>
</body>
</html>
Что результатирует в браузере:
Hello, my name is Angular XSLT module! <button>clickMyXslt</button>
Где, кликнув на <button/>, получаем всплывающее JS окошко:
alert(«Yes, I am from clickMyXslt function!»);
На этом все. Надеюсь по немногу мифы об устаревании XSLT станут мифами.
(*Все эти техники не я сам придумал, а выловил в интернете и соединил в одно)
Удачного всем кода!
PS: Пример такого подхода можно посмотреть здесь (видеоролик в VK).
PSS: Здесь используется AngularJS v1.4.0
Комментарии (25)
k12th
14.10.2015 15:42+3А, собсно, зачем? XSLT, конечно, это прикольно, здорово поворачивает мозги и во время о?но позволяло не давать бэкендерам устраивать вакханалию в шаблонах, а фронтендерам — в бизнес-логике. Но до прихода XSLT2 (который так и не пришел) многие вещи было сделать очень трудно, а без поддержки eXSLT приходилось еще и велосипедить.
При всей любви к моему первому FP-языку — сейчас у нас есть не менее мощные и более человечные шаблонизаторы.grobitto
16.10.2015 01:03xslt 2.0 появился почти 10 лет назад, по крайней мере на сервере
k12th
16.10.2015 10:22В одной-единственной, закрытой (и недешевой, ЕМНИП) имплементации. На практике все пользовались libxslt или биндингами к ней для своего языка. И не 10 лет назад, в 2009 еще не было (спека W3C была, имплементации не было).
grobitto
16.10.2015 11:15Самое забавное в том, что бесплатная ветка 9.1 поддерживает практически все enterprise-фишки, которые в 9.2 стали платными, ее мы и используем в продакшне уже 8 лет — полная поддержка XSLT 2.0, Java-биндинги и т. д. Если на вход подавать саксоновскую же tinytree — то она еще и супер-быстрая, 10-15 мс на трансформацию типичной странички.
а по поводу того, что есть более мощные шаблонизаторы — тут не соглашусь никак. Мощнее XSLT ничего еще не придумали, но эта мощь и стала главной проблемой — те, кто выучил XSLT в нулевых — выросли, а новое поколение перешло на более простые технологии
sourceforge.net/projects/saxon/files/Saxon-B/9.1.0.8k12th
16.10.2015 11:19Насчет мощности, я, пожалуй, соглашусь, это я погорячился. Насчет дат спорить не буду, память уже не та, но в 2008 в яндексе и в 2009 в РИАНе мы почему-то не имели возможности использовать XSLT2.
zolotyh
14.10.2015 17:38+4Я так ни одной причины не увидел, чтобы использовать AngularJS совместно с XSLT. Зато вижу много недостатков:
- Громоздкий синтаксис
- Проблемы с производительностью
- Слабая поддержка XSLT разработчиками
- Трудно найти специалистов
Убежден, что чем меньше разных технологий используется в проекте, тем лучше и спокойнее. В AngularJS для повторного использования кода есть директивы. Оптимальнее пользоваться ими, так как они уже есть из коробки.anjiJa
14.10.2015 20:00Данный фильтр используется только тогда, когда есть спец задание для XSLT, то есть задачи, где XSLT справляется лучше всего.
Иногда такие задачки случаются, и я был несказанно рад, когда увидел этот фильтр. Вот и решил поделится некоторыми решениями против «подводных каменей» при использовании этого фильтра.Razaz
14.10.2015 20:52+3Можно пример таких задач?
anjiJa
14.10.2015 21:54Вот как раз и пример задачи:
www.fl.ru/projects/2489348/frontend-verstka-formyi-raspisaniya-po-konkretnoy-date.html
Ну и примерное решение, в конце данного топика, видео из вк.lair
14.10.2015 22:07+1А с чем вы сравнивали, что утверждаете, что XSLT справляется лучше всего?
anjiJa
14.10.2015 22:26Мне кажется, что древовидные итерации легче делать на XSLT.
Ну а там где программно что-то решать, и все такое — тогда да, XSLT не мастак.
Наверное мне надо было сказать, что сравнение как между декларативными и процедурными языками?lair
14.10.2015 23:25Мне кажется, что древовидные итерации легче делать на XSLT.
По сравнению с чем?anjiJa
14.10.2015 23:58По сравнению с процедурными языками.
Может вы попробуете вести беседу более развернуто, а не вопросами наскоками?lair
14.10.2015 23:59Ну так процедурными языками жизнь не ограничивается. Что мешает взять функциональные (или писать на гибридных в функциональном стиле)?
anjiJa
15.10.2015 00:04Ничего не мешает. Кто во что горазд!
Функциональные языки тоже круто.lair
15.10.2015 00:08+4Вот поэтому я и спрашиваю — почему вы так легко утверждаете, что XSLT справляется с каким-то классом задач лучше всех. Я такой класс задач знаю один, и это — преобразование xml-xml.
mx2000
16.10.2015 07:18А еще XSLT умеет делать xml -> text или, например, xml -> pdf и вообще, если упороться, xslt удобен в преобразовании xml -> что-угодно. А еще xslt полон по Тьюрингу, что какбэ намекает ;)
lair
16.10.2015 11:07+1Одно дело умеет, другое дело — «справляется лучше всех».
И да, если упороться, то можно применить его к любому преобразованию из XML, только удобным это не назовешь.
dannyzubarev
14.10.2015 18:52Дело в том, что данный модуль изначально был сделан для других целей, поэтому и доступен только в виде фильтра. Возможно, если у кого-то есть возможность и желание, то я с радостью приму ваши pull requests с поддержкой директив. :)
VasilioRuzanni
XSLT не устарел, просто в общем случае для SPA он слишком громоздок и те же задачи сегодня решаются массой более элегантных способов.
И зачем нам тогда тут Angular? Он кроме view-логики тут ничего особенного и не дает.anjiJa
>И зачем нам тогда тут Angular?
Он меняет параметры XSLT фильтра на лету, а именно делает свою работу data-binding-га как фреймворк.
То есть, для XSLT — он заменяет сервер.
> те же задачи сегодня решаются массой более элегантных способов.
на вкус и цвет, элегантнее XSLT пока еще нет; ))