Создайте две таблицы из xml с использованием xslt на основе атрибута узла, который меньше целого значения

#html #xml #xslt #xpath

#HTML #xml #xslt #xpath

Вопрос:

Я создал XML-файл, содержащий мои 15 любимых фильмов, которые имеют несколько атрибутов. XML-файл можно увидеть ниже:

 <?xml version="1.0" encoding="utf-8" ?>
<?xml-stylesheet href="movies.xslt" type="text/xsl" ?>

<AllMovies>
  <movie id="01">
    <title>Wizard of Oz</title>
    <director>King Vidor</director>
    <year>1939</year>
    <genre>
      <g1>Classics, </g1>
      <g2>Sci-Fi, </g2>
      <g3>Fantasy</g3>
    </genre>
    <link>https://www.rottentomatoes.com/m/the_wizard_of_oz_1939/</link>
  </movie>
  <movie id="02">
    <title>The Third Man</title>
    <director>Carol Reed</director>
    <year>1949</year>
    <genre>
      <g1>Classics, </g1>
      <g2>Mystery, </g2>
      <g3>Suspense</g3>
    </genre>
    <link>https://www.rottentomatoes.com/m/the-third-man/</link>
  </movie>
  <movie id="03">
    <title>Citizen Kane</title>
    <director>Orson Welles</director>
    <year>1941</year>
    <genre>
      <g1>Classics, </g1>
      <g2>Drama, </g2>
      <g3>Mystery, </g3>
      <g4>Suspense</g4>
    </genre>
    <link>https://www.rottentomatoes.com/m/citizen_kane/</link>
  </movie>
  <movie id="04">
    <title>The Godfather</title>
    <director>Francis Ford Coppola</director>
    <year>1972</year>
    <genre>
      <g1>Suspense, </g1>
      <g2>Drama</g2>
    </genre>
    <link>https://www.rottentomatoes.com/m/godfather/</link>
  </movie>
  <movie id="05">
    <title>Inside Out</title>
    <director>Pete Docter</director>
    <year>2015</year>
    <genre>
      <g1>Comedy, </g1>
      <g2>Animation, </g2>
      <g3>Children</g3>
    </genre>
    <link>https://www.rottentomatoes.com/m/inside_out_2015/</link>
  </movie>
  <movie id="06">
    <title>E.T. The Extra-Terrestrial</title>
    <director>Steven Spielberg</director>
    <year>1982</year>
    <genre>
      <g1>Sci-Fi, </g1>
      <g2>Children, </g2>
      <g3>Fantasy</g3>
    </genre>
    <link>https://www.rottentomatoes.com/m/et_the_extraterrestrial/</link>
  </movie>
  <movie id="07">
    <title>Toy Story 3</title>
    <director>Lee Unkrich</director>
    <year>2010</year>
    <genre>
      <g1>Animation, </g1>
      <g2>Comedy, </g2>
      <g3>Children, </g3>
      <g4>Sci-Fi</g4>
    </genre>
    <link>https://www.rottentomatoes.com/m/toy_story_3/</link>
  </movie>
  <movie id="08">
    <title>Selma</title>
    <director>Ava DuVernay</director>
    <year>2015</year>
    <genre>
      <g1>Biopic, </g1>
      <g2>History</g2>
    </genre>
    <link>https://www.rottentomatoes.com/m/selma/</link>
  </movie>
  <movie id="09">
    <title>Zootopia</title>
    <director>Bryon Howard</director>
    <year>2016</year>
    <genre>
      <g1>Animation, </g1>
      <g2>Comedy, </g2>
      <g3>Action, </g3>
      <g4>Adventure</g4>
    </genre>
    <link>https://www.rottentomatoes.com/m/zootopia/</link>
  </movie>
  <movie id="10">
    <title>Taxi Driver</title>
    <director>Martin Scorsese</director>
    <year>1976</year>
    <genre>
      <g1>Drama, </g1>
      <g2>Mystery, </g2>
      <g3>Suspense</g3>
    </genre>
    <link>https://www.rottentomatoes.com/m/taxi_driver/</link>
  </movie>
  <movie id="11">
    <title>The Dark Knight</title>
    <director>Christopher Nolan</director>
    <year>2008</year>
    <genre>
      <g1>Action, </g1>
      <g2>Crime, </g2>
      <g3>Drama</g3>
    </genre>
    <link>https://www.rottentomatoes.com/m/the_dark_knight</link>
  </movie>
  <movie id="12">
    <title>The Girl with The Dragon Tattoo</title>
    <director>David Fincher</director>
    <year>2011</year>
    <genre>
      <g1>Drama, </g1>
      <g2>Mystery, </g2>
      <g3>Suspense</g3>
    </genre>
    <link>https://www.rottentomatoes.com/m/the_girl_with_the_dragon_tattoo/</link>
  </movie>
  <movie id="13">
    <title>The Last King of Scotland</title>
    <director>Kevin Macdonald</director>
    <year>2006</year>
    <genre>
      <g1>Drama, </g1>
      <g2>Thriller</g2>
    </genre>
  </movie>
  <movie id="14">
    <title>The Hurt Locker</title>
    <director>Kathryn Gigelow</director>
    <year>2009</year>
    <genre>
      <g1>Action, </g1>
      <g2>Adventure, </g2>
      <g3>Drama</g3>
    </genre>
  </movie>
  <movie id="15">
    <title>Aliens</title>
    <director>James Cameron</director>
    <year>1986</year>
    <genre>
      <g1>Horror, </g1>
      <g2>Thriller, </g2>
      <g3>Adventure, </g3>
      <g4>Sci-Fi</g4>
    </genre>
  </movie>
</AllMovies>
  

На основе приведенного выше XML-файла я смог создать шаблон, который отображает все данные в форматированной таблице. Что я хотел бы сделать, так это создать две таблицы на основе <year> атрибута в каждом узле movie. Так, например, я хотел бы, чтобы каждый фильм, выпущенный до 2005 года, был в первой таблице, затем оставьте пробел и добавьте еще одну таблицу, содержащую все фильмы 2005 года и новее. Я пытался использовать оператор if в корневом шаблоне и шаблоне «movie» и не могу заставить его работать.

Ниже приведен мой код xslt, пытающийся решить проблему:

 <?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>

  <xsl:output method="html" indent="yes"/>
  <xsl:template match="/">
    <html>
      <head>
        <title>Assignment 1</title>
        <style>
          body{
          font-family: Arial, Helvetica, sans-serif
          }

          table{
          background-color: #d4ecfb;
          border-collapse: collapse;
          margin-left: 10px;
          }

          th, tr, td{
          border: 1px solid black;
          }

          #id{
          width:3%;
          text-align: left;
          padding-left: 3px;
          }

          #title{
          width:25%;
          text-align: left;
          }

          #director{
          width:20%;
          text-align: left;
          }

          #year{
          width: 5%;
          text-align: left;
          }

          #headers{
          background-color: #FF69B4;
          }

          td{
          padding-left: 3px;
          }
        </style>
      </head>
      <body>
        <h1>Top 15 Favorite Movies</h1>
       <!-- amp;< is the hex for < and amp;> is for the > symbol-->
       <table>
          <tr id="headers">
            <th id="id">ID</th>
            <th id="title">Title</th>
            <th id="director">Director</th>
            <th id="year">Year</th>
            <th id="genre">Genre</th>
            <th id="link">Link</th>
          </tr>
         <xsl:if test="year amp;< 2005">
            <xsl:apply-templates select="AllMovies/movie">
              <xsl:sort select="title" order="ascending"/>
            </xsl:apply-templates>
         </xsl:if>
         <tr></tr>
         <xsl:if test="year amp;> 2005">
           <xsl:apply-templates select="AllMovies/movie">
             <xsl:sort select="title" order="ascending"/>
           </xsl:apply-templates>
         </xsl:if>
        </table>
      </body>
    </html>
  </xsl:template>

  <xsl:template match="AllMovies/movie">
    <tr>
      <td>
        <xsl:value-of select="@id"/>
      </td>
      <td>
        <xsl:value-of select="title"/>
      </td>
      <td>
        <xsl:value-of select="director"/>
      </td>
      <td>
        <xsl:value-of select="year"/>
      </td>
      <td>
        <xsl:value-of select="genre"/>
      </td>
      <td>
        <xsl:value-of select="link"/>
      </td>
    </tr>
  </xsl:template>
</xsl:stylesheet>
  

Ниже приведено изображение моего вывода с помощью инструкции if:
Не работает оператор if

И это изображение является результатом без инструкции if, где вся информация отображается в одной таблице: Одна таблица со всеми отображаемыми данными

Заранее благодарю вас за помощь.

Ответ №1:

Вам нужно переместить условие в year , которое проверяет наличие year элемента, относящегося к узлу документа верхнего уровня, чтобы оно было частью фактического xsl:apply-templates предложения select

т.е. вместо этого….

  <xsl:if test="year amp;< 2005">
     <xsl:apply-templates select="AllMovies/movie">
        <xsl:sort select="title" order="ascending"/>
    </xsl:apply-templates>
 </xsl:if>
  

Сделайте это….

 <xsl:apply-templates select="AllMovies/movie[year amp;< 2005]">
   <xsl:sort select="title" order="ascending"/>
</xsl:apply-templates>
  

Обратите внимание, что для другого шаблона вам нужно будет выполнить amp;>= , а не просто amp;>

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

1. Что действительно интересно, так это то, как я так близко подобрался к решению с помощью различных методов, которые я пробовал, но так и не получил его. Спасибо, Тим, ты здорово помог.

Ответ №2:

Если вы хотите иметь две отдельные таблицы, тогда ваш основной шаблон должен быть структурирован в соответствии с этими строками:

 <xsl:template match="/AllMovies">
    <html>
        <head>
            <title>Assignment 1</title>
            <style>
                /*removed for brevity*/
            </style>
        </head>
        <body>
            <xsl:variable name="header">
                <tr id="headers">
                    <th id="id">ID</th>
                    <th id="title">Title</th>
                    <th id="director">Director</th>
                    <th id="year">Year</th>
                    <th id="genre">Genre</th>
                    <th id="link">Link</th>
                </tr>
            </xsl:variable> 
            <h1>Before 2005</h1>
            <table>
                <xsl:copy-of select="$header"/>
                <xsl:apply-templates select="movie[year amp;< 2005] ">   
                    <xsl:sort select="title" order="ascending"/>
                </xsl:apply-templates>
            </table>
            <h1>2005 and later</h1>
            <table>
                <xsl:copy-of select="$header"/>
                <xsl:apply-templates select="movie[year >= 2005] "> 
                    <xsl:sort select="title" order="ascending"/>
                </xsl:apply-templates>
            </table>
        </body>
    </html>
</xsl:template>
  

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

1. Спасибо, Майкл, ваше решение сработало, но мне пришлось изменить «movie [год выпуска amp; < 2005] » на полное расположение «AllMovies / movie [год выпуска …..».

2. Вы, вероятно, пропустили, что у меня есть <xsl:template match="/AllMovies"> .