使用Muenchian方法进行XSLT多级分组

时间:2012-01-31 00:45:08

标签: xml xslt xslt-1.0

提前感谢您的时间。我有一个深度嵌套的XML,我需要执行XSLT 1.0转换(用于pdf生成)。我正在部分粘贴XML,我已经为它道歉了!

我根据几个答案重新调整了XML,我意识到我遇到了更多问题。感谢您的耐心等待。

如果需要进一步澄清,请告诉我。

INPUT XML

 <Reports>
  <Report>
    <ReportID>R123</ReportID>
    <ReportName>R123Name</ReportName>
    <PurchaseTypes>
      <PurchaseType>
        <Name>Purchase Type 2</Name>
        <Areas>
          <Area>
            <AreaType>American</AreaType>
            <AreaName>IL</AreaName>
            <SaleDetails>
              <SaleDetail>
                <SaleDetailID>
                  SD45
                </SaleDetailID>
                <Amount>
                  177.3
                </Amount>
              </SaleDetail>
              <SaleDetail>
                <SaleDetailID>
                  SD56
                </SaleDetailID>
                <Amount>
                  123
                </Amount>
              </SaleDetail>
            </SaleDetails>
          </Area>
          <Area>
            <AreaType>American</AreaType>
            <AreaName>MN</AreaName>
            <SaleDetails>
              <SaleDetail>
                <SaleDetailID>
                  SD19
                </SaleDetailID>
                <Amount>
                  19
                </Amount>
              </SaleDetail>

            </SaleDetails>
          </Area>
        </Areas>
      </PurchaseType>
    </PurchaseTypes>
  </Report>
</Reports>

输出需要与下图相似

示例图片2: https://picasaweb.google.com/lh/photo/hxTUY6Qv_9eJyvxQ-UhQutMTjNZETYmyPJy0liipFm0?feat=directlink

@DevNull,这就是我的尝试:

  <xsl:template match="Report">
        <xsl:apply-templates select="ReportID|PurchaseTypes/PurchaseType"></xsl:apply-templates>
      </xsl:template>

 <xsl:template match="PurchaseType">
    <xsl:apply-templates select="Name|Areas/Area/AreaType"></xsl:apply-templates>
  </xsl:template>

但我看到美国两次的区域类型。 像这样的东西: R123 购买类型2 美国 美国

2 个答案:

答案 0 :(得分:1)

查看输入XML和所需输出的excel图像,看起来仍然不需要分组。 XML似乎已经按照您需要格式化报告的方式进行组织。

以下是使用XSL-FO创建PDF的示例。

您的XML输入:

<Reports>
  <Report>
    <ReportID>R123</ReportID>
    <ReportName>R123Name</ReportName>
    <PurchaseTypes>
      <PurchaseType>
        <Name>Purchase Type 2</Name>
        <SaleDetails>
          <SaleDetail>
            <SaleDetailID>
              SD45
            </SaleDetailID>
            <Amount>
              177.3
            </Amount>
          </SaleDetail>
          <SaleDetail>
            <SaleDetailID>
              SD56
            </SaleDetailID>
            <Amount>
              123
            </Amount>
          </SaleDetail>
        </SaleDetails>
      </PurchaseType>
    </PurchaseTypes>
  </Report>
  <Report>
    <ReportID>R234</ReportID>
    <ReportName>R234Name</ReportName>
    <PurchaseTypes>
      <PurchaseType>
        <Name>Purchase Type 1</Name>
        <SaleDetails>
          <SaleDetail>
            <SaleDetailID>
              SD456
            </SaleDetailID>
            <Amount>
              17.3
            </Amount>
          </SaleDetail>
          <SaleDetail>
            <SaleDetailID>
              SD556
            </SaleDetailID>
            <Amount>
              23
            </Amount>
          </SaleDetail>
        </SaleDetails>
      </PurchaseType>
      <PurchaseType>
        <Name>Purchase Type 2</Name>
        <SaleDetails>
          <SaleDetail>
            <SaleDetailID>
              SD451
            </SaleDetailID>
            <Amount>
              12.2
            </Amount>
          </SaleDetail>
        </SaleDetails>
      </PurchaseType>
    </PurchaseTypes>
  </Report>
</Reports>

使用此样式表进行转换:

<xsl:stylesheet version="1.0" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="node()|@*">
    <xsl:apply-templates select="node()|@*"/>
  </xsl:template>

  <xsl:attribute-set name="reportBorder" use-attribute-sets="reportPadding">
    <xsl:attribute name="border">solid 1pt black</xsl:attribute>
  </xsl:attribute-set>

  <xsl:attribute-set name="reportPadding">
    <xsl:attribute name="padding-left">4pt</xsl:attribute>
    <xsl:attribute name="padding-right">4pt</xsl:attribute>
    <xsl:attribute name="padding-top">2pt</xsl:attribute>
    <xsl:attribute name="padding-bottom">2pt</xsl:attribute>    
  </xsl:attribute-set>

  <xsl:template match="Reports">
    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
      <fo:layout-master-set>
        <fo:simple-page-master master-name="my-page" page-width="8.5in" page-height="11in">
          <fo:region-body margin="1in" margin-top="1.5in" margin-bottom="1.5in"/>
        </fo:simple-page-master>
      </fo:layout-master-set>
      <fo:page-sequence master-reference="my-page">
        <fo:flow flow-name="xsl-region-body">
          <xsl:apply-templates/>
        </fo:flow>
      </fo:page-sequence>
    </fo:root>
  </xsl:template>

  <xsl:template match="Report">
    <fo:table margin-bottom="12pt" border="solid 2pt black" width="2.5in">
      <fo:table-column column-number="1" width="1.5in"/>
      <fo:table-column column-number="2" width="1in"/>
      <fo:table-body>
        <xsl:apply-templates select="ReportID|PurchaseTypes/PurchaseType/Name"/>
      </fo:table-body>
    </fo:table>
  </xsl:template>

  <xsl:template match="ReportID">
    <fo:table-row>
      <fo:table-cell background-color="#FFFF00" border-top="solid 2pt black" border-left="solid 2pt black" xsl:use-attribute-sets="reportPadding">
        <fo:block><xsl:value-of select="."/></fo:block>
      </fo:table-cell>
      <fo:table-cell border-top="solid 2pt black" border-right="solid 2pt black">
        <fo:block>&#xA0;</fo:block>
      </fo:table-cell>
    </fo:table-row>    
  </xsl:template>

  <xsl:template match="Name">
    <xsl:if test="ancestor-or-self::PurchaseType[preceding-sibling::PurchaseType]">
      <fo:table-row border-left="solid 2pt black">
        <fo:table-cell>
          <fo:block>&#xA0;</fo:block>
        </fo:table-cell>
        <fo:table-cell>
          <fo:block>&#xA0;</fo:block>
        </fo:table-cell>
      </fo:table-row>
    </xsl:if>
    <fo:table-row>
      <fo:table-cell background-color="#DDA0DD" border-left="solid 2pt black" xsl:use-attribute-sets="reportPadding">
        <fo:block><xsl:value-of select="normalize-space(.)"/></fo:block>
      </fo:table-cell>
      <fo:table-cell border-right="solid 2pt black">
        <fo:block>&#xA0;</fo:block>
      </fo:table-cell>
    </fo:table-row>    
    <fo:table-row background-color="#8FBC8F">
      <fo:table-cell xsl:use-attribute-sets="reportBorder">
        <fo:block>Sale Detail ID</fo:block>
      </fo:table-cell>
      <fo:table-cell xsl:use-attribute-sets="reportBorder">
        <fo:block>Amount</fo:block>
      </fo:table-cell>
    </fo:table-row>
    <xsl:apply-templates select="following-sibling::SaleDetails/SaleDetail"/>
  </xsl:template>

  <xsl:template match="SaleDetail">
    <fo:table-row>
      <fo:table-cell xsl:use-attribute-sets="reportBorder">
        <fo:block><xsl:value-of select="normalize-space(SaleDetailID)"/></fo:block>
      </fo:table-cell>
      <fo:table-cell xsl:use-attribute-sets="reportBorder" text-align="right">
        <fo:block><xsl:value-of select="normalize-space(Amount)"/></fo:block>
      </fo:table-cell>
    </fo:table-row>    
  </xsl:template>
</xsl:stylesheet>

制作此PDF:

enter image description here

希望在FO标记中不会丢失正在发生的事情。

答案 1 :(得分:0)

这不是分组问题。我自己对Meunchian很新,所以我甚至无法真正描述如何使用它,所以我会按照W3C

  

Keys提供了一种处理包含隐式文档的方法   交叉引用结构。

Jeni Tennison

  

分组是XSLT样式表中的一个常见问题:你如何处理   元素列表并将它们分组。主要有两个   您需要执行此操作的情况:

     
      
  • 按内容分组(例如将所有来自诺丁汉的人聚集在一起)
  •   
  • 按位置分组(例如,每个列表中的10个项目)
  •   

因为你的所有数据都是非常分层的,所以很容易在一次传递中沿着树的方式工作,从后代组移动到后代组。

以下是完整的解决方案:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="text"/>
  <xsl:variable name="newline" select="'&#13;&#10;'"/>
  <xsl:variable name="tab" select="'&#9;'"/>

  <xsl:template match="/Reports">
    <xsl:apply-templates select="descendant::Report"/>
  </xsl:template>

  <xsl:template match="Report">
    <xsl:value-of select="ReportID"/>
    <xsl:value-of select="$newline"/>
    <xsl:apply-templates select="descendant::PurchaseType"/>
  </xsl:template>

  <xsl:template match="PurchaseType">
    <xsl:value-of select="Name"/>
    <xsl:value-of select="$newline"/>
    <xsl:text>Sale Detail ID</xsl:text>
    <xsl:value-of select="concat($tab,$tab)"/>
    <xsl:text>Amount</xsl:text>
    <xsl:value-of select="$newline"/>
    <xsl:apply-templates select="descendant::SaleDetail"/>
    <xsl:value-of select="$newline"/>
  </xsl:template>

  <xsl:template match="SaleDetail">
    <xsl:value-of select="normalize-space(SaleDetailID)"/>
    <xsl:value-of select="concat($tab,$tab,$tab)"/>
    <xsl:value-of select="normalize-space(Amount)"/>
    <xsl:value-of select="$newline"/>
  </xsl:template>
</xsl:stylesheet>

生成以下内容(我必须将标签转换为SO格式的空格)。理由与您的形象不符:

R123
Purchase Type 2
Sale Detail ID              Amount
SD45                        177.3
SD56                        123

R234
Purchase Type 1
Sale Detail ID              Amount
SD456                       17.3
SD556                       23

Purchase Type 2
Sale Detail ID              Amount
SD451                       12.2