Форматирование подстановочных знаков в XML и XSLT

Почему нет этой строки:

apply-templates select="*/* (под элементом "магазин" в файле XSLT)

применить полужирное форматирование к Blake2? Результат выглядит так:

Начало root в XSLT

«Начало шага 1» Алексис (Задача: Продажи) Сотрудник2 (Задача:) Blake2 «Шаг 1 выполнен»

Конец корня в XSLT

У меня вопрос, почему Blake2 не выделено жирным шрифтом? Это под элементом <employee>.

При изменении этой строки на *apply-templates select="*" Blake2 будет выделен жирным шрифтом. Что отличает это?

Вот XML-файл:

<?xml version="1.0"?> 
<?xml-stylesheet type="text/xsl" href="2.xsl" ?>

<root>
    <shop>
        <person> 
            <employee> 
                <name> Alexis </name> 
                <role> Manager </role> 
                <task> Sales </task> 
            </employee> 

            <employee>
                <name> Employee2 </name>
            </employee>
        </person>

        <employee>
            <name> Blake2 </name>
        </employee>

    </shop>

</root>

Вот файл XSLT:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="root"> 
<html><head></head> 
<body>
Start of root in XSLT <p/> <xsl:apply-templates /> <p/>

End of root in XSLT

</body> 
</html> 
</xsl:template> 

<xsl:template match="shop">
"Step 1 start"
<xsl:apply-templates select="*/*"/>
"Step 1 done" <p/>
</xsl:template> 

<xsl:template match="employee"> 
<b> <xsl:apply-templates select="name"/> </b> 
(Task: <xsl:apply-templates select="task"/>) 
<br></br> 
</xsl:template> 

</xsl:stylesheet>

person shadowz1337    schedule 10.06.2012    source источник


Ответы (2)


Ваш третий шаблон не выбирает никаких <employee> элементов в вашем документе. Он просто выбирает <employee> элементов, которые являются прямыми дочерними узлами текущего элемента. На корневом уровне это не относится ни к каким элементам, но поскольку второй шаблон вызывается <apply-templates> в первом элементе, а второй шаблон применяет шаблоны с (относительным!) Путем */* (т.е. шаблоны для любых элементов, которые дочерние элементы дочерних элементов текущего элемента) выбирается элемент <employee> в элементе <person>.

Второй элемент <employee> не является дочерним по отношению к дочернему элементу <shop>, а является прямым дочерним элементом элемента <shop>, и поэтому не выбирается */*, начиная с <shop>.

Когда вы меняете */* на *, выбираются оба элемента <employee>: второй выбирается, потому что он напрямую соответствует * (прямой дочерний элемент <shop>). * также выбирает <person>, и, поскольку для этого элемента не указан шаблон, будет выполнено поведение по умолчанию, что означает, что шаблоны будут применены к дочерним элементам <person>, который включает первый элемент <employee>.

person O. R. Mapper    schedule 10.06.2012
comment
Спасибо за ваше объяснение! Я понимаю, что вы сказали, но я думал, что xsl: template match сможет найти любой элемент в XML-файле, который соответствует ключевому слову (которое в данном случае является сотрудником)? Кроме того, я думал, что способ работы XML и XSLT заключается в том, что всякий раз, когда элемент в XML собирается быть выполнен, он сначала просматривает файл XSLT для любого соответствующего шаблона. Если он найдет подходящий шаблон для этого конкретного элемента, он выполнит его (как и шаблон магазина в моем вопросе). - person shadowz1337; 10.06.2012
comment
template просто соответствует элементам, которые соответствуют выражению XPath, как видно из текущего узла. Текущий узел - это любой узел, на котором тестируется шаблон - по умолчанию корневой элемент, а также любые дочерние узлы узлов, которые не соответствуют никакому шаблону, а также любые узлы, которые явно выбраны с помощью операторов <apply-templates>. Ничего из этого не применимо ко второму элементу <employee>; он не подчиняется поведению по умолчанию применения шаблонов к дочерним узлам, так как шаблон применяется к его родительскому узлу (<shop>), поэтому поведение по умолчанию переопределяется. - person O. R. Mapper; 10.06.2012
comment
(Продолжение) ..... Итак, когда были выполнены шаблоны apply-templates select = /, он находит магазин / человека / сотрудника и магазин / сотрудника / имя. Просто глядя на магазин / сотрудника / имя, я знаю, что мы получаем имя Blake2, но я не понимаю, что когда он нашел элемент сотрудника, не стал бы он искать соответствующий шаблон в файле XSLT, как это было бы обнаружите, что действительно существует шаблон сотрудника, и отформатирует ли Blake2, выделив его жирным шрифтом? Но вместо этого он пропустил это и сразу перешел к имени (дочернему узлу) сотрудника и просто вывел Blake2, не выделяя его жирным шрифтом ... - person shadowz1337; 10.06.2012
comment
Он никогда не находит магазин / сотрудника. Вы правильно поняли, что он находит только магазин / человека / сотрудника и магазин / сотрудника / имя. Таким образом, единственные <employee> элементы, которые он находит, - это два магазина / человека / сотрудника, и именно к ним применяется шаблон. Промежуточные элементы, упомянутые в XPath, не рассматриваются, учитываются только узлы, полученные в результате выражения XPath. - person O. R. Mapper; 10.06.2012
comment
Это гораздо проще: простое определение шаблона не гарантирует, что этот шаблон будет выбран для выполнения. Шаблоны выбираются для выполнения, если выдано xsl:apply-templates, которое выбирает узел, соответствующий этому шаблону, и нет других шаблонов с более высоким приоритетом или приоритетом импорта. Это включает в себя выбор шаблона для выполнения xsl:apply-templates, который находится в одном из встроенных шаблонов XSLT, которые выполняются всякий раз, когда не найдено другого подходящего шаблона. - person Dimitre Novatchev; 10.06.2012
comment
@ O.R.Mapper: вы вводите людей в заблуждение, говоря, что шаблон просто соответствует элементам, которые соответствуют выражению XPath, как видно из текущего узла. Код типа <xsl:apply-templates select="/root/shop/person/employee" /> вызовет создание экземпляра шаблона с match="employee" независимо от текущего узла. - person Borodin; 11.06.2012
comment
@Borodin: Код типа <xsl:apply-templates select="/root/shop/person/employee" /> приведет к тому, что элемент (ы) <employee>, выбранный выражением XPath, в какой-то момент станет текущим узлом (ами). - person O. R. Mapper; 11.06.2012
comment
@Borodin: Извините, только сейчас понял, к чему вы клоните: верно, когда выражение XPath проверяется на основе текущего узла, и это выражение XPath оказывается абсолютным, оно всегда будет возвращать один и тот же набор результатов независимо от текущего узел есть. Это заложено в природе абсолютных путей, поэтому я не хотел усложнять объяснения, но вы правы в том, что с абсолютным XPath этот шаблон будет применяться всегда. - person O. R. Mapper; 11.06.2012
comment
@ O.R.Mapper: абсолютное или относительное, не имеет значения. В вопросе шаблон с select="*/*" применяется, когда текущий элемент <shop>. Это выбирает первые два элемента <employee> (и вызывает соответствующий шаблон) и третий элемент <name> (который обрабатывается шаблоном по умолчанию). Ни при каких обстоятельствах родительские элементы - <person> и <employee> - не являются текущим узлом. match="XPath" вызывается, когда XPath может соответствовать текущему узлу из любой точки дерева, так, например, match="*/*" совпадает, когда текущий узел является любым элементом с родительским элементом. - person Borodin; 11.06.2012
comment
@Borodin: Правильно, как я уже писал выше - Промежуточные элементы, упомянутые в XPath, не учитываются, учитываются только узлы, полученные в результате выражения XPath. - person O. R. Mapper; 11.06.2012
comment
Я считаю, что вы ошибочно представляете это, но я не думаю, что здесь полезно заниматься этим. Нет никакого смысла в том, чтобы совпадение шаблона относилось к текущему узлу. Димитр объясняет это по-другому выше. - person Borodin; 11.06.2012

Во-первых, давайте посмотрим, как работает процессор xslt. Чтобы шаблоны в xslt были запущены / созданы / активированы, они должны «совпадать». Теперь спросите себя:

  • по чему они совпадают?
  • Что, например, представляет собой вещь, которая удовлетворяет match="root"?

По мере загрузки xslt входной документ или, скорее, его узел верхнего уровня попадает под его внимание. Ваш входной документ начинается с узла root, так что это то, что сначала входит в xslt. Это сразу удовлетворяет match="root". Простой.

Теперь что касается employee. Когда будет подобрана эта маленькая жемчужина?

Что ж, процессор xslt не собирается перебирать все возможные узлы и проверять, есть ли у него подходящий шаблон. Он делает это только для узлов, которым вы сообщаете.

  • Это то, что вы делаете с xsl:apply-templates select='...'.
  • Чтобы employee-узлы на входе были xslt-ed, их нужно выбрать где-нибудь в xsl:apply-templates.

Итак, что произошло? В вашем shop шаблоне вы выбираете */*, к которому нужно применить шаблоны, что означает «дочерние элементы текущего узла» («внуки», если хотите).

  • Текущий узел в шаблоне shop, равный shop, означает, что выбираются два узла сотрудников внутри узла сотрудников (*/* расширяется до person/employee).
  • Blake2 является родственником узла shop и не выбирается.
  • Изменение на * для select возвращает узлы person и employee, которые являются дочерними по отношению к узлу магазина.

Итак, откуда взялся Blake2 без полужирного шрифта? Ну, Blake2 без полужирного шрифта не связан с каким-либо шаблоном, который вы создали, он просто жертва поведения по умолчанию, где текстовые узлы, но не узлы элементов, копируются из входа в выход.


Вам есть чему поучиться, если вы действительно хотите использовать xslt. Я предлагаю начать с преобразования идентичности (ваш друг Google), а затем удалить некоторые элементы, предоставив для них пустой шаблон. Затем выполните однозначный перевод, скажем, все элементы заглавными буквами. Добавьте атрибуты. Попробуйте сделать более строгие совпадения, используя условия xpath ([this stuff]). Обратите внимание на более сложные структуры, такие как условные выражения и конструкции цикла. Погрузитесь в переменные, параметры и шаблон вызова. Используйте документ ().

Повеселись!

person jos    schedule 10.06.2012