如何使用xsl:foreach从非嵌套元素中选择变量

时间:2016-03-22 15:00:07

标签: xml xslt

我输入了一些电影的XML。我需要使用XSLT转换将“屏幕1”中的信息输出到表中。该表应显示“屏幕1”的三个放映时间以及正在播放的电影,类似于下表:

╔════════════╦═════════════╗
║Showing Time║ Film        ║
╠════════════╬═════════════╣
║ 1:30pm     ║ The Revenant║
║ 5:00pm     ║ The Revenant║
║ 8:30pm     ║ The Revenant║
╚════════════╩═════════════╝

这是我的XML,虽然我不知道它是否以XSLT的最佳方式编写:

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="Assignment1.xsl"?>
<Cinema>
  <Name> Old Street Cinema</Name>
  <Address>23 Old Street, Oxford</Address>
  <Telephone>01865 123456</Telephone>
  <Owner>John Arbuttle</Owner>
  <Showings>
    <Showing>
      <Films>
        <Film>
          <Screen>1</Screen>
          <Name>The Revenant</Name>
          <Usher>Sarah Eccles</Usher>
        </Film>
        <Film>
          <Screen>2</Screen>
          <Name>Zoolander 2</Name>
          <Usher>Ari Ventaro</Usher>
        </Film>
        <Film>
          <Screen>3</Screen>
          <Name>Star Wars the Force Awakens</Name>
          <Usher>Jake Calcas</Usher>
        </Film>
      </Films>
    </Showing>
  </Showings>
  <ScreenTimes>
    <Time name="Afternoon">1:30pm</Time>
    <Time name="Early Evening">5:00pm</Time>
    <Time name="Late Evening">8:30pm</Time>
  </ScreenTimes>
</Cinema>

这是未完成的XSL文件:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/Cinema">
    <html>
      <body>
        <h1>The Old Street Cinema </h1>
        <h2>Screen 1</h2>
        <table border="1">
          <tr>
            <th>Showing Time</th>
            <th>Film</th>
          </tr>
          <xsl:for-each select="ScreenTimes">
            <tr>
              <td><xsl:value-of select="Time" /></td>
            </tr>
          </xsl:for-each>
      </table>
      </body>
    </html>
  </xsl:template>
</xsl:stylesheet>

我的问题是:当元素没有嵌套在一起时,如何使用XSLT将显示时间和电影名称放在表格中。

2 个答案:

答案 0 :(得分:0)

你的问题的答案是双重的:

  • 第一种可能性:使用游戏时间的索引Time作为电影片名的索引:

<强> XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/Cinema">
    <html>
      <body>
        <h1>The Old Street Cinema </h1>
        <h2>Screen 1</h2>
        <table border="1">
          <tr>
            <th>Showing Time</th>
            <th>Film</th>
          </tr>
          <xsl:apply-templates />
      </table>
      </body>
    </html>
  </xsl:template>

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

  <xsl:template match="ScreenTimes">
    <xsl:for-each select="Time">
      <xsl:variable name="pos" select="position()" />
      <tr>
        <td><xsl:value-of select="text()" /></td>
        <td><xsl:value-of select="/Cinema/Showings/Showing/Films/Film[$pos]/Name/text()" /></td>
      </tr>
    </xsl:for-each>
  </xsl:template>    
</xsl:stylesheet>
  • 第二种可能性:重构XML文件以将播放时间合并到电影数据中,以便XML文件如下所示:

<强> XSLT:

<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="a.xslt"?>
<Cinema>
  <Name> Old Street Cinema</Name>
  <Address>23 Old Street, Oxford</Address>
  <Telephone>01865 123456</Telephone>
  <Owner>John Arbuttle</Owner>
  <Showings>
    <Showing>
      <Films>
        <Film>
          <Screen>1</Screen>
          <Name>The Revenant</Name>
          <Usher>Sarah Eccles</Usher>
          <Playtime>Afternoon</Playtime>
        </Film>
        <Film>
          <Screen>2</Screen>
          <Name>Zoolander 2</Name>
          <Usher>Ari Ventaro</Usher>
          <Playtime>Early Evening</Playtime>
        </Film>
        <Film>
          <Screen>3</Screen>
          <Name>Star Wars the Force Awakens</Name>
          <Usher>Jake Calcas</Usher>
          <Playtime>Late Evening</Playtime>
        </Film>
      </Films>
    </Showing>
  </Showings>
  <ScreenTimes>
    <Time name="Afternoon">1:30pm</Time>
    <Time name="Early Evening">5:00pm</Time>
    <Time name="Late Evening">8:30pm</Time>
  </ScreenTimes>
</Cinema>

并且XSLT文件将相关数据提取到HTML表中,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/Cinema">
    <html>
      <body>
        <h1>The Old Street Cinema </h1>
        <h2>Screen 1</h2>
        <table border="1">
          <tr>
            <th>Showing Time</th>
            <th>Film</th>
          </tr>
          <xsl:apply-templates />
      </table>
      </body>
    </html>
  </xsl:template>

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

  <xsl:template match="ScreenTimes">
    <xsl:for-each select="Time">
      <xsl:variable name="time" select="@name" />
      <tr>
        <td><xsl:value-of select="text()" /></td>
        <td><xsl:value-of select="/Cinema/Showings/Showing/Films/Film[Playtime = $time]/Name" /></td>
      </tr>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

这远非完美,因为每个游戏时间最多可能有不止一部电影。你必须'反转'for-each循环来实现这一点 - 意味着迭代电影并关联时间。但是,如果没有更多信息,我无法给出更好的答案。

答案 1 :(得分:0)

以下样式表:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/Cinema">
    <xsl:variable name="film" select="Showings/Showing/Films/Film[1]/Name" />
    <html>
        <body>
            <h1>The Old Street Cinema </h1>
            <h2>Screen 1</h2>
            <table border="1">
                <tr>
                    <th>Showing Time</th>
                    <th>Film</th>
                </tr>
                <xsl:for-each select="ScreenTimes/Time">
                    <tr>
                        <td><xsl:value-of select="." /></td>
                        <td><xsl:value-of select="$film" /></td>
                    </tr>
                </xsl:for-each>
            </table>
        </body>
    </html>
</xsl:template>

</xsl:stylesheet>

应用于您的输入,将返回(显示为已渲染):

enter image description here

注意

  • 屏幕#是硬编码的(屏幕名称也是如此);
  • 删除ShowingFilms包装器
  • 可以简化您的XML
  • 您的XML假定所有屏幕的筛选时间都相同。