Для циклов и применять-шаблоны

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

И другой вопрос - это нормально, когда вы просто говорите "apply-templates", когда у вас не будет других потомков элемента, где вы его пишете. В моем случае в шаблоне, который соответствует корню документа, я говорю apply-templates. Затем он находит электронные книги, которые являются его единственным потомком, но у меня может быть элемент "книги", который различает "обычные" книги и электронные книги, тогда он просто перечисляет данные о характере книг. Тогда мне нужно было бы написать apply-templates select="ebooks", если бы я просто хотел, чтобы книги были в моем окончательном документе. Так это тот случай, когда все зависит от того, насколько хорошо вы знаете свой документ?

Спасибо, вот мой код (это только для практики):

XML:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="ebooks.xsl"?>
<ebooks>
    <ebook>
        <title>Advanced Rails Recipes: 84 New Ways to Build Stunning Rails Apps</title>
        <authors>
            <author><name>Mike Clark</name></author>
        </authors>
        <pages>464</pages>
        <isbn>978-0-9787-3922-5</isbn>
        <programming_language>Ruby</programming_language>
        <date>
            <year>2008</year>
            <month>5</month>
            <day>1</day>
        </date>
        <publisher>The Pragmatic Programmers</publisher>
    </ebook>
    ...

XSLT:

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

    <xsl:template match="/">
        <html>
            <head>
                <title>Library</title>
            </head>
            <body>
                <xsl:apply-templates />            
            </body>
        </html>    
    </xsl:template>

    <xsl:template match="ebooks">
        <h1>Ebooks</h1>
        <xsl:apply-templates>
            <xsl:sort select="title"/>
        </xsl:apply-templates>
    </xsl:template>

    <xsl:template match="ebook">
        <h3><xsl:value-of select="title"/></h3>
        <xsl:apply-templates select="date" />

        <xsl:for-each select="authors/author/name">
            <b><xsl:value-of select="."/>,</b>
        </xsl:for-each>
    </xsl:template>

    <xsl:template match="date">
        <table border="1">
            <tr>
                <th>Day</th>
                <th>Month</th>
                <th>Year</th>
            </tr>
            <tr>
                <td><xsl:value-of select="day"/></td>
                <td><xsl:value-of select="month"/></td>
                <td><xsl:value-of select="year"/></td>
            </tr>
        </table>
    </xsl:template>

</xsl:stylesheet>

4 ответа

Решение

Этот вопрос является немного спорным, но вот мой взгляд на него.

Я не вижу четкой линии, когда использовать циклы и когда использовать шаблоны.

Я бы сказал, что вы должны избегать for-each как можно чаще в пользу apply-templates,

С помощью for-each делает вашу программу более сложной, добавляя уровни вложенности, и также невозможно повторно использовать код внутри for-each блок. С помощью apply-templates будет (когда все сделано правильно) генерировать более гибкий и модульный XSLT.

С другой стороны: если вы пишете таблицу стилей с ограниченной сложностью и повторное использование или модуляция не являются проблемой, использование for-each может быть быстрее и легче следовать (для читателя / сопровождающего). Так что это отчасти вопрос личных предпочтений.

В вашем случае я бы нашел это элегантно:

<xsl:template match="ebook">
  <!-- ... -->
  <xsl:apply-templates select="authors/author" />
  <!-- ... -->
</xsl:template>

<xsl:template match="authors/author">
  <b>
    <xsl:value-of select="name"/>
    <xsl:if test="position() &lt; last()">,</xsl:if>
  </b>
</xsl:template>

На ваш другой вопрос

И другой вопрос, это нормально, просто сказать apply-templates когда вы знаете, что не будет других потомков элемента, где вы пишете это.

Когда вы знаете, что в этом элементе никогда не будет детей, пишите apply-templates бессмысленно.

Если все сделано правильно, XSLT обладает способностью гибко справляться с изменяющимся вводом. Если вы ожидаете, что в какой-то момент могут быть дети, apply-templates не повредит.

Просто apply-templates без select является довольно неопределенным с точки зрения того, какие (т.е. все они) и в каком порядке (то есть порядок входных документов) будут обрабатываться. Таким образом, вы можете получить либо узлы обработки, которые вы никогда не хотели обрабатывать, либо узлы, которые вы уже обрабатывали ранее.

Поскольку нельзя написать разумный шаблон для неизвестных узлов, я стараюсь избегать неопределенных apply-templates и просто адаптировать мою таблицу стилей при изменении ввода.

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

С помощью <xsl:for-each> ни в коем случае не вредно, если точно знать, как <xsl:for-each> обрабатывается.

Проблема в том, что многим новичкам в XSLT, имеющим опыт в императивном программировании, требуется <xsl:for-each> в качестве замены "петли" в их любимом PL и думают, что это позволяет им выполнять невозможное - например, увеличивать счетчик или любую другую модификацию уже определенного <xsl:variable>,

Одно обязательное использование <xsl:for-each> в XSLT 1.0 это изменить текущий документ - это часто необходимо для того, чтобы иметь возможность использовать key() Функция в документе, отличном от текущего исходного XML-документа, например, для эффективного доступа к таблице поиска, которая находится в его собственном XML-документе.

С другой стороны, используя <xsl:template> а также <xsl:apply-templates> гораздо мощнее и элегантнее.

Вот некоторые из наиболее важных различий между двумя подходами:

  1. xsl:apply-templates гораздо богаче и глубже xsl:for-each даже потому, что мы не знаем, какой код будет применяться к узлам выбора - в общем случае этот код будет отличаться для разных узлов списка узлов.

  2. Код, который будет применен, может быть написан после xsl:apply template s был написан и людьми, которые не знают оригинального автора.

Реализация функций высшего порядка (HOF) в библиотеке FXSL в XSLT была бы невозможна, если бы в XSLT не было <xsl:apply-templates> инструкция.

другой вопрос, нормально ли просто сказать apply-templates, когда вы (k) теперь, когда не будет других потомков элемента, где вы пишете

<xsl:apply-templates/>

это сокращение для:

<xsl:apply-templates select="child::node()"/>

Даже если есть другие дочерние элементы текущего узла, о которых вам все равно, вы все равно можете использовать короткие <xsl:apply-templates> и иметь другой шаблон, как это:

<xsl:template match="*"/>

Этот шаблон игнорирует ("удаляет") любой элемент. Вы должны переопределить его с более конкретными шаблонами (в XSLT, как правило, более конкретные шаблоны имеют более высокий приоритет и выбираются для обработки по менее конкретным шаблонам, соответствующим одному и тому же узлу):

<xsl:template match="ebook">
  <!-- Necessary processing here -->
</xsl:template>

Я обычно не пользуюсь <xsl:template match="*"/> но я использую другой шаблон, который соответствует (и игнорирует) каждый текстовый узел:

 <xsl:template match="text()"/>

Это обычно имеет тот же эффект, что и при использовании <xsl:template match="*"/> из-за способа, которым XSLT обрабатывает узлы, для которых нет соответствующего шаблона. В любом таком случае XSLT использует свои встроенные шаблоны в так называемой "обработке по умолчанию".

Результатом обработки XSLT по умолчанию поддерева, укорененного в элементе, является вывод конкатенации (в порядке документа) всех потомков текстового узла этого элемента.

Следовательно, предотвращение вывода любого текстового узла с помощью <xsl:template match="text()"/> имеет тот же (нулевой) результат вывода, что и выход для обработки элемента с помощью <xsl:template match="*"/>,

Резюме:

  1. Шаблоны и <xsl:apply-templates> Инструкция заключается в том, как XSLT реализует и имеет дело с полиморфизмом.

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

Ссылка: Смотрите всю эту ветку: http://www.stylusstudio.com/xsllist/200411/post60540.html

Вообще я согласен с ответом Димитра. Основная причина для того, чтобы советовать новичкам использовать xsl: apply-templates вместо xsl: for-each, состоит в том, что как только они освоятся с xsl: apply-templates, им не составит труда выбрать между двумя конструкциями, тогда как до тех пор, пока они не получат этот опыт, они будут использовать xsl: for-each неуместно.

Основное преимущество xsl: apply-templates перед for-each заключается в том, что код лучше адаптируется к изменяющимся структурам документа и требованиям обработки. Трудно продать эту выгоду людям, которые просто хотят взломать код и не заботятся о том, каким будет мир через три года, но это очень реальная выгода.

Это часто читать о xsl:for-each не совсем необходимо в XSLT, но только в некоторых случаях. Обычно вы должны быть в состоянии использовать xsl:apply-templates путь.

Например, ваше преобразование может быть легко адаптировано без xsl:for-each, изменить ebook шаблон следующим образом:

<xsl:template match="ebook">
    <h3><xsl:value-of select="title"/></h3>
    <xsl:apply-templates select="date" />
    <xsl:apply-templates select="authors/author/name"/>
</xsl:template>

и добавив этот:

<xsl:template match="name">
    <b><xsl:value-of select="."/>,</b>
</xsl:template>

Чтобы ответить на ваши вопросы:

Я не вижу четкой линии, когда использовать циклы и когда использовать шаблоны.

В XSLT различие известно как стиль "push" и "pull", о котором вы можете прочитать что-то хорошее @ IBM developerWorks и @ XML.com.

Моё правило о том, что используйте петли только тогда, когда вы не представляете, как от них избавиться:)).

другой вопрос, нормально ли просто сказать apply-templates, когда вы (k) теперь, когда не будет других потомков элемента, где вы пишете

Когда ты сказал"

<xsl:apply-templates />

Вы просто указываете процессору применять шаблоны ко всем дочерним узлам текущего узла контекста. Так что все зависит от того, хочешь ты этого или нет:). У вас могут быть разные дети, и все же нужно применять шаблоны к любому из них. Это действительно зависит от ситуации.

Когда вы используете только <xsl:apply-templates /> Обычно вам нужно обратить внимание на то, как будут применяться встроенные правила, и, в конце концов, при необходимости закрыть их.

Например, в вашем случае вы могли бы также использовать:

<xsl:template match="ebook">
    <h3><xsl:value-of select="title"/></h3>
    <xsl:apply-templates />
</xsl:template>

<xsl:template match="isbn|programming_language|publisher|pages|title"/>

Надеюсь это поможет.

Другие вопросы по тегам