Angular XSLT module

Недавно мне попался маленький проект, где я предложил использование Angular и XSLT, на что я получил такой вопрос: «С чего бы использовать устаревшую технологию XSLT, ведь ее используют только с Java, да к тому же, только для Enterprise»?

Этот вопрос и явился причиной того, что я решил написать данную статью.

Итак, разрешите представить вашему вниманию «химеру» под названием 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

Комментарии 30

    +4
    XSLT не устарел, просто в общем случае для SPA он слишком громоздок и те же задачи сегодня решаются массой более элегантных способов.

    но с модулем XSLT, view логику Angular можно вообще отдать XSLT
    И зачем нам тогда тут Angular? Он кроме view-логики тут ничего особенного и не дает.
      +1
      >И зачем нам тогда тут Angular?
      Он меняет параметры XSLT фильтра на лету, а именно делает свою работу data-binding-га как фреймворк.
      То есть, для XSLT — он заменяет сервер.

      > те же задачи сегодня решаются массой более элегантных способов.
      на вкус и цвет, элегантнее XSLT пока еще нет; ))
      +3
      А, собсно, зачем? XSLT, конечно, это прикольно, здорово поворачивает мозги и во время о́но позволяло не давать бэкендерам устраивать вакханалию в шаблонах, а фронтендерам — в бизнес-логике. Но до прихода XSLT2 (который так и не пришел) многие вещи было сделать очень трудно, а без поддержки eXSLT приходилось еще и велосипедить.

      При всей любви к моему первому FP-языку — сейчас у нас есть не менее мощные и более человечные шаблонизаторы.
        0
        xslt 2.0 появился почти 10 лет назад, по крайней мере на сервере
          0
          В одной-единственной, закрытой (и недешевой, ЕМНИП) имплементации. На практике все пользовались libxslt или биндингами к ней для своего языка. И не 10 лет назад, в 2009 еще не было (спека W3C была, имплементации не было).
            0
            Saxon опенсорсный, пользуемся им с 2007
              0
              Самое забавное в том, что бесплатная ветка 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.8
                0
                Насчет мощности, я, пожалуй, соглашусь, это я погорячился. Насчет дат спорить не буду, память уже не та, но в 2008 в яндексе и в 2009 в РИАНе мы почему-то не имели возможности использовать XSLT2.
              0
              На клиенте XSLT убитый. До ума его так и не довели. К сожалению. А так все было красиво по-началу.
                0
                А мы никогда на клиенте и не пытались это делать, на сервере намного удобнее. Опять же, низкая производительность XSLT — это миф, по крайней мере на Java
                  0
                  Если на сервере тогда совсем непонятно зачем в Angular совать XSLT. Кроме как из-за любви к XSLT :)

                  В тексте вообще говоря неточность.
                  «С чего бы использовать устаревшую технологию XSLT, ведь ее используют только с Java, да к тому же, только для Enterprise»?
                  По крайней мере я сталкивался с проектами и на .NET. и на php. И в своих проектах до сих пор использую.
                  В отечественных «коробочных» CMS на php до сих пор используется в UMI и HostCMS. В 2008 здесь много обсуждался неудачный опыт Битрикса (там кстати тиражировалась легенда о тормознутости)
                    0
                    На .Net сам в 2007 году использовал. В связке с Infopath ;) Правда после этого не очень хочется опять с этим связываться:)
            +4
            Я так ни одной причины не увидел, чтобы использовать AngularJS совместно с XSLT. Зато вижу много недостатков:
            1. Громоздкий синтаксис
            2. Проблемы с производительностью
            3. Слабая поддержка XSLT разработчиками
            4. Трудно найти специалистов

            Убежден, что чем меньше разных технологий используется в проекте, тем лучше и спокойнее. В AngularJS для повторного использования кода есть директивы. Оптимальнее пользоваться ими, так как они уже есть из коробки.
              0
              Данный фильтр используется только тогда, когда есть спец задание для XSLT, то есть задачи, где XSLT справляется лучше всего.
              Иногда такие задачки случаются, и я был несказанно рад, когда увидел этот фильтр. Вот и решил поделится некоторыми решениями против «подводных каменей» при использовании этого фильтра.
                +3
                Можно пример таких задач?
                  0
                  Вот как раз и пример задачи:

                  www.fl.ru/projects/2489348/frontend-verstka-formyi-raspisaniya-po-konkretnoy-date.html

                  Ну и примерное решение, в конце данного топика, видео из вк.
                    +1
                    А с чем вы сравнивали, что утверждаете, что XSLT справляется лучше всего?
                      0
                      Мне кажется, что древовидные итерации легче делать на XSLT.
                      Ну а там где программно что-то решать, и все такое — тогда да, XSLT не мастак.
                      Наверное мне надо было сказать, что сравнение как между декларативными и процедурными языками?
                        0
                        Мне кажется, что древовидные итерации легче делать на XSLT.

                        По сравнению с чем?
                          0
                          По сравнению с процедурными языками.
                          Может вы попробуете вести беседу более развернуто, а не вопросами наскоками?
                            0
                            Ну так процедурными языками жизнь не ограничивается. Что мешает взять функциональные (или писать на гибридных в функциональном стиле)?
                              0
                              Ничего не мешает. Кто во что горазд!
                              Функциональные языки тоже круто.
                                +4
                                Вот поэтому я и спрашиваю — почему вы так легко утверждаете, что XSLT справляется с каким-то классом задач лучше всех. Я такой класс задач знаю один, и это — преобразование xml-xml.
                                  0
                                  Надеюсь вы не обидитесь, если скажу, что кроме xml, xslt еще может преобразовывать в html?
                                  Что тоже, по сути является XML.
                                    +4
                                    Только результат похуже получается, и с валидацией иногда проблемы.

                                    (и нет, html — это не xml, html (как и xml) — это sgml)
                                      0
                                      Не знаю какие проблемы с валидностью HTML на выходе XSLT, но дефолтные ангуляровские директивы сами по себе невалидны.
                                    0
                                    А еще XSLT умеет делать xml -> text или, например, xml -> pdf и вообще, если упороться, xslt удобен в преобразовании xml -> что-угодно. А еще xslt полон по Тьюрингу, что какбэ намекает ;)
                                      +1
                                      Одно дело умеет, другое дело — «справляется лучше всех».

                                      И да, если упороться, то можно применить его к любому преобразованию из XML, только удобным это не назовешь.
                0
                Дело в том, что данный модуль изначально был сделан для других целей, поэтому и доступен только в виде фильтра. Возможно, если у кого-то есть возможность и желание, то я с радостью приму ваши pull requests с поддержкой директив. :)
                  +4
                  Свят, свят, свят!

                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

                  Самое читаемое