【问题标题】:XSL FO group by columns dynamicalyXSL FO 按列动态分组
【发布时间】:2016-07-05 07:35:13
【问题描述】:

我有一个来自 DB 存储过程的 XML 文件,我需要使用带有分组功能的 XSL FO.Net 生成 PDF,如下图所示。谁能指导我如何对列进行分组,分组列不应出现在 HEADER 列中。

就像我可以有 2 个级别的分组一样。我正在使用下面的 XML 和 XSL FO 来生成它。但无法按列分组。

<PdfPrinter>
    <Reports>
    <Header>
    <PrintedDate>2016-07-01T15:16:09.473</PrintedDate>
    <PrintedBy>Pavan</PrintedBy>
    </Header>
    <Report>
    <Name>S</Name>
    <UserName />
    <Remarks />
    <IPAddress>192.168.1.83</IPAddress>
    <DateCreated>2015-10-07T17:48:35.243</DateCreated>
    <AppID>OS</AppID>
    <AppVersion>0.0.0.2</AppVersion>
    <LoginDate>2015-10-07T17:48:05.380</LoginDate>
    <LogoutDate>1900-01-01T00:00:00</LogoutDate>
    </Report>
    <Report>
    <Name>S</Name>
    <UserName />
    <Remarks />
    <IPAddress>192.168.1.83</IPAddress>
    <DateCreated>2015-10-07T17:49:36.107</DateCreated>
    <AppID>OS</AppID>
    <AppVersion>0.0.0.2</AppVersion>
    <LoginDate>2015-10-07T17:49:26.287</LoginDate>
    <LogoutDate>1900-01-01T00:00:00</LogoutDate>
    </Report>
    </Reports>
</PdfPrinter>

XSLT:

    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:ext="http://exslt.org/common"
xmlns:utilityExtension="pdfprinter:extensions:utility"
exclude-result-prefixes="msxsl utilityExtension">
  <!--<xsl:output method="xml" indent="yes" omit-xml-declaration="yes" encoding="utf-8"/>-->
  <xsl:template match="/">

    <xsl:variable name="columnFontSize">12pt</xsl:variable>
    <xsl:variable name="columnFontType">Helvetica</xsl:variable>

    <xsl:variable name="headerPrintedBy">Printed By</xsl:variable>
    <xsl:variable name="headerPrintedDate">Printed Date</xsl:variable>
    <xsl:variable name="headerReportID">Report ID</xsl:variable>
    <xsl:variable name="logo" select="utilityExtension:MapPath('~/App_Data/Resources/IMAGES/logo.jpg')"/>

    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
      <!-- defines the layout master -->
      <fo:layout-master-set>
        <fo:simple-page-master master-name="all-pages" page-width="1600pt" page-height="1190pt">
          <fo:region-body region-name="xsl-region-body" column-gap="0.250in" margin="0.7in" margin-left="0.7in"/>
          <fo:region-before region-name="xsl-region-before" display-align="after" extent="0.700in" />
          <fo:region-after region-name="xsl-region-after" extent="0.700in"/>
        </fo:simple-page-master>
        <fo:page-sequence-master master-name="default-sequence">
          <fo:repeatable-page-master-reference master-reference="all-pages"/>
        </fo:page-sequence-master>
      </fo:layout-master-set>
      <!-- starts actual layout -->
      <fo:page-sequence master-reference="default-sequence">
        <fo:static-content border-bottom-width="1pt" border-bottom-style="solid" border-bottom-color="rgb(192,192,192)" flow-name="xsl-region-before" font-size="10pt" font-family="Helvetica">
          <fo:block color="rgb(105,105,105)" text-align-last="justify">

          </fo:block>
        </fo:static-content>
        <fo:static-content border-top-width="1pt" width="1000pt" border-top-style="solid" border-top-color="rgb(192,192,192)" padding-top="2pt" flow-name="xsl-region-after" font-size="10pt" font-family="Helvetica">
          <fo:table table-layout="fixed" width="500pt">
            <fo:table-column column-width="proportional-column-width(4)"/>
            <fo:table-column column-width="proportional-column-width(1)"/>
            <fo:table-body>
              <fo:table-row>
                <fo:table-cell>
                  <fo:block text-align="right" color="rgb(105,105,105)">&#160;</fo:block>
                </fo:table-cell>
              </fo:table-row>
            </fo:table-body>
          </fo:table>
        </fo:static-content>
        <fo:flow flow-name="xsl-region-body" font-size="10pt" font-family="Helvetica">
          <fo:block>
            <fo:table border-collapse="collapse" width="1200pt"  table-layout="auto" margin-top="-0.002in">
              <fo:table-column column-width="proportional-column-width(55)" column-number="1"/>
              <fo:table-column column-width="proportional-column-width(45)" column-number="2"/>
              <fo:table-body>
                <fo:table-row>
                  <fo:table-cell>
                    <fo:block color="rgb(0,0,128)" font-size="16pt" font-weight="bold">&#160;</fo:block>
                    <fo:block color="rgb(0,0,128)" font-weight="bold"></fo:block>
                    <fo:block color="rgb(0,0,0)" font-weight="bold" font-family="{$columnFontType}" font-size="{$columnFontSize}">
                      <fo:external-graphic src="{$logo}"/>&#160;&#160;&#160;&#160;
                      <fo:block>
                        <xsl:value-of select="$headerOrgName"/>
                      </fo:block>
                    </fo:block>
                    <fo:block color="rgb(0,0,128)" font-weight="bold">&#160;&#160;&#160;&#160;</fo:block>
                    <fo:block color="rgb(0,0,0)" font-weight="bold" font-family="{$columnFontType}" font-size="{$columnFontSize}">
                      <xsl:value-of select="$headerReportID"/>
                    </fo:block>
                    <fo:block>
                      <xsl:value-of select="/PdfPrinter/Reports/Header/ReportID" />
                    </fo:block>
                  </fo:table-cell>
                  <fo:table-cell>
                    <fo:block text-align="left">
                      <fo:inline font-weight="bold" font-family="{$columnFontType}" font-size="{$columnFontSize}">
                        <xsl:value-of select="$headerPrintedBy"/>  :
                      </fo:inline>
                      <fo:block>
                        <xsl:value-of select="/PdfPrinter/Reports/Header/PrintedBy" />
                      </fo:block>
                    </fo:block>
                    <fo:block text-align="left">
                      <fo:inline font-weight="bold" font-family="{$columnFontType}" font-size="{$columnFontSize}">
                        <xsl:value-of select="$headerPrintedDate"/>  :
                      </fo:inline>
                      <fo:block>
                        <xsl:value-of select="/PdfPrinter/Reports/Header/PrintedDate" />
                      </fo:block>
                    </fo:block>
                  </fo:table-cell>
                </fo:table-row>
              </fo:table-body>
            </fo:table>
            <fo:block/>
          </fo:block>
          <fo:block text-align="center">
            <fo:table border-bottom-width="5pt" font-weight="bold" inline-progression-dimension="auto" table-layout="auto" border-bottom-color="rgb(51,51,153)" border-collapse="collapse">
              <fo:table-column column-number="1"/>
              <fo:table-body>
                <fo:table-row border-bottom-color="rgb(0,0,255)" display-align="before">
                  <fo:table-cell border-bottom-width="3pt" border-bottom-style="solid" border-bottom-color="rgb(51,51,153)" padding="2pt" text-align="left">
                    <fo:block text-align="center" font-size="12pt" font-weight="bold" font-family="Helvetica" border-bottom="10pt  "></fo:block>
                    <fo:block>
                      <xsl:value-of select="/PdfPrinter/Reports/Header/ReportTitle" />
                    </fo:block>
                    <fo:block border-bottom-width="10pt" text-align="center"/>
                  </fo:table-cell>
                </fo:table-row>
              </fo:table-body>
            </fo:table>
          </fo:block>
          <fo:block font-size="18pt"
                font-family="sans-serif"
                line-height="24pt"
                space-after.optimum="15pt"
                background-color="blue"
                color="white"
                text-align="center"
                padding-top="3pt">
           Users Report
          </fo:block>
          <fo:block text-align="center">
            <!-- table start -->
            <fo:table border-bottom-width="5pt" width="1200pt" border-bottom-color="rgb(0,51,102)" border-collapse="collapse" background-color="rgb(255,255,255)">
              <!--table header-->
              <xsl:for-each select="/PdfPrinter/Reports/Report[1]/*">
                <fo:table-column column-width="proportional-column-width(4.77)"/>
              </xsl:for-each>
              <fo:table-header>
                  <fo:table-row height="20.81pt" display-align="center" overflow="hidden">
                    <xsl:for-each select="/PdfPrinter/Reports/Report[1]/*">
                    <fo:table-cell text-align="center" border-left-color="rgb(0, 0, 0)" border-left-style="solid" border-left-width="1pt" border-right-color="rgb(0, 0, 0)" border-right-style="solid" border-right-width="1pt" border-top-color="rgb(0, 0, 0)" border-top-style="solid" border-top-width="1pt" border-bottom-color="rgb(0, 0, 0)" border-bottom-style="solid" border-bottom-width="1pt" padding-left="2pt" padding-right="2pt" padding-top="2pt" padding-bottom="2pt">
                      <fo:block color="rgb(0,0,0)" text-align="center" font-weight="normal" font-family="{$columnFontType}" font-size="{$columnFontSize}">
                        <xsl:value-of select="name()"/>
                      </fo:block>
                    </fo:table-cell>
                    </xsl:for-each>
                  </fo:table-row>
              </fo:table-header>
              <!--table body-->
              <fo:table-body>
                <xsl:for-each select="PdfPrinter/Reports/Report">
                  <fo:table-row display-align="before">
                    <xsl:for-each select="*">
                    <fo:table-cell text-align="center" border-top-color="rgb(0, 0, 0)" border-top-style="solid" border-left-width="1pt" border-right-width="1pt" border-top-width="1pt" border-bottom-width="1pt" padding-left="2pt" padding-right="2pt" padding-top="2pt" padding-bottom="2pt">
                      <fo:block>
                          <xsl:value-of select="."/>
                      </fo:block>
                    </fo:table-cell>
                    </xsl:for-each>
                  </fo:table-row>
                </xsl:for-each>
              </fo:table-body>
            </fo:table>
            <!-- table end -->
          </fo:block>
        </fo:flow>
      </fo:page-sequence>
    </fo:root>
  </xsl:template>
</xsl:stylesheet>

我可以动态生成列,但需要按列分组并显示结果,如上图所示。请帮帮我。

提前致谢!

【问题讨论】:

  • 我运行了您提供的 XML 和 XSLT,得到了一个空的 fo:table-header/fo:table-row 和空的 fo:table-body。 XML 需要外部 PdfPrinter 或者您的 XPath 需要更改。
  • @Tony,是的.. 对不起,以编程方式执行此操作.. 您需要在顶部添加 。谢谢你..
  • 您的图形显示 4/5 列,但您的 XML 生成 9 列。您的 XML 中的分组列是什么?
  • 图形仅用于可视化,我只是将其描绘为专家以了解我究竟需要输出。您可以使用“名称”列进行分组吗?因此,图形中的 column5 应替换为 COlumn value : Name and row value by "S" 其次是其他行和列。我希望我很清楚..

标签: xml xslt xsl-fo


【解决方案1】:

由于您使用的是 XSLT 2.0,因此您可以使用 xsl:for-each-groupReport 进行分组。在生成fo:table-columnfo:table-cell 以及跨越整行时,您还不需要考虑Name 元素。

<fo:table border-bottom-width="5pt" width="1200pt" border-bottom-color="rgb(0,51,102)" border-collapse="collapse" background-color="rgb(255,255,255)">
  <!--table header-->
  <xsl:for-each select="/PdfPrinter/Reports/Report[1]/(* except Name)">
    <fo:table-column column-width="proportional-column-width(4.77)"/>
  </xsl:for-each>
  <fo:table-header>
      <fo:table-row height="20.81pt" display-align="center" overflow="hidden">
        <xsl:for-each select="/PdfPrinter/Reports/Report[1]/(* except Name)">
        <fo:table-cell text-align="center" border="rgb(0, 0, 0) solid 1pt" padding="2pt">
          <fo:block color="rgb(0,0,0)" text-align="center" font-weight="normal" font-family="{$columnFontType}" font-size="{$columnFontSize}">
            <xsl:value-of select="name()"/>
          </fo:block>
        </fo:table-cell>
        </xsl:for-each>
      </fo:table-row>
  </fo:table-header>
  <!--table body-->
  <fo:table-body>
    <xsl:for-each-group select="PdfPrinter/Reports/Report"
      group-adjacent="Name">
      <fo:table-row>
        <fo:table-cell number-columns-spanned="{count(*) - 1}">
          <fo:block><xsl:apply-templates select="Name" /></fo:block>
        </fo:table-cell>
      </fo:table-row>
      <xsl:for-each select="current-group()">
        <fo:table-row display-align="before">
          <xsl:for-each select="* except Name">
            <fo:table-cell text-align="center" border-top-color="rgb(0, 0, 0)" border-top-style="solid" border-width="1pt" padding="2pt">
              <fo:block>
                <xsl:value-of select="."/>
              </fo:block>
            </fo:table-cell>
          </xsl:for-each>
        </fo:table-row>
      </xsl:for-each>
    </xsl:for-each-group>
  </fo:table-body>
</fo:table>

要将 Muenchian Grouping 与 XSLT 1.0 处理器一起使用:

version="2.0"' 更改为 'version="1.0"',这样就不会对您使用的 XSLT 版本产生混淆。

在顶层添加这个,例如,在xsl:output之后:

  <xsl:key name="Report" match="Report" use="Name" />

使用这个:

<fo:table border-bottom-width="5pt" width="1200pt" border-bottom-color="rgb(0,51,102)" border-collapse="collapse" background-color="rgb(255,255,255)">
  <!--table header-->
  <xsl:for-each select="/PdfPrinter/Reports/Report[1]/*[local-name() != 'Name']">
    <fo:table-column column-width="proportional-column-width(4.77)"/>
  </xsl:for-each>
  <fo:table-header>
      <fo:table-row height="20.81pt" display-align="center" overflow="hidden">
        <xsl:for-each select="/PdfPrinter/Reports/Report[1]/*[local-name() != 'Name']">
        <fo:table-cell text-align="center" border="rgb(0, 0, 0) solid 1pt" padding="2pt">
          <fo:block color="rgb(0,0,0)" text-align="center" font-weight="normal" font-family="{$columnFontType}" font-size="{$columnFontSize}">
            <xsl:value-of select="name()"/>
          </fo:block>
        </fo:table-cell>
        </xsl:for-each>
      </fo:table-row>
  </fo:table-header>
  <!--table body-->
  <fo:table-body>
    <xsl:for-each select="PdfPrinter/Reports/Report[generate-id() = generate-id(key('Report', Name)[1])]">
      <fo:table-row>
        <fo:table-cell number-columns-spanned="{count(*) - 1}">
          <fo:block><xsl:apply-templates select="Name" /></fo:block>
        </fo:table-cell>
      </fo:table-row>
      <xsl:for-each select="key('Report', Name)">
        <fo:table-row display-align="before">
          <xsl:for-each select="*[local-name() != 'Name']">
            <fo:table-cell text-align="center" border-top-color="rgb(0, 0, 0)" border-top-style="solid" border-width="1pt" padding="2pt">
              <fo:block>
                <xsl:value-of select="."/>
              </fo:block>
            </fo:table-cell>
          </xsl:for-each>
        </fo:table-row>
      </xsl:for-each>
    </xsl:for-each>
  </fo:table-body>
</fo:table>

【讨论】:

  • 我尝试使用上表并在 XSLT 2.0 中出现错误。 (命名空间 'w3.org/1999/XSL/Transform' 中的元素模板在命名空间 'w3.org/1999/XSL/Transform' 中具有无效的子元素 'for-each-group'。预期可能的元素列表:'apply-templates, call-template, apply-imports, for - 名称空间'w3.org/1999/XSL/Transform'中的每个,值,副本,数字,选择等以及名称空间'##other'中的任何元素。)编辑:我想使用XSLT 1.0 ..如果我需要要使用 2.0,我需要参考什么吗?请澄清..非常感谢!
  • 您的样式表包含'version="2.0"',所以我给出了一个XSLT 2.0 解决方案。要使用 XSLT 2.0,您需要一个 XSLT 2.0 处理器,例如 Saxon (saxonica.com)。要使用 XSLT 1.0 进行这种分组,请查看如何进行“Meunchian Grouping”,例如,stackoverflow.com/questions/24411173/…
  • 好的,我是否需要在我的项目中添加任何 dll 才能使用 xslt 2.0?如何在我的项目中使用 XSLT 2.0?请建议..
  • 这是一个不同的问题,我没有答案。
  • 如何使分组列动态化?我想用任何列替换名称。是否可以?请指导我。
猜你喜欢
  • 2013-01-30
  • 1970-01-01
  • 2011-11-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-14
  • 2016-12-18
  • 2020-08-06
  • 1970-01-01
相关资源
最近更新 更多