В каком порядке выполняются шаблоны в документе XSLT и соответствуют ли они исходному XML или буферизованному выходу?
вот что всегда озадачивало меня в XSLT:
- в каком порядке выполняются шаблоны, и
- когда они выполняются, совпадают ли они с (a) исходным исходным XML или (b) текущим выходом XSLT до этого момента?
пример:
<person>
<firstName>Deane</firstName>
<lastName>Barker</lastName>
</person>
вот фрагмент XSLT:
<!-- Template #1 -->
<xsl:template match="/">
<xsl:value-of select="firstName"/> <xsl:value-of select="lastName"/>
</xsl:template>
<!-- Template #2 -->
<xsl:template match="/person/firstName">
First Name: <xsl:value-of select="firstName"/>
</xsl:template>
два вопроса по этому поводу:
- Я предполагаю, что шаблон #1 будет выполняться первым. Я не знаю, почему я предполагаю это - это просто потому, что он появляется сначала в документе?
- будет ли выполняться шаблон №2? Он соответствует узлу в исходном XML, но к тому времени, когда мы доберемся до этого шаблона (предполагая, что он работает вторым), узел "firstName" не будет в выходном дереве.
Итак," более поздние " шаблоны связаны с тем, что произошло в "более ранних" шаблонах, или они работают с исходным документом, не обращая внимания на то, что было преобразовано "до" их? (Все эти слова заключены в кавычки, потому что мне трудно обсуждать временные проблемы, когда я действительно мало знаю, как определяется порядок шаблонов в первую очередь...)
В приведенном выше примере у нас есть шаблон, который соответствует корневому узлу ( " / " ), который-когда он выполняется-по существу удалил все узлы из вывода. В этом случае, будет ли это упреждать все другие шаблоны от выполнения, так как нет ничего, чтобы соответствовать после того, как этот первый шаблон полный?
до этого момента я был обеспокоен тем, что более поздние шаблоны не выполняются, потому что узлы, с которыми они работали, не отображаются в выходных данных, но как насчет обратного? Может ли" более ранний " шаблон создать узел, с которым "более поздний" шаблон может что-то сделать?
на том же XML, что и выше, рассмотрим этот XSL:
<!-- Template #1 -->
<xsl:template match="/">
<fullName>
<xsl:value-of select="firstName"/> <xsl:value-of select="lastName"/>
</fullName>
</xsl:template>
<!-- Template #2 -->
<xsl:template match="//fullName">
Full Name: <xsl:value-of select="."/>
</xsl:template>
шаблон #1 создает новый узел с именем "имя". Шаблон №2 совпадает на том же узле. Будет ли шаблон №2 выполняться, потому что узел "fullName" существует в выходных данных к тому времени, когда мы перейдем к шаблону #2?
Я понимаю, что я глубоко не знаю о "Дзен" XSLT. На сегодняшний день мои таблицы стилей состоят из шаблона, соответствующего корневому узлу, а затем полностью процедурны оттуда. Я устал делать это. Я бы предпочел на самом деле правильно понять XSLT, поэтому мой вопрос.
4 ответов:
мне нравится ваш вопрос. Вы очень четко формулируете то, чего еще не понимаете. Вам просто нужно что-то связать вместе. Моя рекомендация заключается в том, что Вы читаете "как работает XSLT", глава, которую я написал, чтобы решить именно те вопросы, которые вы задаете. Я хотел бы услышать, если это связывает вещи вместе для вас.
менее формально, я попытаюсь ответить на каждый из ваших вопросов.
- в каком порядке делать шаблоны выполнить, и
- когда они выполняются, совпадают ли они с (a) исходным исходным XML или (b) сила тока на выходе XSLT в том, что точка?
в любой заданной точке обработки XSLT есть, в некотором смысле, два контекста, которые вы идентифицируете как (a) и (b): где вы находитесь в источник дерева, и где вы находитесь в результате дерево. Где вы находитесь в исходном дереве называется текущего узла. Оно можно изменить и перейти все вокруг исходного дерева, как вы выбираете произвольные наборы узлов для обработки с помощью XPath. Однако, концептуально, вы никогда не "прыгать вокруг" дерева результатов таким же образом. Процессор XSLT строит его упорядоченным образом; сначала он создает корневой узел дерева результатов; затем он добавляет дочерние элементы, создавая результат в порядке документа (сначала глубина). [Ваш пост мотивирует меня снова взять мою визуализацию программного обеспечения для экспериментов XSLT...]
порядок правила шаблонов в таблице стилей никогда не имеют значения. Вы не можете сказать, просто взглянув на таблицу стилей, в каком порядке будут созданы правила шаблона, сколько раз будет создано правило или даже будет ли оно вообще. (
match="/"исключение; вы всегда можете знать, что он будет срабатывать.)я предполагаю, что шаблон #1 будет сначала выполнить. Я не знаю, почему я предположим, что это-это просто потому, что это появляется первым в списке документ?
Неа. Он будет называться первым, даже если вы поместите его последним в документ. Порядок правил шаблона никогда не имеет значения (за исключением случая ошибки, когда у вас есть несколько правил шаблона с одинаковым приоритетом, совпадающим с одним и тем же узлом; даже тогда это необязательно для разработчика, и вы никогда не должны полагаться на такое поведение). Он называется первым, потому что первое, что всегда происходит всякий раз, когда вы запускаете процессор XSLT-это виртуальный вызов
<xsl:apply-templates select="/"/>. Один виртуальный вызов создает все дерево. Снаружи ничего не происходит. Вы можете настроить или" настроить " поведение этой инструкции, определив правила шаблона.будет ли выполняться шаблон №2? Он соответствует узлу в исходном XML, но к тому времени мы доберемся до этого шаблон (предполагая, что он работает второй), узел" firstName " не будет находиться в дерево вывода.
шаблон #2 (ни любые другие правила шаблона) будет никогда не срабатывает, если у вас есть
<xsl:apply-templates/>позвоните куда-нибудь вmatch="/"правило. Если у вас их нет, то никаких правил шаблона, кромеmatch="/"будет срабатывать. Подумайте об этом так: для запуска правила шаблона он не может просто соответствовать узлу во входных данных. Он должен соответствовать узлу, который вы выбрали для ).в конце концов, вы получаете древовидный стек рекурсивных вызовов одной и той же" функции" (
<xsl:apply-templates>). И эта древовидная структура изоморфна к вашему фактическому результату. Не все понимают это или думали об этом таким образом; это потому, что мы нет никаких эффективных инструментов визуализации...еще.шаблон #1 создает новый узел "полное имя". Шаблон №2 соответствует тот же самый узел. Будет Шаблон #2 выполнить, потому что узел " fullName существует в выводе к тому времени, когда мы перейти к шаблону №2?
Неа. Единственный способ сделать цепочку обработки-явно настроить ее таким образом. Создайте переменную, например,
$tempTree, который содержит новый<fullName>элемент, а затем процесс это, такой<xsl:apply-templates select="$tempTree">. Для этого в XSLT 1.0 необходимо обернуть ссылку на переменную функцией расширения (например,exsl:node-set()), но в XSLT 2.0 он будет работать так же, как есть.независимо от того, обрабатываете ли вы узлы из исходного исходного дерева или во временном дереве, которое вы создаете, в любом случае вам нужно явно указать, какие узлы вы хотите обработать.
мы не рассмотрели, как XSLT получает все свое неявное поведение. Вы также должны поймите встроенные правила шаблона. Я пишу таблицы стилей все время, которые даже не включают явное правило для корневого узла (
match="/"). Вместо этого я полагаюсь на встроенное правило для корневых узлов (применяю шаблоны к дочерним узлам), которое совпадает со встроенным правилом для узлов элементов. Таким образом, я могу игнорировать большие части ввода, пусть процессор XSLT автоматически пересекает его, и только когда он сталкивается с узлом, который меня интересует, я сделаю что-то особенное. Или я мог бы написать единственное правило, которое копирует все рекурсивно (называемое преобразованием идентичности), переопределяя его только там, где это необходимо, чтобы внести инкрементные изменения во входные данные. После того, как вы прочитали "как работает XSLT", ваше следующее задание-найти "преобразование идентичности".я понимаю, что я глубоко невежественны о "Дзен" XSLT. На сегодняшний день мой стилей состоял из шаблон, соответствующий корневому узлу, затем полностью процессуального оттуда. Я устала этот. Я бы скорее на самом деле понимаю XSLT правильно, отсюда и мой вопрос.
я аплодирую вам. Теперь пришло время принять "красную таблетку": читать "как работает XSLT"
Шаблоны всегда совпадение в исходном XML. Таким образом, порядок не имеет большого значения, если только 2 или более шаблонов не совпадают с одним и тем же узлом(узлами). В этом случае, несколько контр-интуитивно, правило с последние запускается соответствующий шаблон.
в вашем 1-м примере шаблон #1 выполняется, потому что при запуске обработки входного xml он начинается с корня, и это единственный шаблон в вашей таблице стилей, который соответствует корневому элементу. Даже если он был 2-м в таблице стилей, он все равно будет работать 1-м.
в этом примере шаблон 2 не будет выполняться, поскольку вы уже обработали корневой элемент с помощью шаблона 1, и после корневого элемента больше нет элементов для обработки. Если вы хотите обрабатывать другие элементы с помощью дополнительных шаблоны вы должны изменить его.
<xsl:template match="/"> <xsl:apply-templates/> </xsl:template>Также обратите внимание, что этот пример ничего не выведет, так как в текущем контексте (корень) нет элемента firstName, только элемент person, поэтому он должен быть:
<xsl:template match="/"> <xsl:value-of select="person/firstName"/> <xsl:value-of select="person/lastName"/> </xsl:template>мне легче думать, что вы шагаете через xml, начиная в корне и ищет шаблон, который соответствует этому элементу, а затем следует этим инструкциям для создания вывода. XSLT преобразует входной документ в выходной, поэтому выходной doucument пуст в начале преобразования. Выход не используется как часть преобразования, это просто выход из него.
в вашем 2-м примере шаблон #2 не будет выполняться, потому что шаблон запускается против входного xml, а не выходного.
ответ Эвана в основном хороший.
однако одна вещь, которая, похоже, отсутствует, - это возможность "вызывать" куски кода без какого-либо сопоставления. Это позволит - по крайней мере, по мнению некоторых людей-значительно улучшить структурирование.
Я сделал небольшой пример в попытке показать, что я имею в виду.
<xsl:template match="/" name="dotable"> <!-- Surely the common html part could be placed somewhere else --> <!-- the head and the opening body --> <html> <head><title>Salary table details</title></head> <body> <!-- Comments are better than nothing --> <!-- but that part should really have been somewhere else ... --> <!-- Now do what we really want here ... this really is making the table! --> <h1>Salary Table</h1> <table border = "3" width="80%"> <xsl:for-each select="//entry"> <tr> <td><xsl:value-of select="name" /></td> <td><xsl:value-of select="firstname" /></td> <td><xsl:value-of select="age" /></td> <td><xsl:value-of select="salary" /></td> </tr> </xsl:for-each> </table> <!-- Now close out the html --> </body> </html> <!-- this should also really be somewhere else --> <!-- This approach works, but leads to horribly monolithic code --> <!-- Further - it leads to templates including code which is strictly --> <!-- not relevant to them. I've not found a way round this yet --> </xsl:template>однако, после того, как вы немного поиграли, и сначала использовали подсказку, что если есть два совпадающих шаблона, последний один в коде будет выбран, а затем реструктурировать мой код (не все показано здесь), я достиг этого, который, кажется, работает, и, надеюсь, генерирует правильный код, а также отображение нужных данных -
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- <?xml version="1.0"?>--> <xsl:template name="dohtml"> <html> <xsl:call-template name="dohead" /> <xsl:call-template name="dobody" /> </html> </xsl:template> <xsl:template name="dohead"> <head> <title>Salary details</title> </head> </xsl:template> <xsl:template name="dobody"> <body> <xsl:call-template name="dotable" /> </body> </xsl:template> <xsl:template match="/entries" name="dotable"> <h1>Salary Table</h1> <table border = "3" width="80%"> <xsl:for-each select="//entry"> <tr> <td><xsl:value-of select="name" /></td> <td><xsl:value-of select="firstname" /></td> <td><xsl:value-of select="age" /></td> <td><xsl:value-of select="salary" /></td> </tr> </xsl:for-each> </table> </xsl:template> <xsl:template match="/" name="main"> <xsl:call-template name="dohtml" /> </xsl:template>[прокрутите код выше вверх-вниз, если вы не можете увидеть все это]
то, как это работает, является основным шаблоном всегда соответствует - соответствует /
это куски кода - шаблоны - которые называемый.
Это означает, что теперь это не возможно, чтобы соответствовать другой шаблон, но возможно, чтобы соответствовать явно на именованном узле, который в этом случае является узлом самого высокого уровня в xml - вызываемых записях.
небольшая модификация кода привела к приведенному выше примеру.
Comments