Для циклов и применять-шаблоны - PullRequest
15 голосов
/ 14 июня 2011

Я недавно начал использовать 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 ]

9 голосов
/ 14 июня 2011

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

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

Я бы сказал, что вы должны стараться избегать 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 и просто адаптировать мою таблицу стилей при изменении ввода.

5 голосов
/ 14 июня 2011

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

Использование <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 было написано и люди, которые не знают оригинального автора.

В библиотеке FXSL реализация функций высшего порядка (HOF) в 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

4 голосов
/ 14 июня 2011

Обычно читать о 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"/>

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

3 голосов
/ 14 июня 2011

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

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

...