Недавно мне попался маленький проект, где я предложил использование 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

Комментарии (25)


  1. VasilioRuzanni
    14.10.2015 15:34
    +4

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

    но с модулем XSLT, view логику Angular можно вообще отдать XSLT
    И зачем нам тогда тут Angular? Он кроме view-логики тут ничего особенного и не дает.


    1. anjiJa
      14.10.2015 19:38
      +1

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

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


  1. k12th
    14.10.2015 15:42
    +3

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

    При всей любви к моему первому FP-языку — сейчас у нас есть не менее мощные и более человечные шаблонизаторы.


    1. grobitto
      16.10.2015 01:03

      xslt 2.0 появился почти 10 лет назад, по крайней мере на сервере


      1. k12th
        16.10.2015 10:22

        В одной-единственной, закрытой (и недешевой, ЕМНИП) имплементации. На практике все пользовались libxslt или биндингами к ней для своего языка. И не 10 лет назад, в 2009 еще не было (спека W3C была, имплементации не было).


        1. grobitto
          16.10.2015 11:04

          Saxon опенсорсный, пользуемся им с 2007


        1. 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.8


          1. k12th
            16.10.2015 11:19

            Насчет мощности, я, пожалуй, соглашусь, это я погорячился. Насчет дат спорить не буду, память уже не та, но в 2008 в яндексе и в 2009 в РИАНе мы почему-то не имели возможности использовать XSLT2.


  1. zolotyh
    14.10.2015 17:38
    +4

    Я так ни одной причины не увидел, чтобы использовать AngularJS совместно с XSLT. Зато вижу много недостатков:

    1. Громоздкий синтаксис
    2. Проблемы с производительностью
    3. Слабая поддержка XSLT разработчиками
    4. Трудно найти специалистов

    Убежден, что чем меньше разных технологий используется в проекте, тем лучше и спокойнее. В AngularJS для повторного использования кода есть директивы. Оптимальнее пользоваться ими, так как они уже есть из коробки.


    1. anjiJa
      14.10.2015 20:00

      Данный фильтр используется только тогда, когда есть спец задание для XSLT, то есть задачи, где XSLT справляется лучше всего.
      Иногда такие задачки случаются, и я был несказанно рад, когда увидел этот фильтр. Вот и решил поделится некоторыми решениями против «подводных каменей» при использовании этого фильтра.


      1. Razaz
        14.10.2015 20:52
        +3

        Можно пример таких задач?


        1. anjiJa
          14.10.2015 21:54

          Вот как раз и пример задачи:

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

          Ну и примерное решение, в конце данного топика, видео из вк.


          1. lair
            14.10.2015 22:07
            +1

            А с чем вы сравнивали, что утверждаете, что XSLT справляется лучше всего?


            1. anjiJa
              14.10.2015 22:26

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


              1. lair
                14.10.2015 23:25

                Мне кажется, что древовидные итерации легче делать на XSLT.

                По сравнению с чем?


                1. anjiJa
                  14.10.2015 23:58

                  По сравнению с процедурными языками.
                  Может вы попробуете вести беседу более развернуто, а не вопросами наскоками?


                  1. lair
                    14.10.2015 23:59

                    Ну так процедурными языками жизнь не ограничивается. Что мешает взять функциональные (или писать на гибридных в функциональном стиле)?


                    1. anjiJa
                      15.10.2015 00:04

                      Ничего не мешает. Кто во что горазд!
                      Функциональные языки тоже круто.


                      1. lair
                        15.10.2015 00:08
                        +4

                        Вот поэтому я и спрашиваю — почему вы так легко утверждаете, что XSLT справляется с каким-то классом задач лучше всех. Я такой класс задач знаю один, и это — преобразование xml-xml.


                        1. anjiJa
                          15.10.2015 00:16

                          Надеюсь вы не обидитесь, если скажу, что кроме xml, xslt еще может преобразовывать в html?
                          Что тоже, по сути является XML.


                          1. lair
                            15.10.2015 00:26
                            +4

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

                            (и нет, html — это не xml, html (как и xml) — это sgml)


                        1. mx2000
                          16.10.2015 07:18

                          А еще XSLT умеет делать xml -> text или, например, xml -> pdf и вообще, если упороться, xslt удобен в преобразовании xml -> что-угодно. А еще xslt полон по Тьюрингу, что какбэ намекает ;)


                          1. lair
                            16.10.2015 11:07
                            +1

                            Одно дело умеет, другое дело — «справляется лучше всех».

                            И да, если упороться, то можно применить его к любому преобразованию из XML, только удобным это не назовешь.


  1. dannyzubarev
    14.10.2015 18:52

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


  1. DenimTornado
    15.10.2015 21:53
    +4

    Свят, свят, свят!