【问题标题】:XSLT to html tableXSLT 到 html 表
【发布时间】:2014-05-27 22:01:08
【问题描述】:

我有一个电影的 XML 文件,下面是其中的两个示例——mediaList 中有许多电影元素,我希望我的 XSLT 将其转换为 HTML 表格供其他人查看。

<mediaList>
 <movie id="1299349" dateCreated="2014-04-11" lastModified="2014-04-12">
    <title>
        <titleSort>Armageddon</titleSort>
    </title>
    <director>
        <personTerm type="code" authority="lccn">no98124072</personTerm>
        <personTerm type="text">Bay, Michael, 1964-</personTerm>
    </director>
    <genre>Action and adventure</genre>
    <genre>Disaster</genre>
    <writer>
        <personTerm type="code" authority="lccn">n91119795</personTerm>
        <personTerm type="text">Hensleigh, Jonathan</personTerm>
    </writer>
    <writer>
        <personTerm type="code" authority="lccn">no98124254</personTerm>
        <personTerm type="text">Abrams, J. J. (Jeffrey Jacob), 1966-</personTerm>
    </writer>
    <screenplay href="http://endeavor.flo.org/vwebv/holdingsInfo?bibId=578717">PN1997 .A73 1997a</screenplay>
    <language>
        <languageTerm type="code" authority="iso639-2">eng</languageTerm>
        <languageTerm type="text">English</languageTerm>
    </language>
    <year>1998</year>
    <callNumber href="http://endeavor.flo.org/vwebv/holdingsInfo?bibId=1299349">[DVD] PN1995.9 .A3 B39 1999</callNumber>
</movie>
<movie id="1324917" dateCreated="2014-04-13">
    <title>
        <titleSort>Police Story 2</titleSort>
    </title>
    <director>
        <personTerm type="code" authority="lccn">no96039667</personTerm>
        <personTerm type="text">Cheng, Long, 1954-</personTerm>
    </director>
    <genre>Martial arts</genre>
    <genre>Buddy</genre>
    <writer>
        <personTerm type="code" authority="lccn">no96039667</personTerm>
        <personTerm type="text">Cheng, Long, 1954-</personTerm>
    </writer>
    <writer>
        <personTerm type="code" authority="lccn">no2005066079</personTerm>
        <personTerm type="text">Tang, Edward, 1946-</personTerm>
    </writer>
    <language>
        <languageTerm type="code" authority="iso639-3">yue</languageTerm>
        <languageTerm type="text">Yue Chinese</languageTerm>
    </language>
    <year>1988</year>
    <callNumber href="http://endeavor.flo.org/vwebv/holdingsInfo?bibId=1324917">[DVD] PN1995.9 .A3 C52 2006</callNumber>
</movie>
</Medialist

现在,我的 XSLT 看起来像这样:

 <?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output method="html"/>
    <xsl:template match="/">
        <html>
            <head>
                <link rel="stylesheet" type="text/css" href="mediaList.css"/>
                <title/>
            </head>
            <body>
                <table>

                    <tr>
                        <th>Title</th>
                        <th>Director</th>
                        <th>Genre</th>
                        <th>Writer</th>
                        <th>Screenplay</th>
                        <th>Source</th>
                        <th>Language</th>
                        <th>Year</th>
                        <th>Call Number</th>
                    </tr>

                    <xsl:for-each select="mediaList/movie">
                        <tr>
                            <td>
                                <xsl:apply-templates select="./title"/>
                            </td>
                            <td>
                                <xsl:apply-templates select="./director/personTerm[@type='text']"/>
                            </td>
                            <xsl:choose>
                                <xsl:when test="count(./genre) > 1">
                                    <td>
                                        <xsl:call-template name="recursiveGenre">
                                            <xsl:with-param name="numberG" select="count(./genre)"/>
                                        </xsl:call-template>
                                        <xsl:value-of select="./genre[1]"/>
                                    </td>
                                </xsl:when>
                                <xsl:otherwise>
                                    <td>
                                        <xsl:value-of select="./genre"/>
                                    </td>
                                </xsl:otherwise>
                            </xsl:choose>

                            <xsl:choose>
                                <xsl:when test="count(./writer) > 1">
                                    <td>
                                        <xsl:call-template name="recursive">
                                            <xsl:with-param name="number" select="count(./writer)"/>
                                        </xsl:call-template>
                                        <xsl:value-of select="writer[1]/personTerm[@type='text']"/>
                                    </td>
                                </xsl:when>
                                <xsl:otherwise>
                                    <td>
                                        <xsl:value-of select="writer/personTerm[@type='text']"/>
                                    </td>
                                </xsl:otherwise>
                            </xsl:choose>

                            <td>
                                <xsl:apply-templates select="screenplay"/>
                            </td>
                            <td>
                                <xsl:apply-templates select="source"/>
                            </td>
                            <td>
                                <xsl:value-of select="./language/languageTerm[@type='text']"/>
                            </td>
                            <td>
                                <xsl:value-of select="./year"/>
                            </td>
                            <td>
                                <xsl:apply-templates select="callNumber"/>
                            </td>
                        </tr>
                    </xsl:for-each>
                </table>
            </body>
        </html>
    </xsl:template>

    <xsl:template match="title">
        <xsl:if test="./nonSort">
            <xsl:value-of select="./nonSort"/>
            <xsl:text> </xsl:text>
        </xsl:if>
        <xsl:value-of select="./titleSort"/>
    </xsl:template>

    <xsl:template name="recursive">
        <xsl:param name="number"/>
        <xsl:if test="$number > 1">
            <xsl:value-of select="writer[$number]/personTerm[@type='text']"/>
            <xsl:text> / </xsl:text>
            <xsl:call-template name="recursive">
                <xsl:with-param name="number" select="$number - 1"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>

    <xsl:template name="recursiveGenre">
        <xsl:param name="numberG"/>
        <xsl:if test="$numberG > 1">
            <xsl:value-of select="genre[$numberG]"/>
            <xsl:text> / </xsl:text>
            <xsl:call-template name="recursiveGenre">
                <xsl:with-param name="numberG" select="$numberG - 1"/>
            </xsl:call-template>
        </xsl:if>
    </xsl:template>

    <xsl:template match="screenplay | source | callNumber">
        <a>
            <xsl:attribute name="href">
                <xsl:value-of select="./@href"/>
            </xsl:attribute>
            <xsl:value-of select="."/>
        </a>
    </xsl:template>

</xsl:stylesheet>

因此,虽然这个有点笨拙,但它工作正常 - 它会生成一个由标题锚定的漂亮表格,并在后续单元格中提供有关每个标题的相关信息。

但我真正想做的是以不同的方式显示数据。例如,如果我想按流派对标题进行分组,以便输出如下所示:

     <table>

                    <tr>
                        <th>Genre</th>
                        <th>Title</th>
                        <th>Director</th>
                        <th>Writer</th>
                        <th>Screenplay</th>
                        <th>Source</th>
                        <th>Language</th>
                        <th>Year</th>
                        <th>Call Number</th>
                    </tr>
    <tr><td>Action and Adventure</td>
<td>Some Action/Comedy Title</td>
...
</tr>
<tr><td>Action and Adventure</td>
<td>Some Action/Comedy Title - The Return</td>
...
</tr>
<tr><td>Action and Adventure</td>
<td>Revenge of the Action/Comedy Title</td>
...
</tr>
<tr><td>Comedy</td>
<td>Some Action/Comedy Title</td>
...
<tr><td>Comedy</td>
<td>Some Action/Comedy Title - The Return</td>
</tr>
<tr><td>Comedy</td>
<td>Revenge of the Action/Comedy Title</td>
...
</tr>
</table>

我还希望能够通过任何其他“重复值”列来查看它,例如语言(许多电影元素都有不止一种语言元素)、作家(同样的交易)

有没有办法通过在单个 XSLT 文件中包含所有类型的转换来在单击时重新生成表格?对于每种“类型”的表,我是否需要单独的 XSLT 文件?有没有更好的方法来做我正在做的事情?

我们将不胜感激任何和所有的建议——我在这方面还是很陌生,我正在上我的第一堂编程课,我们正在学习 XML/XSLT。

【问题讨论】:

  • 您好,我刚刚看到是XSL 2.0。到目前为止,我只使用 1.0 - 抱歉,我无法真正帮助分组。请尝试使用 而不是 (stackoverflow.com/questions/6342902/…)。用于板上的分组搜索。在 XSLT 1.0 中有 Muenchian 分组——我认为在 XSLT 2.0 中有一个更简单的解决方案。最好的问候,彼得

标签: xml xslt


【解决方案1】:

我将在此处提供一个 XSLT 1.0 解决方案(在 XSLT 2.0 中仍然可以使用),因为该解决方案相当通用且易于添加新的分组参数。

在 XSLT 1.0 中,您使用一种称为Muenchian Grouping 的技术进行分组,并涉及创建查找节点的键。对于“流派”,您可以像这样定义键:

<xsl:key name="genre" match="genre" use="." />

对于语言,你可以这样做

<xsl:key name="language" match="language" use="languageTerm[@type='text']" />

然而,在这个特定的例子中,如果键的名称与元素名称完全匹配会更容易,并且“use”属性只是“.”,所以对于这个答案,键的定义如下

<xsl:key name="languageTerm" match="languageTerm[@type='text']" use="." />

对于您的 XSLT,您还可以定义一个参数来说明您想要分组的内容

<xsl:param name="groupBy" select="'genre'" />

这里的值需要匹配键名(以及被匹配元素的名称)。

然后,要获得每个组的不同值,表达式如下:

<xsl:apply-templates select="movie//*[local-name() = $groupBy]
                             [generate-id() = generate-id(key($groupBy, .)[1])]" />

(这是第二个xpath条件,它是分组子句)。

在与此匹配的模板中,这实际上是您的标题行,然后您可以获得“组”的所有 movie 元素,就像这样

<xsl:apply-templates select="key($groupBy, .)/ancestor::movie" />

在这种情况下,这是完整的 XSLT:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
    <xsl:output indent="yes"/>
    <xsl:output method="html" indent="yes" />

    <xsl:key name="genre" match="genre" use="." />
    <xsl:key name="languageTerm" match="languageTerm[@type='text']" use="." />

    <xsl:param name="groupBy" select="'genre'" />

    <xsl:template match="/*">
        <xsl:apply-templates select="movie//*[local-name() = $groupBy][generate-id() = generate-id(key($groupBy, .)[1])]" />
    </xsl:template>

    <xsl:template match="movie//*">
        <h1><xsl:value-of select="." /></h1>
        <ul>
            <xsl:apply-templates select="key($groupBy, .)/ancestor::movie" />
        </ul>
    </xsl:template>

    <xsl:template match="movie">
        <li><xsl:value-of select="title" /></li>
    </xsl:template>
</xsl:stylesheet>

要按语言分组,请将参数更改为“languageTerm”。希望添加不同的分组不会太难。

请注意,如前所述,这实际上是一个 XSLT 1.0。通常,在 XSLT 2.0 中,您应该使用 xsl:for-each-group 进行分组。我在这里只使用了 XSLT 1.0,因为可以说添加新组更容易,只需为每个组添加一个新的 xsl:key

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-26
    相关资源
    最近更新 更多