Background Color:
 
Background Pattern:
Reset
Search
Home Recent Changes Show All Pages

Part 2. Multiple Namespaces and Transformations

Not Rated Yet

This article is the 2nd of a 5 part course in complex data-binding with namespaces, making choices, dynamic parameters and dynamic data.

 

Course Contents

 

With a single source of data the complexity of the bindings is good, but is limited to the original structure. By extending and transforming our data we can add a new dimension to the generated document.

 

Article Contents

 

Creating the Transformation

 

We have our simple sales datasource file with the quarterly sales in 3 of the regions. We have calculated our regional totals by adding each of the quarterly sales, but we also need to calculate the total sales for each quarter. We could do it in the document template, but it would be hard coded and reduce our flexibility

Thankfully scryber allows us to put an XSLT transformation between the source data and the template - so we can change the output as required and reduce the dependancy.

	<?xml version="1.0" encoding="utf-8"?>
	<xsl:stylesheet version="1.0" 
	    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
	    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
	    xmlns:s="http://sample.xml.com/sales"
	    xmlns:env="http://sample.xml.com/sales/envelope"
	>
	  <xsl:output method="xml" indent="yes" standalone="yes" />
	  <xsl:template match="/" >
	    <env:wrapper>
	      <env:copy>
	        <xsl:apply-templates select="@* | node()"/>
	      </env:copy>
	      <env:totals>
	        <xsl:call-template name="quarter" >
	          <xsl:with-param name="q" >1</xsl:with-param>
	        </xsl:call-template>
	        <xsl:call-template name="quarter" >
	          <xsl:with-param name="q" >2</xsl:with-param>
	        </xsl:call-template>
	        <xsl:call-template name="quarter" >
	          <xsl:with-param name="q" >3</xsl:with-param>
	        </xsl:call-template>
	        <xsl:call-template name="quarter" >
	          <xsl:with-param name="q" >4</xsl:with-param>
	        </xsl:call-template>
	      </env:totals>
	    </env:wrapper>
	  </xsl:template>

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

	  <xsl:template name="quarter" >
	    <xsl:param name="q" ></xsl:param>
	    <env:quarter>
	      <xsl:attribute name="number" >
	        <xsl:value-of select="$q"/>
	      </xsl:attribute>

	      <xsl:attribute name="books_sold">
	      <xsl:call-template name="sumProducts">
	        <xsl:with-param name="pNodes" select="s:sales/s:data/s:region/s:quarter[@number=$q]"/>
	      </xsl:call-template>
	      </xsl:attribute>
	     </env:quarter>
	  </xsl:template>

	  <xsl:template name="sumProducts">
	    <xsl:param name="pNodes" select="/.."/>
	    <xsl:param name="pAccum" select="0"/>

	    <xsl:choose>
	      <xsl:when test="not($pNodes)">
	        <xsl:value-of select="$pAccum"/>
	      </xsl:when>
	      <xsl:otherwise>
	        <xsl:call-template name="sumProducts">
	          <xsl:with-param name="pNodes" select="$pNodes[position() >1]"/>
	          <xsl:with-param name="pAccum" select=
	      "$pAccum + $pNodes[1]/@books_sold"/>
	        </xsl:call-template>
	      </xsl:otherwise>
	    </xsl:choose>
	  </xsl:template>

	</xsl:stylesheet>
	

 

Whilst learning XSL transformations is beyond the scope of this article, the transformation will take our existing xml data and wrap it in a new bunch of elements (in a new envelope namespace) and then append the quarter totals to the end. The actual XML output will be as below.

	<?xml version="1.0" encoding="utf-8" standalone="yes"?>
	<env:wrapper xmlns:env="http://sample.xml.com/sales/envelope" xmlns:s="http://sample.xml.com/sales">
	  <env:copy>
	    <sales xmlns="http://sample.xml.com/sales">
	      <summary>
	        <heading>Lucerne Publishing</heading>
	        <subhead>Regional Sales Report</subhead>
	        <description>Sales report for the West Coast, Central and East Coast regions.</description>
	      </summary>
	      <data year="2014">
	        <region>
	          <name>West Coast</name>
	          <quarter number="1" books_sold="24000" />
	          <quarter number="2" books_sold="38600" />
	          <quarter number="3" books_sold="44030" />
	          <quarter number="4" books_sold="21000" />
	        </region>
	        <region>
	          <name>Central</name>
	          <quarter number="1" books_sold="11000" />
	          <quarter number="2" books_sold="16080" />
	          <quarter number="3" books_sold="25000" />
	          <quarter number="4" books_sold="29000" />
	        </region>
	        <region>
	          <name>East Coast</name>
	          <quarter number="1" books_sold="27000" />
	          <quarter number="2" books_sold="31400" />
	          <quarter number="3" books_sold="40100" />
	          <quarter number="4" books_sold="30000" />
	        </region>
	      </data>
	    </sales>
	  </env:copy>
	  <env:totals>
	    <env:quarter number="1" books_sold="62000" />
	    <env:quarter number="2" books_sold="86080" />
	    <env:quarter number="3" books_sold="109130" />
	    <env:quarter number="4" books_sold="80000" />
	  </env:totals>
	</env:wrapper>

 

Adding to the data source

 

We can now update our xml data source to use the transformation and add the registered namespace (with a prefix)

 

    <data:XMLDataSource id="MyComplexSalesData" source-path="./Data/Sales.xml" >
      <Transform path="./Data/SalesToTotals.xslt" ></Transform>
      <Namespaces>
        <data:Xmlns prefix="s" namespace="http://sample.xml.com/sales"/>
        <data:Xmlns prefix="e" namespace="http://sample.xml.com/sales/envelope"/>
      </Namespaces>
    </data:XMLDataSource>

 

Generating the output

 

With this in place we can update our page template to use the new XML schema to generate the new document including the output totals

 

    <pdf:Page id="MyComplexOutput" outline-title="Transformed with 2 namespaces" >
      <Content>

        <data:ForEach select="e:wrapper" datasource-id="MyComplexSalesData" count="1" start-index="0" >
          <Template>
            
            <!-- Separate template for the env:copy/s:sales/s:summary-->
            <data:ForEach select="e:copy/s:sales/s:summary" >
              <Template>
                <pdf:Div id="titles" style:margins="10pt">
                  <pdf:H1 id="heading" text="{xpath:s:heading}" />
                  <pdf:H3 id="subhead" text="{xpath:s:subhead}" />
                  <pdf:Div id="desc" >
                    <pdf:Label text="{xpath:s:description}" />
                  </pdf:Div>
                </pdf:Div>
              </Template>
            </data:ForEach>
            
            <pdf:Table id="salesgrid" style:full-width="true" style:font-size="14pt" style:margins="10pt" >
              <pdf:Header-Row >
                <pdf:Header-Cell>Region</pdf:Header-Cell>
                <pdf:Header-Cell> Q1</pdf:Header-Cell>
                <pdf:Header-Cell> Q2</pdf:Header-Cell>
                <pdf:Header-Cell> Q3</pdf:Header-Cell>
                <pdf:Header-Cell> Q4</pdf:Header-Cell>
                <pdf:Header-Cell>Total</pdf:Header-Cell>
              </pdf:Header-Row>
              
              <!-- All region rows in sales -->
              <data:ForEach select="e:copy/s:sales/s:data/s:region" >
                <Template>
                  <pdf:Row>
                    <pdf:Cell>
                      <pdf:Label text="{xpath:s:name}" />
                    </pdf:Cell>
                    <pdf:Cell>
                      <pdf:Number value="{xpath:s:quarter[@number='1']/@books_sold}" style:number-format="C" />
                    </pdf:Cell>
                    <pdf:Cell>
                      <pdf:Number value="{xpath:s:quarter[@number='2']/@books_sold}" style:number-format="C" />
                    </pdf:Cell>
                    <pdf:Cell>
                      <pdf:Number value="{xpath:s:quarter[@number='3']/@books_sold}" style:number-format="C" />
                    </pdf:Cell>
                    <pdf:Cell>
                      <pdf:Number value="{xpath:s:quarter[@number='4']/@books_sold}" style:number-format="C" />
                    </pdf:Cell>
                    <pdf:Cell>
                      <pdf:Number value="{xpath:(s:quarter[@number='1']/@books_sold + s:quarter[@number='2']/@books_sold + s:quarter[@number='3']/@books_sold + s:quarter[@number='4']/@books_sold)}" style:number-format="C" />
                    </pdf:Cell>
                  </pdf:Row>
                </Template>
              </data:ForEach>
              
              <!-- footer row from env:totals-->
              <data:ForEach select="e:totals" >
                <Template>
                  <pdf:Footer-Row style:font-bold="true">
                    <pdf:Footer-Cell>
                      Total
                    </pdf:Footer-Cell>
                    <pdf:Footer-Cell>
                      <pdf:Number value="{xpath:e:quarter[@number='1']/@books_sold}" style:number-format="C" />
                    </pdf:Footer-Cell>
                    <pdf:Footer-Cell>
                      <pdf:Number value="{xpath:e:quarter[@number='2']/@books_sold}" style:number-format="C" />
                    </pdf:Footer-Cell>
                    <pdf:Footer-Cell>
                      <pdf:Number value="{xpath:e:quarter[@number='3']/@books_sold}" style:number-format="C" />
                    </pdf:Footer-Cell>
                    <pdf:Footer-Cell>
                      <pdf:Number value="{xpath:e:quarter[@number='3']/@books_sold}" style:number-format="C" />
                    </pdf:Footer-Cell>
                    <pdf:Cell>
                      <pdf:Number value="{xpath:(e:quarter[@number='1']/@books_sold + e:quarter[@number='2']/@books_sold + e:quarter[@number='3']/@books_sold + e:quarter[@number='4']/@books_sold)}" style:number-format="C" />
                    </pdf:Cell>
                  </pdf:Footer-Row>
                </Template>
              </data:ForEach>
              
            </pdf:Table>
          </Template>
        </data:ForEach>
      </Content>
    </pdf:Page>

 

This is giving us our desired data output, but it would be nice to show how those values compare to Lucernes' target sales values. We can do this using Part 3. Choices and Conditions

See Also.

 



  Rating
Rate This Page: Poor Great   |  Rate Content |
Average rating:  No Ratings Yet   
Number of Ratings : 0
  Comments
Add Comment
No Comments Yet