Применение XSLT преобразований для конвертации XAML между различными платформами
Платформы WPF и Silverlight используют язык разметки XAML для описания элементов пользовательского интерфейса, шаблонов и стилей. Если вы разрабатываете одновременно под разные XAML платформы, то естественно, возникает желание иметь общие файлы разметки для этих платформ.Разметка в WPF и Silverlight очень схожа, но имеются досадные отличия, которые сильно осложняют ее шаринг. В нашей компании эта проблема была решена несколько лет назад в виде внутреннего инструмента, который называется WPF2SL.
WPF2SL слишком специфичен, чтобы быть полезным широкой публике, поэтому мы не планируем его публиковать. В этой статье я расскажу об особенностях XSLT преобразований применительно к разметке XAML и о некоторых сложностях и особенностях, с которыми мы столкнулись.Проект WPF2SL стартовал 4 года назад, когда мы решили создать линейки компонентов для платформ WPF и Silverlight. WPF контролы у нас были готовы раньше, поэтому возникла идея сделать шаринг разметки между платформами. В то время разрыв между разметкой WPF и Silverlight был больше, чем сейчас, потому что в Silverlight 3 не было implicit styles, markup extensions и были сильно ограничены байндинги.
Кстати, некоторые наши конкуренты пошли по другому пути. У них были сначала готовы Silverlight контролы и их линейка WPF контролов получена из априори урезанной платформы, поэтому они до сих пор в полной мере не используют всех возможностей WPF платформы.
Начнем с создания System.Xml.Xsl.XslCompiledTransform. Тут всё, как написано в MSDN. Однако следует помнить, что загрузка XSLT файла методом XslCompiledTransform.Load занимает много времени, потому что в этот момент в памяти будет создана временная сборка для конечного автомата, который описан в XSLT файле.
В одной из ранних версий WPF2SL на каждый входной XAML файл производилась полная инициализация с вызовом XslCompiledTransform.Load. Это сильно замедляло работу утилиты. В XslCompiledTransform загружается XSLT файл, содержащий описания преобразований для узлов и атрибутов исходного дерева. Преобразования в XSLT файле упорядочены по возрастанию приоритета. Правило с самым низким приоритетом — первое. Это копирующее правило.
Если для узла или атрибута не найдется более приоритетного правила, от будет скопирован.Отсутствие DynamicResource в Silverlight
Если просто заменить DynamicResource на StaticResource, полученная разметка будет содержать много ошибок, связанных с неверным следованием ресурсов, потому что StaticResource требует, чтобы ресурс был объявлен до его использования. Решением стало ручное упорядочивание ресурсов внутри файла. XSLT шаблон для замены DynamicResource на StaticResource выглядит так.
Вырезание узлов и атрибутов которые отсутствуют в Silverlight
Так как WPF разметка значительно богаче Silverlight разметки, нам придется вырезать узлы и атрибуты из XAML дерева. Это очень просто делается в XSLT.Пример вырезания атрибута:
За счет этого в WPF сложнее ошибиться в названии ключа в объявлении ресурса или в ссылке на ресурс.
Вернемся к преобразованию XAML. В Silverlight объектных ключей нет, поэтому
public override void WriteString (string text) { if (NamespacesReplacementTable.ContainsKey (text)) base.WriteString (NamespacesReplacementTable[text]); else base.WriteString (text);
… }
Этого наследника можно отдать в метод XslCompiledTransform.Transfrom (reader, writer) в качестве второго параметра. Перегруженый WriteString в соответствии с таблицей замен подменяет неймспейс при записи.Интеграция в процесс компиляции WPF2SL — это консольное приложение. В наших SL проектах на Pre-build event прописан вызов WPF2SL с соответствующими параметрами.Но тут не все просто как кажется. Практически у всех сейчас машины с многоядерными процессорами, на которых msbuild делает одновременную сборку сразу для нескольких проектов. WPF2SL в процессе работы создавала временные файлы в Temp. Поскольку их названия совпадали, возникал конфликт доступа. Проблема была решена добавлением ID процесса к названию файла.
Диагностика проблем в XSLT преобразовании К сожалению, удобного средства диагностики XSLT преобразований нет (по крайней мере, автору о них не известно). Когда какие-то из XSLT преобразований работают не так, как ожидается, самый действенный способ — итеративная модификация XSLT с анализом результатов. Если результат преобразования сильно отличается от ожидаемого, смело помещайте в коментарий половину XSLT файла; если всё еще не понятно, еще половину и так далее. Этот способ получил у нас название: «метод половинного комента».Описанный способ является универсальным для всех декларативных языков, в том числе и для XAML. Если не понятно, какой из шаблонов сформировал неверную строчку в выходном файле, можно временно в шаблон вписать строчку, которая позволит однозначно его идентифицировать.
Выводы XSLT преобразования хорошо работают в задаче конвертации XAML разметки между различными платформами, а .NET реализация XSLT преобразований XslCompiledTransform достаточно гибкая, производительная и расширяемая.Литература Сэл Мангано. XSLT. Сборник рецептов
