Условное отображение с помощью XSLT ..?

#html #xml #xslt

#HTML #xml #xslt

Вопрос:

ниже приведен мой XML-код —

 <topic no=1>
<desc>......</desc>
<references>
    <book>XSLT Essentials</book>
    <chapter>11</chapter>
    <book>XSLT Cookbook</book>
    <chapter>10</chapter>
</references>
</topic>    

<topic no=2>
<desc>......</desc>
<references>
    <book>Javascript in 10 mins</book>
    <chapter>11</chapter>
</references>
</topic>

<topic no=3>
<desc>......</desc>
<references>
    <book></book>
    <chapter></chapter>
</references>
</topic>
  

Сначала я объясняю ситуацию.

Вывод HTML только в отношении тега references, который я ищу, выглядит так —

для темы no =1

 <table><tr>
  <td>Book</td><td>Chapter</td></tr>
<tr>
  <td>XSLT Essentials</td><td>11</td></tr>
<tr>
  <td>XSLT Cookbook</td><td>10</td></tr>
</table>
  

……

для темы no = 2

 <table><tr>
  <td>Book</td><td>Chapter</td></tr>
<tr>
  <td>Javascript in 10 mins</td><td>11</td></tr>
</table>
  

……

для темы no = 3 Нет таблицы, поскольку ссылки не используются.

Это пример, поэтому в первом случае XML-файл содержит только 2 ссылки, но в некоторых случаях эти ссылки могут даже достигать 12, а в некоторых случаях 0 (ноль).

Хорошего дня — Джон 🙂

Ответ №1:

Это, вероятно, одно из самых простых и коротких решений. Обратите внимание, что явные условные инструкции вообще не используются:

 <xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

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

 <xsl:template match="/*[topic]">
       <xsl:apply-templates/>
 </xsl:template>

 <xsl:template match="topic/references[book/text()]">
    <table>
     <tr><td>Book</td><td>Chapter</td></tr>
   <xsl:apply-templates select="book"/>
    </table>
 </xsl:template>

 <xsl:template match="book">
  <tr>
   <td><xsl:value-of select="."/></td>
   <td><xsl:value-of select=
       "following-sibling::chapter[1]"/>
   </td>
  </tr>
 </xsl:template>
</xsl:stylesheet>
  

при применении к предоставленному входному тексту (исправлено, чтобы стать правильно сформированным XML-документом):

 <t>
    <topic no="1">
        <desc>......</desc>
        <references>
            <book>XSLT Essentials</book>
            <chapter>11</chapter>
            <book>XSLT Cookbook</book>
            <chapter>10</chapter>
        </references>
    </topic>
    <topic no="2">
        <desc>......</desc>
        <references>
            <book>Javascript in 10 mins</book>
            <chapter>11</chapter>
        </references>
    </topic>
    <topic no="3">
        <desc>......</desc>
        <references>
            <book></book>
            <chapter></chapter>
        </references>
    </topic>
</t>
  

получен желаемый, правильный результат:

 <table>
   <tr>
      <td>Book</td>
      <td>Chapter</td>
   </tr>
   <tr>
      <td>XSLT Essentials</td>
      <td>11</td>
   </tr>
   <tr>
      <td>XSLT Cookbook</td>
      <td>10</td>
   </tr>
</table>
<table>
   <tr>
      <td>Book</td>
      <td>Chapter</td>
   </tr>
   <tr>
      <td>Javascript in 10 mins</td>
      <td>11</td>
   </tr>
</table>
  

Объяснение: Правильное использование шаблонов сопоставления с образцом.

Правило Димитра: всякий раз, когда у вас есть явная условная инструкция ( <xsl:if> , <xsl:choose> , <xsl:when> , и т.д.), Это, вероятно, означает, что вы не использовали соответствие шаблону шаблона, как следовало бы.

Чтобы узнать больше, почему полезно полностью избегать условных инструкций: прочитайте этот важный курс Pluralsight:

Тактические шаблоны проектирования в .NET: поток управления

Зоран Хорват

Комментарии:

1. Большое спасибо … :). Скорее, я ждал вашего ответа. Так любезно с вашей стороны .. 🙂 и то, как вы отвечаете с объяснением, — лучший способ учиться (и учить тоже ;)). Это вы разработали это, я имею в виду XSLT ..? Еще раз большое спасибо .. 🙂

2. @John: Добро пожаловать. Да, XSLT — это быстрый, элегантный, мощный функциональный язык. Я не был среди создателей XSLT 1.0 / 2.0, но XSLT был моим хобби и иногда использовался в моих профессиональных задачах в течение последних 11 лет.

3. @Dimitre, молодец! Я знаю, что XQuery здесь не запрашивается, но вы упомянули короткие решения, а этот XQuery довольно короткий: //book[text()]/..!element table{<tr><td>Book</td><td>Chapter</td></tr>,book!<tr><td>{text()}</td><td>{following::*[1]/text()}</td></tr>}

4. @Gunther, да, Xpath 3.0 в целом и оператор simple-mapping ! придают нам исключительную выразительность и элегантность.

Ответ №2:

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

 <xsl:param name="topic" select="'1'"/>
  

(1 здесь является параметром по умолчанию)

Затем, чтобы получить все соответствующие разделы для параметра, это просто случай выполнения следующего:

 <xsl:apply-templates select="//topic[@no=$topic][references/book != '']"/>
  

При этом также будут игнорироваться темы, на которые нет ссылок.

Итак, учитывая следующий XSLT

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:param name="topic" select="'1'"/>

   <xsl:template match="/">
      <xsl:if test="//topic[@no=$topic][references/book != '']">
         <table>
            <tr>
               <td>Book</td>
               <td>Chapter</td>
            </tr>
            <xsl:apply-templates select="//topic[@no=$topic][references/book != '']"/>
         </table>
      </xsl:if>
   </xsl:template>

   <xsl:template match="topic">
      <xsl:apply-templates select="references"/>
   </xsl:template>

   <xsl:template match="references">
      <xsl:apply-templates select="book"/>
   </xsl:template>

   <xsl:template match="book">
      <tr>
         <td>
            <xsl:value-of select="."/>
         </td>
         <td>
            <xsl:value-of select="following-sibling::chapter[1]"/>
         </td>
      </tr>
   </xsl:template>
</xsl:stylesheet>
  

При применении к следующему входному XML

 <topics>
   <topic no="1">
      <desc>......</desc>
      <references>
         <book>XSLT Essentials</book>
         <chapter>11</chapter>
         <book>XSLT Cookbook</book>
         <chapter>10</chapter>
      </references>
   </topic>
   <topic no="2">
      <desc>......</desc>
      <references>
         <book>Javascript in 10 mins</book>
         <chapter>11</chapter>
      </references>
   </topic>
   <topic no="3">
      <desc>......</desc>
      <references>
         <book/>
         <chapter/>
      </references>
   </topic>
</topics>
  

Выводится следующее

 <table>
   <tr>
      <td>Book</td>
      <td>Chapter</td>
   </tr>
   <tr>
      <td>XSLT Essentials</td>
      <td>11</td>
   </tr>
   <tr>
      <td>XSLT Cookbook</td>
      <td>10</td>
   </tr>
</table>
  

Когда параметр изменяется на 2, выводится следующее:

 <table>
   <tr>
      <td>Book</td>
      <td>Chapter</td>
   </tr>
   <tr>
      <td>Javascript in 10 mins</td>
      <td>11</td>
   </tr>
</table>
  

Когда параметр изменяется на 3, ничего не выводится.

Комментарии:

1. Тим — Большое спасибо. Я думаю, что было бы легко и эффективно добавить атрибут со значением Y или N в <references> тег вместо <topic> тега.

Ответ №3:

Сделайте это так:

 <xsl:template match="content">

    <xsl:apply-templates select="references" />
</xsl:template>
<xsl:template match="references">
          <xsl:if test="book != '']">
           <table>
           <tr><td>Book</td><td>Chapter</td></tr>
           <xsl:apply-templates select="book" />
         </table>
          </xsl:if>
</xsl:template>
<xsl:template match="book">
    <tr><td><xsl:value-of select="." /></td><td><xsl:value-of select="following-sibling::chapter[1]" /></td></tr>
</xsl:template>
  

протестировано, и это работает 😉

Комментарии:

1. Я использовал //following-sibling::* вместо того, что вы дали… Теперь работает в соответствии с моими потребностями… Большое спасибо … 🙂

2. @kim — Это работает, но только тогда, когда используются ссылки. Если у меня нет ссылок, тогда рисуйте таблицу… пожалуйста, прочитайте мой вопрос еще раз и посмотрите, что я написал жирным шрифтом .. 🙂