Для циклов и шаблонов заявок

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

И еще один вопрос: нормально ли просто утверждать шаблоны, когда вы сейчас, что не будут другие дети того элемента, где вы его пишете. В моем случае в шаблоне, который соответствует корню документа, я говорю 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>

Ответы

Ответ 1

Этот вопрос немного аргументирован, но вот мой подход к нему.

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

Я бы сказал, что вы стремитесь избегать 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 довольно неспецифичен, как в терминах (т.е. все из них), так и в каком порядке (т.е.: порядок ввода документа) будут обрабатываться. Таким образом, вы можете в конечном итоге либо обрабатывать узлы, которые вы никогда не хотели обработать, или node, которые вы уже обработали ранее.

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

Ответ 2

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

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

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

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

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

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

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

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

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

другой вопрос - это нормально для просто скажем, применять шаблоны, когда вы (k) теперь что не будут другие дети элемент, в котором вы его пишете

<xsl:apply-templates/>

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

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

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

<xsl:template match="*"/>

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

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

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

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

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

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

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

Резюме:

  • Шаблоны и инструкция <xsl:apply-templates> - это то, как XSLT реализует и занимается полиморфизмом.

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

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

Ответ 3

Общеизвестно, что читать 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, когда вы (k) теперь не будете другими дочерними элементами элемента, в котором вы его пишете.

Когда вы говорите

<xsl:apply-templates />

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

Когда вы используете только <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"/>

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

Ответ 4

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

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