如何应用两个模板,并根据大小和xslt使用的模板对结果进行分组



我正在尝试解析一个XML并生成一个可用于打印的HTML。

XML中元素的内容像卡片一样呈现,并且具有正面和背面的信息。一页纸可以放八张牌。为了使HTML/CSS世界中的定位更容易,我想按如下方式预先安排XSLT输出:对于输入中的16个元素,我希望首先有前8个元素的正面输出,然后是前8个元件的背面输出,以不同的顺序,当使用双面打印时,它们与对应的正面匹配,然后是接下来8个元素,等等的正面输出。

背面的顺序是这样的:前半部分按相反的顺序排列,然后后半部分按相反顺序排列。示例:背面卡4、3、2、1、8、7、6、5。

或者对于以下输入(为了简单起见,我只使用每页4张卡片作为示例):

<cards>
<card>
<question>First for the front</question>
<answer>First to the back</answer>
</card>
<card>
<question>Second for the front</question>
<answer>Second to the back</answer>
</card>
<card>
<question>Third for the front</question>
<answer>Third to the back</answer>
</card>
<card>
<question>Fourth for the front</question>
<answer>Fourth to the back</answer>
</card>
<card>
<question>Fifth for the front</question>
<answer>Fifth to the back</answer>
</card>
</cards>

我想得到以下输出:

<html><body>
<div>
<div class="card1 front">First for the front</div>
<div class="card2 front">Second for the front</div>
<div class="card3 front">Third for the front</div>
<div class="card4 front">Fourth for the front</div>
</div>
<div>
<div class="card2 back">Second to the back</div>
<div class="card1 back">First to the back</div>
<div class="card4 back">Fourth to the back</div>
<div class="card3 back">Third to the back</div>
</div>
<div>
<div class="card1 front">Fifth for the front</div>
</div>
<div>
<div class="card1 back">Fifth to the back</div>
</div>
</body></html>

我有一个想法,在下一个匹配和模式中处理两次元素,但我不知道如何将其与我想要应用的排序/分组相结合。

如果能有一个指向正确方向的指针,我将不胜感激。

让我们将其通用化-我们希望每页$rows$cols张卡片,在答案一侧,每行都需要按相反顺序打印。

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:param name="rows" select="2" />
<xsl:param name="cols" select="2" />
<xsl:variable name="pageSize" select="$rows * $cols" />
<xsl:template match="/">
<html>
<body>
<xsl:apply-templates select="cards/card[position() mod $pageSize = 1]" />
</body>
</html>
</xsl:template>
<xsl:template match="card">
<!-- fronts -->
<div>
<xsl:call-template name="printRows">
<xsl:with-param name="element" select="1"/>
<xsl:with-param name="order" select="'ascending'" />
</xsl:call-template>
</div>
<!-- backs -->
<div>
<xsl:call-template name="printRows">
<xsl:with-param name="element" select="2"/>
<xsl:with-param name="order" select="'descending'" />
</xsl:call-template>
</div>
</xsl:template>
<xsl:template name="printRows">
<xsl:param name="element" />
<xsl:param name="order" />
<xsl:variable name="thePage"
select=". | following-sibling::card[position() &lt; $pageSize]" />
<!-- split into rows -->
<xsl:for-each select="$thePage[position() mod $cols = 1]">
<xsl:variable name="theRow"
select=". | following-sibling::card[position() &lt; $cols]" />
<!-- and process each row in appropriate order -->
<xsl:apply-templates select="$theRow/*[$element]">
<xsl:sort select="position()" order="{$order}" data-type="number" />
</xsl:apply-templates>
</xsl:for-each>
</xsl:template>
<xsl:template match="question">
<div class="card{(count(../preceding-sibling::card) mod $pageSize) + 1} front">
<xsl:value-of select="." />
</div>
</xsl:template>
<xsl:template match="answer">
<div class="card{(count(../preceding-sibling::card) mod $pageSize) + 1} back">
<xsl:value-of select="." />
</div>
</xsl:template>
</xsl:stylesheet>

这将适用于任何网格大小,只需通过前两个参数设置(或传入)行和列的数量。为了计算类名,我计算了前面的同级元素,以便数字基于原始文档顺序中的card元素的完整集合-position()函数将给出排序的位置,并且仅在当前行中。

然而,我认为你的输出逻辑可能有缺陷——在最后一行(短),第五张牌的背面应该在第二列,而不是第一列,以便在其相应的正面对面打印。一般来说,如果"后排"的卡片少于$cols张,那么你需要用空的div来填充它,让所有的卡片都排好。一种方法是修改printRows模板,如下所示:

<!-- split into rows -->
<xsl:for-each select="$thePage[position() mod $cols = 1]">
<xsl:variable name="theRow"
select=". | following-sibling::card[position() &lt; $cols]" />
<xsl:if test="$order = 'descending'">
<!--
special case for a short reverse row (i.e. the last row of the last page) - we need
to left-pad this row with empty columns to get the right positioning
-->
<xsl:call-template name="emptyDivs">
<xsl:with-param name="num" select="$cols - count($theRow)" />
</xsl:call-template>
</xsl:if>
<!-- and process each row in appropriate order -->
<xsl:apply-templates select="$theRow/*[$element]">
<xsl:sort select="position()" order="{$order}" data-type="number" />
</xsl:apply-templates>
</xsl:for-each>

其中emptyDivs模板为

<xsl:template name="emptyDivs">
<xsl:param name="num"/>
<xsl:if test="$num &gt; 0">
<div class="padding back" />
<xsl:call-template name="emptyDivs">
<xsl:with-param name="num" select="$num - 1" />
</xsl:call-template>
</xsl:if>
</xsl:template>

这将为两行两列的页面生成以下输出:

<html>
<body>
<div>
<div class="card1 front">First for the front</div>
<div class="card2 front">Second for the front</div>
<div class="card3 front">Third for the front</div>
<div class="card4 front">Fourth for the front</div>
</div>
<div>
<div class="card2 back">Second to the back</div>
<div class="card1 back">First to the back</div>
<div class="card4 back">Fourth to the back</div>
<div class="card3 back">Third to the back</div>
</div>
<div>
<div class="card1 front">Fifth for the front</div>
</div>
<div>
<div class="padding back"></div>
<div class="card1 back">Fifth to the back</div>
</div>
</body>
</html>

或者对于两行乘三列如下:

<html>
<body>
<div>
<div class="card1 front">First for the front</div>
<div class="card2 front">Second for the front</div>
<div class="card3 front">Third for the front</div>
<div class="card4 front">Fourth for the front</div>
<div class="card5 front">Fifth for the front</div>
</div>
<div>
<div class="card3 back">Third to the back</div>
<div class="card2 back">Second to the back</div>
<div class="card1 back">First to the back</div>
<div class="padding back"></div>
<div class="card5 back">Fifth to the back</div>
<div class="card4 back">Fourth to the back</div>
</div>
</body>
</html>

XSLT1.0转换实现了所需的结构:

<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="html" encoding="UTF-8" indent="yes" />
<xsl:template match="/cards">
<html>
<body>
<xsl:for-each select="card[position() mod 4 = 1]">
<xsl:variable name="thisPage" select="
. | following-sibling::card[position() &lt; 4]
" />
<div class="front">
<xsl:apply-templates select="$thisPage/question" />
</div>
<div class="back">
<xsl:apply-templates select="$thisPage/answer">
<xsl:sort select="substring('2143', position(), 1)" data-type="number" />
</xsl:apply-templates>
</div>
</xsl:for-each>
</body>
</html>
</xsl:template>
<xsl:template match="card/*">
<div class="card">
<xsl:value-of select="normalize-space()" />
</div>
</xsl:template>
</xsl:transform>

我认为你并不真的需要编号的CSS类名。添加它们会使事情变得不必要的复杂。

如有必要,您可以使用nth-child在CSS样式表中轻松实现同样的功能。

.back .card:nth-child(1) {
/* this is card2 */
}

也就是说,通过在CSS中组合position: absolutenth-child,您还可以在背面实现整个定位,而不依赖于源顺序。这样一来,XSLT中的特殊排序就没有必要了。

相关内容

  • 没有找到相关文章

最新更新