格式化 table 列以忽略重复项 XSLT-1.0
Formatting table columns to ignore duplicates XSLT-1.0
我希望有人能用 XSLT 1.0 中的概念为我指明正确的方向。我正在生成一个 PDF,所以代码有点长,我认为只包含相关位会更合适。
我有 XML 类似于以下框架(完整的 XML 有几十行,每行不仅包含制作人和出版物):
<root>
<table>
<row>
<PRODUCER/>
<PUBLICATION_CODE_-_NAME/>
</row>
<row>
<PRODUCER/>
<PUBLICATION_CODE_-_NAME/>
</row>
</table>
</root>
我目前能够使用 XSLT 生成一个 table,它看起来类似于包含多行的:
| Producer Name | Publication |
----------------------------------
|Producer 1 |Publication A |
|Producer 1 |Publication B |
|Producer 1 |Publication C |
|Producer 2 |Publication D |
|Producer 2 |Publication E |
|Producer 2 |Publication F |
以此类推。
在我的 XSLT 中生成此代码的主要部分是:
<xsl:template match ="table">
<fo:table>
<fo:table-body font-size="10pt"
font-family="sans-serif"
line-height="10pt"
space-after.optimum="3pt">
<xsl:for-each select="row">
<fo:table-row>
<fo:table-cell width="2.125in"
height="0.2in">
<xsl:choose>
<xsl:apply-templates select="PRODUCER"/>
</xsl:choose>
</fo:table-cell>
<fo:table-cell width="3.25in"
height="0.2in">
<xsl:apply-templates select="PUBLICATION_CODE_-_NAME"/>
</fo:table-cell>
</fo:table-row>
</xsl:for-each>
</fo:table-body>
</fo:table>
</xsl:template>
<xsl:template match="PRODUCER">
<fo:block>
<xsl:value-of select="@value"/>
</fo:block>
</xsl:template>
<xsl:template match="PUBLICATION_CODE_-_NAME">
<fo:block>
<xsl:value-of select="@value"/>
</fo:block>
</xsl:template>
现在问题出现了,我希望 table 的输出看起来更像这样,而不是上面的 table。
| Producer Name | Publication |
----------------------------------
|Producer 1 |Publication A |
| |Publication B |
| |Publication C |
|Producer 2 |Publication D |
| |Publication E |
| |Publication F |
我尝试这样做的方式是在 XSLT 的这一部分中
<xsl:template match="PRODUCER">
<fo:block>
<xsl:value-of select="@value"/>
</fo:block>
</xsl:template>
此时,据我了解,上下文节点是PRODUCER。因此,为了比较前几行中的 PRODUCER 值,我需要使用一些具有 ../preceding-sibling 效果的东西,以便找到最后一行的 preceding-sibling(而不是 PRODUCER)。另外,这些信息已经由生产者订购,所以我只需要查看最近的前兄弟而不是所有这些。
我试图用来解决这个问题的代码如下:
<xsl:template match="PRODUCER">
<fo:block>
<xsl:if test="not(../preceding-sibling::PRODUCER/@value = self/@value>
<xsl:value-of select="@value"/>
</xsl:if>
</fo:block>
</xsl:template>
我不知道语法是否不正确,或者这是否是执行此操作的好方法,但我们将不胜感激任何和所有输入。如果我可以提供任何其他有助于澄清的信息,或者如果我的问题有任何问题,请告诉我。
谢谢
可以用分组来做,也可以用preceding-sibling来做。我会注意到你说 "dozens" ...我不会担心使用分组。我 运行 这个样本有 2000 行,执行时间为 2.3 秒(在带有 Saxon 的 oXygen 中的调试模式下),没有调试时为 0.1 秒。几十会花几分之一秒。我在这里扩展了您的样本,包括对没有前兄弟姐妹的第一次出现的测试。你也可以结合一些东西,但我留下这个是为了让你看到不同的决定:
样本XML:
<root>
<table>
<row>
<PRODUCER>1</PRODUCER>
<PUBLICATION>A</PUBLICATION>
</row>
<row>
<PRODUCER>1</PRODUCER>
<PUBLICATION>B</PUBLICATION>
</row>
<row>
<PRODUCER>1</PRODUCER>
<PUBLICATION>C</PUBLICATION>
</row>
<row>
<PRODUCER>2</PRODUCER>
<PUBLICATION>B</PUBLICATION>
</row>
<row>
<PRODUCER>2</PRODUCER>
<PUBLICATION>C</PUBLICATION>
</row>
<row>
<PRODUCER>3</PRODUCER>
<PUBLICATION>A</PUBLICATION>
</row>
<row>
<PRODUCER>4</PRODUCER>
<PUBLICATION>B</PUBLICATION>
</row>
</table>
</root>
XSL 测试前同级,放入一个变量中使用并只选择 [1],它是紧接在前的一个:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format"
version="1.0">
<xsl:output indent="yes"/>
<xsl:template match ="table">
<fo:table>
<fo:table-body font-size="10pt"
font-family="sans-serif"
line-height="10pt"
space-after.optimum="3pt">
<xsl:for-each select="row">
<fo:table-row>
<fo:table-cell width="2.125in"
height="0.2in">
<xsl:apply-templates select="PRODUCER"/>
</fo:table-cell>
<fo:table-cell width="3.25in"
height="0.2in">
<xsl:apply-templates select="PUBLICATION"/>
</fo:table-cell>
</fo:table-row>
</xsl:for-each>
</fo:table-body>
</fo:table>
</xsl:template>
<xsl:template match="PRODUCER">
<fo:block>
<!-- Get the previous row element to the one I am in -->
<xsl:variable name="test" select="parent::row/preceding-sibling::row[1]"/>
<xsl:choose>
<!-- First test, do we have a row? -->
<xsl:when test="$test">
<!-- Yes we have a previous row -->
<xsl:choose>
<!-- Next, is the previous row's PRODUCER text the same as ours? -->
<xsl:when test="$test/PRODUCER/text() = text()">
<!-- It is, output nothing -->
<fo:leader/>
</xsl:when>
<xsl:otherwise>
<!-- It is not, so output it -->
<xsl:value-of select="concat('Producer ',.)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<!-- We are the first row (no previous one) so output it -->
<xsl:otherwise>
<xsl:value-of select="concat('Producer ',.)"/>
</xsl:otherwise>
</xsl:choose>
</fo:block>
</xsl:template>
<xsl:template match="PUBLICATION">
<fo:block>
<xsl:value-of select="concat('Publication ',.)"/>
</fo:block>
</xsl:template>
</xsl:stylesheet>
输出:
<fo:table xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:table-body font-size="10pt" font-family="sans-serif" line-height="10pt" space-after.optimum="3pt">
<fo:table-row>
<fo:table-cell width="2.125in" height="0.2in">
<fo:block>Producer 1</fo:block>
</fo:table-cell>
<fo:table-cell width="3.25in" height="0.2in">
<fo:block>Publication A</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell width="2.125in" height="0.2in">
<fo:block>
<fo:leader/>
</fo:block>
</fo:table-cell>
<fo:table-cell width="3.25in" height="0.2in">
<fo:block>Publication B</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell width="2.125in" height="0.2in">
<fo:block>
<fo:leader/>
</fo:block>
</fo:table-cell>
<fo:table-cell width="3.25in" height="0.2in">
<fo:block>Publication C</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell width="2.125in" height="0.2in">
<fo:block>Producer 2</fo:block>
</fo:table-cell>
<fo:table-cell width="3.25in" height="0.2in">
<fo:block>Publication B</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell width="2.125in" height="0.2in">
<fo:block>
<fo:leader/>
</fo:block>
</fo:table-cell>
<fo:table-cell width="3.25in" height="0.2in">
<fo:block>Publication C</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell width="2.125in" height="0.2in">
<fo:block>Producer 3</fo:block>
</fo:table-cell>
<fo:table-cell width="3.25in" height="0.2in">
<fo:block>Publication A</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell width="2.125in" height="0.2in">
<fo:block>Producer 4</fo:block>
</fo:table-cell>
<fo:table-cell width="3.25in" height="0.2in">
<fo:block>Publication B</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>
我希望有人能用 XSLT 1.0 中的概念为我指明正确的方向。我正在生成一个 PDF,所以代码有点长,我认为只包含相关位会更合适。
我有 XML 类似于以下框架(完整的 XML 有几十行,每行不仅包含制作人和出版物):
<root>
<table>
<row>
<PRODUCER/>
<PUBLICATION_CODE_-_NAME/>
</row>
<row>
<PRODUCER/>
<PUBLICATION_CODE_-_NAME/>
</row>
</table>
</root>
我目前能够使用 XSLT 生成一个 table,它看起来类似于包含多行的:
| Producer Name | Publication |
----------------------------------
|Producer 1 |Publication A |
|Producer 1 |Publication B |
|Producer 1 |Publication C |
|Producer 2 |Publication D |
|Producer 2 |Publication E |
|Producer 2 |Publication F |
以此类推。
在我的 XSLT 中生成此代码的主要部分是:
<xsl:template match ="table">
<fo:table>
<fo:table-body font-size="10pt"
font-family="sans-serif"
line-height="10pt"
space-after.optimum="3pt">
<xsl:for-each select="row">
<fo:table-row>
<fo:table-cell width="2.125in"
height="0.2in">
<xsl:choose>
<xsl:apply-templates select="PRODUCER"/>
</xsl:choose>
</fo:table-cell>
<fo:table-cell width="3.25in"
height="0.2in">
<xsl:apply-templates select="PUBLICATION_CODE_-_NAME"/>
</fo:table-cell>
</fo:table-row>
</xsl:for-each>
</fo:table-body>
</fo:table>
</xsl:template>
<xsl:template match="PRODUCER">
<fo:block>
<xsl:value-of select="@value"/>
</fo:block>
</xsl:template>
<xsl:template match="PUBLICATION_CODE_-_NAME">
<fo:block>
<xsl:value-of select="@value"/>
</fo:block>
</xsl:template>
现在问题出现了,我希望 table 的输出看起来更像这样,而不是上面的 table。
| Producer Name | Publication |
----------------------------------
|Producer 1 |Publication A |
| |Publication B |
| |Publication C |
|Producer 2 |Publication D |
| |Publication E |
| |Publication F |
我尝试这样做的方式是在 XSLT 的这一部分中
<xsl:template match="PRODUCER">
<fo:block>
<xsl:value-of select="@value"/>
</fo:block>
</xsl:template>
此时,据我了解,上下文节点是PRODUCER。因此,为了比较前几行中的 PRODUCER 值,我需要使用一些具有 ../preceding-sibling 效果的东西,以便找到最后一行的 preceding-sibling(而不是 PRODUCER)。另外,这些信息已经由生产者订购,所以我只需要查看最近的前兄弟而不是所有这些。
我试图用来解决这个问题的代码如下:
<xsl:template match="PRODUCER">
<fo:block>
<xsl:if test="not(../preceding-sibling::PRODUCER/@value = self/@value>
<xsl:value-of select="@value"/>
</xsl:if>
</fo:block>
</xsl:template>
我不知道语法是否不正确,或者这是否是执行此操作的好方法,但我们将不胜感激任何和所有输入。如果我可以提供任何其他有助于澄清的信息,或者如果我的问题有任何问题,请告诉我。
谢谢
可以用分组来做,也可以用preceding-sibling来做。我会注意到你说 "dozens" ...我不会担心使用分组。我 运行 这个样本有 2000 行,执行时间为 2.3 秒(在带有 Saxon 的 oXygen 中的调试模式下),没有调试时为 0.1 秒。几十会花几分之一秒。我在这里扩展了您的样本,包括对没有前兄弟姐妹的第一次出现的测试。你也可以结合一些东西,但我留下这个是为了让你看到不同的决定:
样本XML:
<root>
<table>
<row>
<PRODUCER>1</PRODUCER>
<PUBLICATION>A</PUBLICATION>
</row>
<row>
<PRODUCER>1</PRODUCER>
<PUBLICATION>B</PUBLICATION>
</row>
<row>
<PRODUCER>1</PRODUCER>
<PUBLICATION>C</PUBLICATION>
</row>
<row>
<PRODUCER>2</PRODUCER>
<PUBLICATION>B</PUBLICATION>
</row>
<row>
<PRODUCER>2</PRODUCER>
<PUBLICATION>C</PUBLICATION>
</row>
<row>
<PRODUCER>3</PRODUCER>
<PUBLICATION>A</PUBLICATION>
</row>
<row>
<PRODUCER>4</PRODUCER>
<PUBLICATION>B</PUBLICATION>
</row>
</table>
</root>
XSL 测试前同级,放入一个变量中使用并只选择 [1],它是紧接在前的一个:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format"
version="1.0">
<xsl:output indent="yes"/>
<xsl:template match ="table">
<fo:table>
<fo:table-body font-size="10pt"
font-family="sans-serif"
line-height="10pt"
space-after.optimum="3pt">
<xsl:for-each select="row">
<fo:table-row>
<fo:table-cell width="2.125in"
height="0.2in">
<xsl:apply-templates select="PRODUCER"/>
</fo:table-cell>
<fo:table-cell width="3.25in"
height="0.2in">
<xsl:apply-templates select="PUBLICATION"/>
</fo:table-cell>
</fo:table-row>
</xsl:for-each>
</fo:table-body>
</fo:table>
</xsl:template>
<xsl:template match="PRODUCER">
<fo:block>
<!-- Get the previous row element to the one I am in -->
<xsl:variable name="test" select="parent::row/preceding-sibling::row[1]"/>
<xsl:choose>
<!-- First test, do we have a row? -->
<xsl:when test="$test">
<!-- Yes we have a previous row -->
<xsl:choose>
<!-- Next, is the previous row's PRODUCER text the same as ours? -->
<xsl:when test="$test/PRODUCER/text() = text()">
<!-- It is, output nothing -->
<fo:leader/>
</xsl:when>
<xsl:otherwise>
<!-- It is not, so output it -->
<xsl:value-of select="concat('Producer ',.)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:when>
<!-- We are the first row (no previous one) so output it -->
<xsl:otherwise>
<xsl:value-of select="concat('Producer ',.)"/>
</xsl:otherwise>
</xsl:choose>
</fo:block>
</xsl:template>
<xsl:template match="PUBLICATION">
<fo:block>
<xsl:value-of select="concat('Publication ',.)"/>
</fo:block>
</xsl:template>
</xsl:stylesheet>
输出:
<fo:table xmlns:fo="http://www.w3.org/1999/XSL/Format">
<fo:table-body font-size="10pt" font-family="sans-serif" line-height="10pt" space-after.optimum="3pt">
<fo:table-row>
<fo:table-cell width="2.125in" height="0.2in">
<fo:block>Producer 1</fo:block>
</fo:table-cell>
<fo:table-cell width="3.25in" height="0.2in">
<fo:block>Publication A</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell width="2.125in" height="0.2in">
<fo:block>
<fo:leader/>
</fo:block>
</fo:table-cell>
<fo:table-cell width="3.25in" height="0.2in">
<fo:block>Publication B</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell width="2.125in" height="0.2in">
<fo:block>
<fo:leader/>
</fo:block>
</fo:table-cell>
<fo:table-cell width="3.25in" height="0.2in">
<fo:block>Publication C</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell width="2.125in" height="0.2in">
<fo:block>Producer 2</fo:block>
</fo:table-cell>
<fo:table-cell width="3.25in" height="0.2in">
<fo:block>Publication B</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell width="2.125in" height="0.2in">
<fo:block>
<fo:leader/>
</fo:block>
</fo:table-cell>
<fo:table-cell width="3.25in" height="0.2in">
<fo:block>Publication C</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell width="2.125in" height="0.2in">
<fo:block>Producer 3</fo:block>
</fo:table-cell>
<fo:table-cell width="3.25in" height="0.2in">
<fo:block>Publication A</fo:block>
</fo:table-cell>
</fo:table-row>
<fo:table-row>
<fo:table-cell width="2.125in" height="0.2in">
<fo:block>Producer 4</fo:block>
</fo:table-cell>
<fo:table-cell width="3.25in" height="0.2in">
<fo:block>Publication B</fo:block>
</fo:table-cell>
</fo:table-row>
</fo:table-body>
</fo:table>