Задача такая:
Модифицировать исходный xml, при этом
1) узлы, которые не подлежат явной обработке, просто копируются
2) должны сохрянятся как все пробелы внутри тэгов, так и форматирование атрибутов:
<Configurations>
<Configuration
Name="Debug|Pocket PC 2003 (ARMV4)"
OutputDirectory="$(PlatformName)\$(ConfigurationName)"
IntermediateDirectory="$(PlatformName)\$(ConfigurationName)"
ConfigurationType="1"
CharacterSet="1"
3) Проверять и изменять значения (атрибутов)
Пример 1. Для всех VisualStudioProject/Configurations/Configuration изменить атрибут Name="Debug|Win32" на Name="Debug|Pocket PC 2003 (ARMV4)", Name="Unicode Debug|Win32" на Name="Unicode Debug|Pocket PC 2003 (ARMV4)"
Пример 2. Для всех VisualStudioProject/Configurations/Configuration/Tool с атрибутом Name="VCCLCompilerTool" проверить атрибут PreprocessorDefinitions="_DEBUG;_WIN32_WCE=$(CEVER);UNDER_CE;$(PLATFORMDEFINES);WINCE;DEBUG;_WINDOWS;$(ARCHFAM);$(_ARCHFAM_);_UNICODE;UNICODE" и добавить элементы в список, если их там нет. Элементы списка разделены точкой с запятой.
Хочу по быстрому сконвертировать массу VC проектов под другую платформу, и поиметь еще скрипт для модификации проектов — к примеру, студия создает проект с OutputDirectory="$(PlatformName)\$(ConfigurationName)", а мне нужно OutputDirectory="$(ProjectDir)\..\out", ну и прочие подобные мелочи тюнить.
Сам с нуля почти неделю наверно ковырятся буду. Полностью готового xslt конечно не жду, накидайте просто заготовок и советов, что смотреть.
PS Использую XSLTPROC. Вроде еще где-то saxon стоял, но его неохота использовать. В принципе, при большом преимуществе, можно конечно и любой другой процессор поставить.
2 — внутренний текст узлов копируется, форматирование вроде никак, да и зачем? По анализу строк придется написать достаточно громоздкие XPath-запросы, инструменты см., к примеру, здесь: http://msdn.microsoft.com/en-us/library/ms256180.aspx.
Тоже самое, только покороче немного?
>2 — внутренний текст узлов копируется, форматирование вроде никак, да и зачем?
Глазами смотреть строчки с длиннющими значениями атрибутов удобнее. В основном на этапе отладки шаблонов.
А как параметр вставить вместо константы? В xsltproc передаю --param OutputDirectory mypath, хочу OutputDirectory поместить в значение атрибута.
Тут еще два вопроса — 1) подставить дефолтное значение, если не задан параметр, 2) выругаться и остановить преобразование, если параметр надо явно указывать.
И как задать значение атрибута, если он не существует? А если существует, то проверить его значение и изменить?
Следующий код только меняет значение и не работает, если атрибута нет вообще ;(
Здравствуйте, Marty, Вы писали:
M>И как задать значение атрибута, если он не существует? А если существует, то проверить его значение и изменить?
Атрибут итак создается в выходном дереве невзирая на то, был он во входном или нет.
M>Следующий код только меняет значение и не работает, если атрибута нет вообще
Так у вас процитированный шаблон просто не запускается на таких элементах, на нем запускается основной копирующий шаблон. Посмотрите внимательно на значение match-атрибута.
Здравствуйте, rsn81, Вы писали:
M>>Следующий код только меняет значение и не работает, если атрибута нет вообще R>Так у вас процитированный шаблон просто не запускается на таких элементах, на нем запускается основной копирующий шаблон. Посмотрите внимательно на значение match-атрибута.
Я примерно так и предполагал, просто у меня мозга не хватает, как сделать условную обработку. Я вижу только один путь — в лоб — сделать второй шаблон, в котором match будет проверять наличие атрибута, и если его нет — будет создавать. Но и в этом вариенте есть вопросы — как такой match записать Второй вариант — использовать xsl:if, но как им пользоваться, я пока не понял.
Здравствуйте, Marty, Вы писали:
M>>>Следующий код только меняет значение и не работает, если атрибута нет вообще R>>Так у вас процитированный шаблон просто не запускается на таких элементах, на нем запускается основной копирующий шаблон. Посмотрите внимательно на значение match-атрибута. M>Я примерно так и предполагал, просто у меня мозга не хватает, как сделать условную обработку. Я вижу только один путь — в лоб — сделать второй шаблон, в котором match будет проверять наличие атрибута, и если его нет — будет создавать.
Именно это и есть штатный способ в XSLT.
M>Но и в этом вариенте есть вопросы — как такой match записать
match="tag[not(@attribute)]"
M>Второй вариант — использовать xsl:if, но как им пользоваться, я пока не понял.
Аналогично. Но не стоит, условную логику лучше делать с помощью сопоставления шаблонов.
Здравствуйте, rsn81, Вы писали:
M>>Я примерно так и предполагал, просто у меня мозга не хватает, как сделать условную обработку. Я вижу только один путь — в лоб — сделать второй шаблон, в котором match будет проверять наличие атрибута, и если его нет — будет создавать. R>Именно это и есть штатный способ в XSLT.
Спасибо за подсказку. Стал понемногу "прозревать"
M>>Второй вариант — использовать xsl:if, но как им пользоваться, я пока не понял. R>Аналогично. Но не стоит, условную логику лучше делать с помощью сопоставления шаблонов.
Последний вопрос. Как сделать множественную обработку одного и того же узла? Проверить одно условие, модифицировать, проверить другое, снова модифицировать.
Не совсем понятно, как работает XSLT — каждый шаблон, применяемый к входному документу, формирует новый документ — дерево, к которому опять пробуется применить все шаблоны, и если ничего не подходит, то тогда обработка завершается? В принципе логично, но больно медленно на мой взгляд, и зациклится довольно просто. В этом случае просто набор шаблонов делаем и они последовательно будут применятся.
Если оно как-то по другому работает, то тогда ничего не понятно ;(
И еще вопросик
Как сделать match, чтобы в нем проверять значение атрибута тэга и значение атрибута родительского по отношению к первому, и если они не синхронизированны, то шаблон бы срабатывал?
Здравствуйте, Marty, Вы писали:
M> И еще вопросик M>Как сделать match, чтобы в нем проверять значение атрибута тэга и значение атрибута родительского по отношению к первому, и если они не синхронизированны, то шаблон бы срабатывал?
item[@attribute != parent::*/@attribute]
item[@attribute != ../@attribute]
Здравствуйте, Marty, Вы писали:
M>Последний вопрос. Как сделать множественную обработку одного и того же узла? Проверить одно условие, модифицировать, проверить другое, снова модифицировать.
Ага.
M>Не совсем понятно, как работает XSLT — каждый шаблон, применяемый к входному документу, формирует новый документ — дерево,
Ага.
M>к которому опять пробуется применить все шаблоны, и если ничего не подходит, то тогда обработка завершается?
А вот это — нет. Обычная потоковая обработка: есть входной поток, есть выходной поток — преобразователь читает входной поток и пишет выходной поток. Иными словами выходной поток преобразователь не читает.
Здравствуйте, rsn81, Вы писали:
R>Здравствуйте, Marty, Вы писали:
M>>Последний вопрос. Как сделать множественную обработку одного и того же узла? Проверить одно условие, модифицировать, проверить другое, снова модифицировать. R>Ага.
А поподробнее? Код, который я ниже привел, не работает, отрабатывает только последний шаблон.
Значит, надо все-таки как-то через xsl:if делать?
Не пойму как это записать. Однократно создать атрибут (с обновленным содержимым) могу, но не понимаю, как мне несколько раз изменить содержимое, хотя бы просто добавляя
<xsl:template match="/VisualStudioProject/Configurations/Configuration/Tool[@Name='VCCLCompilerTool']">
<xsl:copy>
<!-- Создаем базовое значение копированием исходного. А надо? -->
<xsl:attribute name="PreprocessorDefinitions"><xsl:value-of select="attribute::PreprocessorDefinitions"/></xsl:attribute>
<!-- Начинаем добавлять разные штуки -->
<xsl:if> test="not(contains(@PreprocessorDefinitions,'_CRT_SECURE_NO_WARNINGS'))">
<!-- Что тут написать, вот в чем вопрос -->
</xsl:if>
<xsl:if> test="not(contains(@PreprocessorDefinitions,'_CRT_SECURE_NO_DEPRECATE'))">
...
</xsl:if>
...
<!-- Обработать все прочие атрибуты как-то аналогично -->
<xsl:copy-of select="@*[local-name() != 'PreprocessorDefinitions' and остальные уже обработанные ]"/>
<xsl:apply-templates/>
</xsl:copy>
</xsl:template>
Вот это точно не работает, срабатывает только последнее.
M>>к которому опять пробуется применить все шаблоны, и если ничего не подходит, то тогда обработка завершается? R>А вот это — нет. Обычная потоковая обработка: есть входной поток, есть выходной поток — преобразователь читает входной поток и пишет выходной поток. Иными словами выходной поток преобразователь не читает.
Ну, как оно работает, понятно. Как писать шаблоны при такой архитектуре — вот это очень непонятно ;(
Здравствуйте, Marty, Вы писали:
M>>>Последний вопрос. Как сделать множественную обработку одного и того же узла? Проверить одно условие, модифицировать, проверить другое, снова модифицировать. R>>Ага. M>А поподробнее? Код, который я ниже привел, не работает, отрабатывает только последний шаблон. M>Значит, надо все-таки как-то через xsl:if делать? M>Не пойму как это записать. Однократно создать атрибут (с обновленным содержимым) могу, но не понимаю, как мне несколько раз изменить содержимое, хотя бы просто добавляя
Выше я вас неправильно понял. Несколько раз никак, это потоковая обработка: на момент записи в выходной поток вы должны принять окончательное решение в данном случае о значении атрибута.
M>
M><xsl:template match="/VisualStudioProject/Configurations/Configuration/Tool[@Name='VCCLCompilerTool']">
M><xsl:copy>
M> <!-- Создаем базовое значение копированием исходного. А надо? -->
M> <xsl:attribute name="PreprocessorDefinitions"><xsl:value-of select="attribute::PreprocessorDefinitions"/></xsl:attribute>
M> <!-- Начинаем добавлять разные штуки -->
M> <xsl:if> test="not(contains(@PreprocessorDefinitions,'_CRT_SECURE_NO_WARNINGS'))">
M> <!-- Что тут написать, вот в чем вопрос -->
M> </xsl:if>
M> <xsl:if> test="not(contains(@PreprocessorDefinitions,'_CRT_SECURE_NO_DEPRECATE'))">
M> ...
M> </xsl:if>
M> ...
M> <!-- Обработать все прочие атрибуты как-то аналогично -->
M> <xsl:copy-of select="@*[local-name() != 'PreprocessorDefinitions' and остальные уже обработанные ]"/>
M> <xsl:apply-templates/>
M></xsl:copy>
M></xsl:template>
M>
Определите на каждое определение препроцессора по переменной, значение которых определяйте с помощью xsl:if. В конце при определении атрибута в выходном потоке просто конкатенируйте значения всех переменных.
M>Вот это точно не работает, срабатывает только последнее.
Не, так не пойдет. Я же писал выше, что это потоковая обработка. Вот у вас и срабатывает только один шаблон из конкурирующих (возможно, срабатывают все, но результат записывается от последнего). Шаблоны нужны для обработки непересекающихся множеств элементов, а у вас из-за атрибута с определениями препроцессоров получилось пересечение. M>
M>>>к которому опять пробуется применить все шаблоны, и если ничего не подходит, то тогда обработка завершается? R>>А вот это — нет. Обычная потоковая обработка: есть входной поток, есть выходной поток — преобразователь читает входной поток и пишет выходной поток. Иными словами выходной поток преобразователь не читает. M>Ну, как оно работает, понятно. Как писать шаблоны при такой архитектуре — вот это очень непонятно ;(
Ага, по началу сложно.
Здравствуйте, rsn81, Вы писали:
R>Определите на каждое определение препроцессора по переменной, значение которых определяйте с помощью xsl:if. В конце при определении атрибута в выходном потоке просто конкатенируйте значения всех переменных.
Вроде бы если я объявлю переменные внутри xsl:if, то они не будут видны вне этого блока. С учетом того, что переменные это вовсе не переменные, а именованные константы, то я не представляю, как их использовать в моем случае ;(
M>>Ну, как оно работает, понятно. Как писать шаблоны при такой архитектуре — вот это очень непонятно ;( R>Ага, по началу сложно.
Вообще кошмар. Пробовал тут пользоваться DocBook XML'ем, мало что понял, но сложилось впечатление, что шаблоны там какие-то фанатики писали, нормальный человек такое не осилит
Здравствуйте, Marty, Вы писали:
M>Вроде бы если я объявлю переменные внутри xsl:if, то они не будут видны вне этого блока. С учетом того, что переменные это вовсе не переменные, а именованные константы, то я не представляю, как их использовать в моем случае ;(
Ага, только это не константы, а неизменяемые (immutable) переменные. Так что вы попробуйте наоборот, xsl:if внутри xsl:variable.
M>Вообще кошмар. Пробовал тут пользоваться DocBook XML'ем, мало что понял, но сложилось впечатление, что шаблоны там какие-то фанатики писали, нормальный человек такое не осилит
После привычки к императивным языкам любой функциональный язык будет сложным вне зависимости от синтаксиса.
Здравствуйте, Marty, Вы писали:
M>Вообще кошмар. Пробовал тут пользоваться DocBook XML'ем, мало что понял, но сложилось впечатление, что шаблоны там какие-то фанатики писали, нормальный человек такое не осилит
А что там сложно, не совсем понятно? Шаблоны Docbook XSL, конечно, не образец мегаправильности, но разобраться можно без труда.