We help IT Professionals succeed at work.

XSLT Help - Multiple forced pages in one document for PDF and HTML.

Ryla
Ryla asked
on
My data looks like this:
Inventory ID, Product Name, Product ID, Price, Store Location, Store Category
1, Shirt Cotton, 1, 10, Dallas, Mid
2, Pant Demin, 2, 25, Dallas, Mid
3,Pant Cotton, 5, 20, Dallas, Sml
4,Pant Cotton, 5, 20, Chicago, Mid
5,Pant Demin, 2, 25, Chicago, Mid

Using XSL, I need my report to display the unique pairs Store Location and Store Category on individual pages in the same document. So with this sample data I should have three pages -- the first one with Dallas, Mid data, the second one with Dallas, Small data, and the last one with Chicago Mid data.

I am stumped as to do this. I could filter my dataset first but how could I append all my datasets in xsl?
Could I do a page break in a loop?

Comment
Watch Question

XSLT takes as input an XML file, it can't work with CSV.
So you need to find a way to convert your CSV data to a XML.
Suppose, you did that and you have the XML file like follows:

<?xml version="1.0"?>
<Root>
      <Product>
            <Inventory-ID>1</Inventory-ID>
            <Product-Name>Shirt Cotton</Product-Name>
            <Product-ID>1</Product-ID>
            <Price>10</Price>
            <Store-Location>Dallas</Store-Location>
            <Store-Category>Mid</Store-Category>
      </Product>
      <Product>
            <Inventory-ID>2</Inventory-ID>
            <Product-Name>Pant Demin</Product-Name>
            <Product-ID>2</Product-ID>
            <Price>25</Price>
            <Store-Location>Dallas</Store-Location>
            <Store-Category>Mid</Store-Category>
      </Product>
      <Product>
            <Inventory-ID>3</Inventory-ID>
            <Product-Name>Pant Cotton</Product-Name>
            <Product-ID>5</Product-ID>
            <Price>20</Price>
            <Store-Location>Dallas</Store-Location>
            <Store-Category>Sml</Store-Category>
      </Product>
      <Product>
            <Inventory-ID>4</Inventory-ID>
            <Product-Name>Pant Cotton</Product-Name>
            <Product-ID>5</Product-ID>
            <Price>20</Price>
            <Store-Location>Chicago</Store-Location>
            <Store-Category>Mid</Store-Category>
      </Product>
      <Product>
            <Inventory-ID>5</Inventory-ID>
            <Product-Name>Pant Demin</Product-Name>
            <Product-ID>2</Product-ID>
            <Price>25</Price>
            <Store-Location>Chicago</Store-Location>
            <Store-Category>Mid</Store-Category>
      </Product>
</Root>

Then, to create a multi-page grouped FO, you can use an XSLT like in the following sample:
<?xml version="1.0" encoding="windows-1252"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
	<xsl:key name="product-key" match="Product" use="concat(Store-Location,Store-Category)"/>
	<xsl:output method="xml" encoding="windows-1252"/>
	<xsl:template match="/Root">
		<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
			<fo:layout-master-set>
				<fo:simple-page-master master-name="page" margin-top="60pt" margin-right="60pt" margin-bottom="60pt" margin-left="60pt">
					<fo:region-body margin-bottom="2cm" margin-top="2cm" region-name="body"/>
				</fo:simple-page-master>
			</fo:layout-master-set>
			<fo:page-sequence master-reference="page">
				<fo:flow flow-name="body">
					<xsl:for-each select="Product[generate-id(.) = generate-id(key('product-key',concat(Store-Location,Store-Category)))]">
						<fo:block>
							<xsl:if test="position() != 1">
								<xsl:attribute name="page-break-before">always</xsl:attribute>
       						</xsl:if>						
							<xsl:value-of select="concat(Store-Location,', ',Store-Category)"/>
							<xsl:variable name="cur-cat" select="concat(Store-Location,Store-Category)"/>
							<xsl:for-each 
 select="../Product[concat(Store-Location,Store-Category) = $cur-cat]">
								<fo:block>
									<xsl:value-of select="Product-Name"/>
								</fo:block>
    						</xsl:for-each>
							
						</fo:block>
  					</xsl:for-each>
				</fo:flow>
			</fo:page-sequence>
		</fo:root>
	</xsl:template>
</xsl:stylesheet>

Open in new window

p.pdf

Author

Commented:
This is exactly what I was looking for! Thank you!
I currently have a SQL dataset turned into XML into a XmlSchema transformed into a XSLT document and then its binded to a report viewer. I havent used XSL-FO before so I am trying to intergrate it. Its ignoring it right now.

Author

Commented:
I wanted to add that the reason I am doing the XSLT is because in some instances my data is dynamic and I might have more columns for different types of products. This is handled on what products and information is selected by the user on the application. Thus creating a dynamic report.
Please try to replace "page-break-before" to just "break-before".

Author

Commented:
Attached is my code. Im doing something wrong. Its not doing the page breaks.

<?xml version="1.0" encoding="utf-16"?>
<xs:schema id="Report" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
  <xs:element name="Report" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
    <xs:complexType>
      <xs:choice minOccurs="0" maxOccurs="unbounded">
        <xs:element name="Product">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="INVENTORY_ID_col" msdata:Caption="INVENTORY ID" type="xs:string" minOccurs="0" />
              <xs:element name="PRODUCT_NAME_col" msdata:Caption="PRODUCT NAME" type="xs:string" minOccurs="0" />
              <xs:element name="PRODUCT_ID_col" msdata:Caption="PRODUCT ID" type="xs:string" minOccurs="0" />
              <xs:element name="PRICE_col" msdata:Caption="PRICE" type="xs:string" minOccurs="0" />
              <xs:element name="STORE_LOCATION_col" msdata:Caption="STORE LOCATION" type="xs:string" minOccurs="0" />
              <xs:element name="STORE_CATEGORY_col" msdata:Caption="STORE CATEGORY" type="xs:string" minOccurs="0" />
              <xs:element name="TOTAL_UNITS_IN_STOCK_col" msdata:Caption="TOTAL UNITS IN STOCK" type="xs:string" minOccurs="0" />
              <xs:element name="TOTAL_UNITS_SOLD_col" msdata:Caption="TOTAL_UNITS_SOLD" type="xs:string" minOccurs="0" />
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:choice>
    </xs:complexType>
  </xs:element>
</xs:schema>
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:rd="http://schemas.microsoft.com/SQLServer/reporting/reportdesigner" xmlns="http://schemas.microsoft.com/sqlserver/reporting/2005/01/reportdefinition">
  <xsl:param name="City"></xsl:param>
  <xsl:param name="today"></xsl:param>
  <xsl:param name="Units"></xsl:param>
  <xsl:param name="Product"></xsl:param>
  <xsl:param name="Filter"></xsl:param>
  <xsl:param name="Report"></xsl:param>
  <xsl:param name="Title"></xsl:param>
  <xsl:variable name="mvarName" select="/xs:schema/@Name" />
  <xsl:variable name="mvarFontSize">8pt</xsl:variable>
  <xsl:variable name="mvarFontWeight">500</xsl:variable>
  <xsl:variable name="mvarFontWeightBold">700</xsl:variable>
  <xsl:variable name="page.orientation">landscape</xsl:variable>
  <xsl:key name="product-key" match="Product" use="concat(STORE_LOCATION_col,STORE_CATEGORY_col)"/>
  <!--<xsl:output method="xml" encoding="windows-1252"/>-->
  <xsl:template match="/Report">
    <fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
      <fo:layout-master-set>
        <fo:simple-page-master master-name="page" margin-top="60pt" margin-right="60pt" margin-bottom="60pt" margin-left="60pt">
          <fo:region-body margin-bottom="2cm" margin-top="2cm" region-name="body"/>
        </fo:simple-page-master>
      </fo:layout-master-set>
      <fo:page-sequence master-reference="page">
        <fo:flow flow-name="body">
          <xsl:for-each select="Product[generate-id(.) = generate-id(key('product-key',concat(STORE_LOCATION_col,STORE_CATEGORY_col)))]">
            <fo:block>
              <xsl:if test="position() != 1">
                <xsl:attribute name="break-before">always</xsl:attribute>
              </xsl:if>
              <xsl:value-of select="concat(STORE_LOCATION_col,', ',STORE_CATEGORY_col)"/>
              <xsl:variable name="cur-cat" select="concat(STORE_LOCATION_col,STORE_CATEGORY_col)"/>
              <xsl:for-each select="../Product[concat(STORE_LOCATION_col,STORE_CATEGORY_col) = $cur-cat]">
                <fo:block>
                   <xsl:apply-templates select="/xs:schema/xs:element/xs:complexType/xs:choice/xs:element/xs:complexType/xs:sequence" />
                </fo:block>
              </xsl:for-each>
            </fo:block>
          </xsl:for-each>
        </fo:flow>
      </fo:page-sequence>
    </fo:root>
  </xsl:template>
  <!--<xsl:template match="/">
    <xsl:apply-templates select="/xs:schema/xs:element/xs:complexType/xs:choice/xs:element/xs:complexType/xs:sequence" />
  </xsl:template>-->
  <xsl:template match="xs:sequence">
    <Report xmlns="http://schemas.microsoft.com/sqlserver/reporting/2005/01/reportdefinition" xmlns:rd="http://schemas.microsoft.com/SQLServer/reporting/reportdesigner">
      <InteractiveHeight>11in</InteractiveHeight>
      <PageWidth>11in</PageWidth>
      <PageHeight>8.5in</PageHeight>
      <LeftMargin>0.2in</LeftMargin>
      <TopMargin>0.3in</TopMargin>
      <BottomMargin>0.31in</BottomMargin>
      <RightMargin>0.2in</RightMargin>
      <rd:DrawGrid>true</rd:DrawGrid>
      <InteractiveWidth>8.5in</InteractiveWidth>
      <rd:GridSpacing>0.05in</rd:GridSpacing>
      <rd:SnapToGrid>true</rd:SnapToGrid>
      <Width>8.5in</Width>
      <Language>en-US</Language>
      <rd:ReportID>7358b654-3ca3-44a0-8677-efe0a55c7c45</rd:ReportID>
      <xsl:call-template name="BuildDataSource" />
      <xsl:call-template name="BuildDataSet" />
      <PageHeader>
        <Height>1.9in</Height>
        <!--PDF-->
        <PrintOnLastPage>true</PrintOnLastPage>
        <PrintOnFirstPage>true</PrintOnFirstPage>
        <ReportItems>
          <Textbox Name="tbTitle">
            <!--<Left>2.5in</Left>-->
            <Top>0.15in</Top>
            <rd:DefaultName>tbTitle</rd:DefaultName>
            <Width>10in</Width>
            <Style>
              <FontFamily>Verdana</FontFamily>
              <FontWeight>100</FontWeight>
              <FontSize>8pt</FontSize>
              <TextAlign>Center</TextAlign>
              <PaddingLeft>1pt</PaddingLeft>
              <PaddingRight>1pt</PaddingRight>
              <PaddingTop>1pt</PaddingTop>
              <PaddingBottom>1pt</PaddingBottom>
            </Style>
            <CanGrow>true</CanGrow>
            <CanShrink>true</CanShrink>
            <Height>.18in</Height>
            <Value>
              <xsl:value-of select="$Title" />
            </Value>
          </Textbox>
          <Textbox Name="tbSubTitle">
            <!--<Left>2.5in</Left>-->
            <Top>0.35in</Top>
            <rd:DefaultName>tbSubTitle</rd:DefaultName>
            <Width>10.8in</Width>
            <Style>
              <FontFamily>Verdana</FontFamily>
              <FontWeight>500</FontWeight>
              <FontSize>12pt</FontSize>
              <TextAlign>Center</TextAlign>
              <PaddingLeft>1pt</PaddingLeft>
              <PaddingRight>1pt</PaddingRight>
              <PaddingTop>1pt</PaddingTop>
              <PaddingBottom>1pt</PaddingBottom>
            </Style>
            <CanGrow>true</CanGrow>
            <CanShrink>true</CanShrink>
            <Height>0.15in</Height>
            <Value>Inventory Report</Value>
          </Textbox>
          <Textbox Name="tbUnits">
            <Left>.5in</Left>
            <Top>.75in</Top>
            <rd:DefaultName>tbUnits</rd:DefaultName>
            <Width>11in</Width>
            <Style>
              <FontFamily>Verdana</FontFamily>
              <FontSize>7pt</FontSize>
            </Style>
            <CanGrow>true</CanGrow>
            <CanShrink>true</CanShrink>
            <Height>.15in</Height>
            <Value>
              Units: <xsl:value-of select="$Units" />
            </Value>
          </Textbox>
          <Textbox Name="tbProductList">
            <Left>.5in</Left>
            <Top>.90in</Top>
            <rd:DefaultName>tbProductList</rd:DefaultName>
            <Style>
              <FontFamily>Verdana</FontFamily>
              <FontSize>7pt</FontSize>
            </Style>
            <CanGrow>true</CanGrow>
            <CanShrink>true</CanShrink>
            <Height>.15in</Height>
            <Value>
              Product List: <xsl:value-of select="$Product" />
            </Value>
          </Textbox>
          <Textbox Name="tbCity">
            <Left>.5in</Left>
            <Top>1.05in</Top>
            <rd:DefaultName>tbCity</rd:DefaultName>
            <Style>
              <FontFamily>Verdana</FontFamily>
              <FontSize>7pt</FontSize>
            </Style>
            <CanGrow>true</CanGrow>
            <CanShrink>true</CanShrink>
            <Height>.15in</Height>
            <Value>
              City/State: <xsl:value-of select="$City" />
            </Value>
          </Textbox>
          <Textbox Name="tbLocation">
            <Left>.5in</Left>
            <Top>1.20in</Top>
            <rd:DefaultName>tbLocation</rd:DefaultName>
            <Style>
              <FontFamily>Verdana</FontFamily>
              <FontSize>7pt</FontSize>
            </Style>
            <CanGrow>true</CanGrow>
            <CanShrink>true</CanShrink>
            <Height>.15in</Height>
            <Value>
              Location: <xsl:value-of select="$Filter" />
            </Value>
          </Textbox>
          <Textbox Name="tbToday">
            <Left>.5in</Left>
            <Top>1.35in</Top>
            <rd:DefaultName>tbToday</rd:DefaultName>
            <Style>
              <FontFamily>Verdana</FontFamily>
              <FontSize>7pt</FontSize>
            </Style>
            <CanGrow>true</CanGrow>
            <CanShrink>true</CanShrink>
            <Height>.15in</Height>
            <Value>
              Reported on: <xsl:value-of select="$today" />
            </Value>
          </Textbox>
        </ReportItems>
      </PageHeader>
      <Body>
        <ReportItems>
          <Table Name="table1">
            <DataSetName>
              <xsl:value-of select="$mvarName" />
            </DataSetName>
            <KeepTogether>true</KeepTogether>
            <Top>0in</Top>
            <!--space between params and table in excel-->
            <ZIndex>1</ZIndex>
            <Header>
              <TableRows>
                <TableRow>
                  <TableCells>
                    <xsl:apply-templates select="xs:element" mode="HeaderTableCell" />
                  </TableCells>
                  <Height>0.10in</Height>
                </TableRow>
              </TableRows>
              <RepeatOnNewPage>true</RepeatOnNewPage>
              <FixedHeader>true</FixedHeader>
            </Header>
            <Details>
              <TableRows>
                <TableRow>
                  <TableCells>
                    <xsl:apply-templates select="xs:element" mode="DetailTableCell" />
                  </TableCells>
                  <Height>0.1in</Height>
                </TableRow>
              </TableRows>
            </Details>
            <TableColumns>
              <xsl:apply-templates select="xs:element" mode="TableColumn" />
            </TableColumns>
          </Table>
        </ReportItems>
        <Height>7in</Height>
      </Body>
      <PageFooter>
        <Height>0.3in</Height>
        <PrintOnLastPage>true</PrintOnLastPage>
        <PrintOnFirstPage>true</PrintOnFirstPage>
        <ReportItems>
          <Textbox Name="txtPage1">
            <!--<Top>0.25in</Top>-->
            <Left>.25in</Left>
            <rd:DefaultName>txtFootnote</rd:DefaultName>
            <Style>
              <FontFamily>Verdana</FontFamily>
              <FontSize>7pt</FontSize>
              <TextAlign>Center</TextAlign>
            </Style>
            <Height>0.2in</Height>
            <Label>Footnote</Label>
            <Value>
              * - Indicates a backlogged order.
            </Value>
          </Textbox>
          <Textbox Name="txtPage2">
            <!--<Top>0.25in</Top>-->
            <Left>1.5in</Left>
            <rd:DefaultName>txtPage</rd:DefaultName>
            <Style>
              <FontFamily>Verdana</FontFamily>
              <FontSize>7pt</FontSize>
              <TextAlign>Right</TextAlign>
            </Style>
            <Height>0.2in</Height>
            <Label>Page</Label>
            <Value>
              ="Page " + Globals!PageNumber.ToString() + " of " + Globals!TotalPages.ToString()
            </Value>
          </Textbox>
        </ReportItems>
      </PageFooter>
      <Code>
        Public Function GetColor (ByVal price as String) as String
        Dim price as string
        If price &lt; 50 Then
        color="Red"
        Else
        color="Black"
        End If

        Return color
        End Function
      </Code>
    </Report>
  </xsl:template>
  <xsl:template name="BuildDataSource">
    <DataSources>
      <DataSource Name="DummyDataSource">
        <ConnectionProperties>
          <ConnectString />
          <DataProvider>SQL</DataProvider>
        </ConnectionProperties>
        <rd:DataSourceID>84635ff8-d177-4a25-9aa5-5a921652c79c</rd:DataSourceID>
      </DataSource>
    </DataSources>
  </xsl:template>
  <xsl:template name="BuildDataSet">
    <DataSets>
      <DataSet Name="{$mvarName}">
        <Query>
          <rd:UseGenericDesigner>true</rd:UseGenericDesigner>
          <CommandText />
          <DataSourceName>DummyDataSource</DataSourceName>
        </Query>
        <Fields>
          <xsl:apply-templates select="xs:element" mode="Field" />
        </Fields>
      </DataSet>
    </DataSets>
  </xsl:template>
  <xsl:template match="xs:element" mode="Field">
    <xsl:variable name="varFieldName">
      <xsl:value-of select="@name" />
    </xsl:variable>
    <xsl:variable name="varDataType">
      <xsl:choose>
        <xsl:when test="@type='xs:int'">System.Int32</xsl:when>
        <xsl:when test="@type='xs:string'">System.String</xsl:when>
        <xsl:when test="@type='xs:dateTime'">System.DateTime</xsl:when>
        <xsl:when test="@type='xs:boolean'">System.Boolean</xsl:when>
        <xsl:when test="@type='xs:decimal'">System.Decimal</xsl:when>
      </xsl:choose>
    </xsl:variable>
    <Field Name="{$varFieldName}">
      <rd:TypeName>
        <xsl:value-of select="$varDataType" />
      </rd:TypeName>
      <DataField>
        <xsl:value-of select="$varFieldName"/>
      </DataField>
    </Field>
  </xsl:template>
  <xsl:template match="xs:element" mode="HeaderTableCell">
    <xsl:variable name="varFieldName">
      <xsl:value-of select="@name" />
    </xsl:variable>
    <xsl:variable name="varCaptiondName_Head">
      <xsl:value-of select="@msdata:Caption" />
    </xsl:variable>
    <TableCell>
      <ReportItems>
        <Textbox Name="textbox_Header{position()}">
          <rd:DefaultName>
            textbox_Header<xsl:value-of select="position()" />
          </rd:DefaultName>
          <Value>
            <xsl:value-of select="$varCaptiondName_Head" />
          </Value>
          <CanGrow>true</CanGrow>
          <CanShrink>true</CanShrink>
          <ZIndex>11</ZIndex>
          <Style>
            <TextAlign>Center</TextAlign>
            <FontFamily>Arial</FontFamily>
            <PaddingLeft>1pt</PaddingLeft>
            <PaddingRight>1pt</PaddingRight>
            <PaddingTop>1pt</PaddingTop>
            <PaddingBottom>1pt</PaddingBottom>
            <Color>Black</Color>
            <BackgroundColor>white</BackgroundColor>
            <BorderWidth>
              <Left>1pt</Left>
              <Right>1pt</Right>
            </BorderWidth>
            <FontSize>8pt</FontSize>
          </Style>
        </Textbox>
      </ReportItems>
    </TableCell>
  </xsl:template>
  <!--Data table-->
  <xsl:template match="xs:element" mode="DetailTableCell">
    <xsl:variable name="varFieldName">
      <xsl:value-of select="@name" />
    </xsl:variable>
    <xsl:variable name="varCaptiondName_Detail">
      <xsl:value-of select="@msdata:Caption" />
    </xsl:variable>
    <TableCell>
      <ReportItems>
        <Textbox Name="textBox_Detail{$varFieldName}">
          <rd:DefaultName>
            textBox_Detail<xsl:value-of select="$varFieldName" />
          </rd:DefaultName>
          <Value>
            =Fields!<xsl:value-of select="$varFieldName" />.Value
          </Value>
          <CanGrow>true</CanGrow>
          <CanShrink>true</CanShrink>
          <ZIndex>8</ZIndex>
          <Style>
            <PaddingLeft>1pt</PaddingLeft>
            <PaddingBottom>1pt</PaddingBottom>
            <PaddingRight>1pt</PaddingRight>
            <PaddingTop>1pt</PaddingTop>
            <FontFamily>Arial</FontFamily>
            <xsl:choose>
              <xsl:when test="$sReport='PDF'">
                <FontSize>7pt</FontSize>
              </xsl:when>
              <xsl:otherwise>
                <FontSize>8pt</FontSize>
              </xsl:otherwise>
            </xsl:choose>
            <FontWeight>100</FontWeight>
            <BorderColor>
              <Default>white</Default>
            </BorderColor>
            <BackgroundColor>white</BackgroundColor>
            <xsl:choose>
              <xsl:when test="contains($varFieldName,'Product')">
                <Color>
                  =Code.GetColor(Fields!<xsl:value-of select="@name" />.Value)
                </Color>
              </xsl:when>
              <xsl:otherwise>
                <Color>Black</Color>
              </xsl:otherwise>
            </xsl:choose>
          </Style>
        </Textbox>
      </ReportItems>
    </TableCell>
  </xsl:template>
  <!--Column Headers-->
  <xsl:template match="xs:element" mode="TableColumn">
    <xsl:variable name="varFieldName">
      <xsl:value-of select="@name" />
    </xsl:variable>
    <xsl:variable name="varCaptiondName_Detail">
      <xsl:value-of select="@msdata:Caption" />
    </xsl:variable>
    <TableColumn>
      <Width>1in</Width>
    </TableColumn>
  </xsl:template>
  <xsl:template name="replace-string">
    <xsl:param name="text" />
    <xsl:param name="from" />
    <xsl:param name="to" />
    <xsl:choose>
      <xsl:when test="contains($text, $from)">
        <xsl:variable name="before" select="substring-before($text, $from)" />
        <xsl:variable name="after" select="substring-after($text, $from)" />
        <xsl:variable name="prefix" select="concat($before, $to)" />
        <xsl:value-of select="$before" />
        <xsl:value-of select="$to" />
        <xsl:call-template name="replace-string">
          <xsl:with-param name="text" select="$after" />
          <xsl:with-param name="from" select="$from" />
          <xsl:with-param name="to" select="$to" />
        </xsl:call-template>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$text" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

Open in new window

You've posted some kind of report definition. I don't see actual data in it.

Author

Commented:
Attached is the data in form of XML. The data columns are dynamic. The XSLT I use is made specific for the dynamic  nature of the report. I have been trying to integrate the XSLT-FO with the XSLT I currently have. Do you see anything that Im doing wrong?
<Report>
  <Table1>
    <INVENTORY_ID_col>85001</INVENTORY_ID_col>
    <PRODUCT_NAME_col>Cotton Shirt</PRODUCT_NAME_col>
    <PRODUCT_ID_col>00598</PRODUCT_ID_col>
    <PRICE_col>0</PRICE_col>
    <STORE_LOCATION_col>Dallas</STORE_LOCATION_col>
    <STORE_CATEGORY_col>Mid</STORE_CATEGORY_col>
  </Table1>
  <Table1>
    <INVENTORY_ID_col>85105</INVENTORY_ID_col>
    <PRODUCT_NAME_col>LOGO #1 Shirt</PRODUCT_NAME_col>
    <PRODUCT_ID_col>00237</PRODUCT_ID_col>
    <PRICE_col>25</PRICE_col>
    <STORE_LOCATION_col>Chicago</STORE_LOCATION_col>
    <STORE_CATEGORY_col>Mid</STORE_CATEGORY_col>
    <TOTAL_UNITS_IN_STOCK_col>14</TOTAL_UNITS_IN_STOCK_col>
    <TOTAL_UNITS_SOLD_col>61</TOTAL_UNITS_SOLD_col>
  </Table1>
  <Table1>
    <INVENTORY_ID_col>85092</INVENTORY_ID>
    <PRODUCT_NAME_col>LOGO #2 Shirt</PRODUCT_NAME_col>
    <PRODUCT_ID_col>00541</PRODUCT_ID_col>
    <PRICE_col>30</PRICE_col>
    <STORE_LOCATION_col>Dallas</STORE_LOCATION_col>
    <STORE_CATEGORY_col>Sml</STORE_CATEGORY_col>
    <TOTAL_UNITS_IN_STOCK_col>30</TOTAL_UNITS_IN_STOCK_col>
    <TOTAL_UNITS_SOLD_col>20</TOTAL_UNITS_SOLD_col>
  </Table1>
</Report>

Open in new window

I've modified a little the XSLT I provided before to be compatible with the new XML.
It works. Please see attached a PDF file with the output. I used XMLPDF's Ibex processor to convert the FO to PDF.
<?xml version="1.0" encoding="windows-1252"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
	<xsl:key name="product-key" match="Table1" use="concat(STORE_LOCATION_col,STORE_CATEGORY_col)"/>
	<xsl:output method="xml" encoding="windows-1252" indent="yes"/>
	<xsl:template match="/Report">
		<fo:root xmlns:fo="http://www.w3.org/1999/XSL/Format">
			<fo:layout-master-set>
				<fo:simple-page-master master-name="page" margin-top="60pt" margin-right="60pt" margin-bottom="60pt" margin-left="60pt">
					<fo:region-body margin-bottom="2cm" margin-top="2cm" region-name="body"/>
				</fo:simple-page-master>
			</fo:layout-master-set>
			<fo:page-sequence master-reference="page">
				<fo:flow flow-name="body">
					<xsl:for-each 
select="Table1[generate-id(.) = generate-id(key('product-key',concat(STORE_LOCATION_col,STORE_CATEGORY_col)))]">
						<fo:block>
							<xsl:if test="position() != 1">
								<xsl:attribute name="page-break-before">always</xsl:attribute>
       						</xsl:if>						
							<xsl:value-of select="concat(STORE_LOCATION_col,', ',STORE_CATEGORY_col)"/>
							<xsl:variable name="cur-cat" select="concat(STORE_LOCATION_col,STORE_CATEGORY_col)"/>
							<xsl:for-each 
 select="../Table1[concat(STORE_LOCATION_col,STORE_CATEGORY_col) = $cur-cat]">
								<fo:block>
									<xsl:value-of select="PRODUCT_NAME_col"/>
								</fo:block>
    						</xsl:for-each>
							
						</fo:block>
  					</xsl:for-each>
				</fo:flow>
			</fo:page-sequence>
		</fo:root>
	</xsl:template>
</xsl:stylesheet>

Open in new window

pb.pdf