8.5 Export XML from Related Databases

8.4 Fixed-width Text Export

You can find an example of a text export for column widths to be of the same width. You can change the variable to be any width, but you don't have a way to change each column independently. This stylesheet is called fixed_width.xsl and is found with the other example stylesheets in FileMaker Pro 6. Our example will use <xsl:variable> to pass values and <xsl:param> to pass the width of each column.

8.41 Getting the Column Widths

Sometimes you will be given a map for the width of each column, such as in Listing 8.17. This map may also include default values to use or a format for text, like the amount column. Sometimes you may need to make a best guess by counting the characters in a sample output, as seen in Listing 8.18. This type of document may be in a monospaced font so you can see the columns. You can understand why it is much easier to determine the correct column width when you have a map!

Listing 8.17: Map of columns

start example
 begin (4) 'ORD ' firstname (20) lastname (20) state (2) amount (9, 2) 000000.00 
end example

Listing 8.18: Sample text output

start example
 ORD Beverly            Voth            KY000001.00 ORD Doug               Rowe            FL000002.00 
end example

8.42 Setting Up Default Values

You may wish to use values multiple times within an XSLT stylesheet. These can be set by using the XSL top-level elements <xsl:variable> and <xsl:param> or by defining an !ENTITY before the <xsl:stylesheet> element. A good reason for using these methods is to allow quick changes to a default value, such as the end-of-line character or a delimiter. The difference between the <xsl:variable> and the <xsl:param> elements is that PARAM is used if a value doesn't already exist. We'll use both of these XSLT elements in our example, so you will see ways that they can be used.

The value of these elements can be global (used throughout the stylesheet) if set as top-level elements, or local if set within a template. In either case, the value of the variable or parameter is returned if the name is used in an XPath expression, by appending the "$" character before the name of the variable or parameter. For example, "$eol" returns the value set by:

 <!-- end-of-line = CRLF --> <xsl:variable name="eol"><xsl:text>&#13;&#10;</xsl:text></xsl:variable> 

The value of an ENTITY is called by using the defined name of the entity between the "&" and ";" characters. Listing 8.19 shows how to define an ENTITY for use in an XSL stylesheet.

Listing 8.19: Define an ENTITY

start example
 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE stylesheet[       <!ENTITY eol "<xsl:text>&#13;&#10;</xsl:text>"> ]> <xsl:stylesheet> ... </xsl:stylesheet> 
end example

We will use the <xsl:variable> for the fixed-width example. We need to define the end-of-line character and some "padding" characters for numbers and text. Start the stylesheet as in Listing 8.20. Change the end-of-line character to your preference. You may also define any other default values you may use throughout the stylesheet.

Listing 8.20: Begin variable_fixed.xsl

start example
 <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/   XSL/Transform" xmlns:fmp="http://www.filemaker.com/fmpxmlresult">       <xsl:output method="text" version="1.0" encoding="UTF-8"         indent="no" />       <!-- SET UP VARIABLES -->       <!-- end-of-line = carriage return, change as needed -->       <xsl:variable name="eol"><xsl:text>&#13;</xsl:text>       </xsl:variable>       <!-- space as text fill character -->       <xsl:variable name="padSpace"><xsl:text>&#32;</xsl:text>       </xsl:variable>       <!-- zero as number fill character -->       <xsl:variable name="padNum"><xsl:text>0</xsl:text></xsl:variable>       <!-- set your own default values here -->       <xsl:variable name="begin"><xsl:text>ORD</xsl:text><xsl:value-of select="$padSpace" /></xsl:variable>       <!-- main template here -->       <xsl:template match="fmp:FMPXMLRESULT">             <xsl:for-each select="fmp:RESULTSET/fmp:ROW">             <xsl:value-of select="$begin" />                   <!-- Begin each row with line start text -->             <xsl:apply-templates />                   <!-- see if there are templates for the columns                     -->             <xsl:value-of select="$eol" />                   <!-- end each row with the end-of-line character                     -->         </xsl:for-each>       </xsl:template> </xsl:stylesheet> 
end example

8.43 Passing Parameters

The sample template shown here is used on each column to pass the desired width of the column and the padding character to use. <xsl:with-param> is used with <xsl:call-template> to pass this information. Our first column from the database is the firstname field and will be 20 characters wide padded with the space character. Each column will have a separate template match, so that we can pass different widths and padding characters. You may need to create a default template to handle any columns not specifically called.

Listing 8.21: Set up each column and default template

start example
 <xsl:template match="fmp:COL[1]">       <xsl:call-template name="makeCol">             <xsl:with-param name="colWidth" select="20" />             <xsl:with-param name="colPad" select="$padSpace" />       </xsl:call-template> </xsl:template> <xsl:template match="fmp:COL">       <!-- do nothing for other columns, if any --> </xsl:template> 
end example

8.44 Testing Data Length

For our example, a text string that is not long enough for a column will be padded on the right with additional spaces. If the text string is too long, it will be truncated to the column length. A number may need to be padded with leading zeros, as in our example, or with spaces. You must determine the padding character to use and whether it occurs before or after your text string. Use the <xsl:choose> element to test for the length of a string and what template to call for further processing.

Let's analyze Listing 8.22. This is a template named makeCol. Each column template in your stylesheet, as in Listing 8.21, calls the template. We will set the default parameters to use if we forgot to pass them to the template. You will get an XSL processor error if you use the parameters in the template and don't pass them to the template or set them within the template. The "colPad" parameter can use the global variable "padSpace", which was set at the beginning of the stylesheet.

Listing 8.22: makeCol template

start example
 <xsl:template name="makeCol">       <xsl:param name="colWidth" select="0" />       <xsl:param name="colPad" select="$padSpace" />       <xsl:choose>             <xsl:when test="string-length(fmp:DATA) &lt; $colWidth">                         <!-- we will make another test here,                           see Listing 8.21 -->             </xsl:when>             <xsl:otherwise>                   <xsl:value-of select="substring(fmp:DATA,1,                     $colWidth)" />             </xsl:otherwise>       </xsl:choose> </xsl:template> 
end example

Next we create an <xsl:choose> test to see if the width of the string value of the column is less than ("&lt;") the passed parameter "colWidth". When the string is not long enough, we will test for the padding character, as in Listing 8.23. Otherwise we truncate the string by using the XPath function substring(). If the string value of the column is exactly the correct width, this function will just return the string value.

Listing 8.23: Test the padding character

start example
 <xsl:choose>       <xsl:when test="$colPad = $padSpace">             <xsl:value-of select="fmp:DATA" />             <xsl:call-template name="textPad">                   <xsl:with-param name="padCount" select="$colWidth                     - string-length(fmp:DATA)" />                   <xsl:with-param name="colPad" select="$colPad" />             </xsl:call-template>       </xsl:when>       <xsl:otherwise>             <xsl:call-template name="textPad">                   <xsl:with-param name="padCount" select="$colWidth                     - string-length(fmp:DATA)" />                   <xsl:with-param name="colPad" select="$colPad" />             </xsl:call-template>             <xsl:value-of select="fmp:DATA" />       </xsl:otherwise> </xsl:choose> 
end example

Listing 8.23 will be inserted in the makeCol template, above, where we need to make this test. We've passed a character to use for padding. When the character is the space ("$padSpace"), we want to have the output take the string value of the DATA element and call another template, textPad, to add the padding. We pass the parameter that tells us the number of times we need to add the padding character. If the padding character is the zero ("$padNum"), we want to call the textPad template, passing the "padCount" parameter, and then output the string value of the DATA element.

Listing 8.24: makeCol template complete

start example
 <xsl:template name="makeCol">       <xsl:param name="colWidth" select="0" />       <xsl:param name="colPad" select="$padSpace" />       <xsl:choose>             <xsl:when test="string-length(fmp:DATA) &lt; $colWidth">                   <xsl:choose>                         <xsl:when test="$colPad = $padSpace">                               <xsl:value-of select="fmp:DATA" />                               <xsl:call-template name="textPad">                                     <xsl:with-param name="padCount"                                       select="$colWidth - string                                      -length(fmp:DATA)" />                                     <xsl:with-param name="colPad" select="$colPad" />                               </xsl:call-template>                         </xsl:when>                         <xsl:otherwise>                               <xsl:call-template name="textPad">                                     <xsl:with-param name="padCount"                                        select="$colWidth - string                                       -length(fmp:DATA)" />                                     <xsl:with-param name="colPad"                                       select="$colPad" />                               </xsl:call-template>                               <xsl:value-of select="fmp:DATA" />                         </xsl:otherwise>                   </xsl:choose>             </xsl:when>             <xsl:otherwise>                   <xsl:value-of select="substring(fmp:DATA,1,$colWidth)" />             </xsl:otherwise>       </xsl:choose> </xsl:template> 
end example

8.45 Looping to Add Padding Characters

The makeCol template calls the next template, textPad. You may begin to see how the XSL template is used very much like a Perform Script[subscript] in FileMaker Pro. Each template builds upon the one that calls it. We use a default parameter of "0" if none is passed and decrement a passed parameter throughout the loop. The <xsl:if> test will fail when there are no more padding characters to output. When all padding is complete, the stylesheet returns to the calling template, makeCol.

Listing 8.25: textPad template

start example
 <xsl:template name="textPad">       <xsl:param name="padCount" select="0" />       <xsl:param name="colPad" select="$padSpace" />       <!-- template calls itself until all the required padding is         included -->       <xsl:if test="$padCount > 0">             <xsl:value-of select="$colPad" />             <xsl:call-template name="textPad">                   <!-- decrement the parameter -->                   <xsl:with-param name="padCount" select="$padCount - 1" />                   <xsl:with-param name="colPad" select="$colPad" />             </xsl:call-template>       </xsl:if> </xsl:template> 
end example

8.46 The Complete Variable Fixed-Width Stylesheet

We'll put all the templates together, create a template for each column in our FMPXMLRESULT export, and save the stylesheet as variable_ fixed.xsl. The width of each column is passed along with the padding character to another template.

Listing 8.26: variable_fixed.xsl

start example
 <?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/   Transform" xmlns:fmp="http://www.filemaker.com/fmpxmlresult">       <xsl:output method="text" version="1.0" encoding="UTF-8"         indent="no" />       <!-- SET UP VARIABLES -->       <!-- end-of-line = carriage return, change as needed -->       <xsl:variable name="eol"><xsl:text>&#13;</xsl:text></xsl:variable>       <!-- space as text fill character -->       <xsl:variable name="padSpace"><xsl:text>&#32;</xsl:text>       </xsl:variable>       <!-- zero as number fill character -->       <xsl:variable name="padNum"><xsl:text>0</xsl:text></xsl:variable>       <!-- set your own default values here -->       <xsl:variable name="begin"><xsl:text>ORD</xsl:text><xsl:value-of         select="$padSpace" /></xsl:variable>       <!-- main template here -->       <xsl:template match="fmp:FMPXMLRESULT">             <xsl:for-each select="fmp:RESULTSET/fmp:ROW">             <xsl:value-of select="$begin" />                   <!-- Begin each row with line start text -->             <xsl:apply-templates />                   <!-- see if there are templates for the columns -->             <xsl:value-of select="$eol" />                   <!-- end each row with the end-of-line character -->       </xsl:for-each>       </xsl:template>       <!-- SET UP EACH FIELD/COLUMN WIDTH -->       <xsl:template match="fmp:COL[1]">             <!-- firstname -->             <xsl:call-template name="makeCol">                   <xsl:with-param name="colWidth" select="20" />                   <xsl:with-param name="colPad" select="$padSpace" />             </xsl:call-template>       </xsl:template>       <xsl:template match="fmp:COL[2]">             <!-- lastname -->             <xsl:call-template name="makeCol">                   <xsl:with-param name="colWidth" select="20" />                   <xsl:with-param name="colPad" select="$padSpace" />             </xsl:call-template>       </xsl:template>       <xsl:template match="fmp:COL[3]">             <!-- state -->             <xsl:call-template name="makeCol">                   <xsl:with-param name="colWidth" select="2" />                   <xsl:with-param name="colPad" select="$padSpace" />             </xsl:call-template>       </xsl:template>       <xsl:template match="fmp:COL[4]">             <!-- amount -->             <xsl:call-template name="makeCol">                   <xsl:with-param name="colWidth" select="9" />                   <xsl:with-param name="colPad" select="$padNum" />             </xsl:call-template>       </xsl:template>       <xsl:template match="fmp:COL">             <!-- do nothing for other columns, if any -->       </xsl:template>       <!-- TEMPLATE TO TEST FOR COLUMN WIDTH -->       <xsl:template name="makeCol">             <xsl:param name="colWidth" select="0" />             <xsl:param name="colPad" select="$padSpace" />             <xsl:choose>                   <xsl:when test="string-length(fmp:DATA) &lt; $colWidth">                         <xsl:choose>                               <xsl:when test="$colPad = $padSpace">                                     <xsl:value-of select="fmp:DATA" />                                     <xsl:call-template name="textPad">                                           <xsl:with-param name="padCount"                                             select="$colWidth - string                                             -length(fmp:DATA)" />                                           <xsl:with-param name="colPad"                                             select="$colPad" />                                     </xsl:call-template>                               </xsl:when>                               <xsl:otherwise>                                     <xsl:call-template name="textPad">                                           <xsl:with-param name="padCount"                                             select="$colWidth - string                                             -length(fmp:DATA)" />                                           <xsl:with-param name="colPad"                                             select="$colPad" />                                     </xsl:call-template>                                     <xsl:value-of select="fmp:DATA" />                               </xsl:otherwise>                         </xsl:choose>                   </xsl:when>                   <xsl:otherwise>                         <xsl:value-of select="substring(fmp:DATA,1,                           $colWidth)" />                   </xsl:otherwise>             </xsl:choose>       </xsl:template>       <!-- PADDING TEMPLATE -->       <xsl:template name="textPad">       <xsl:param name="padCount" select="0" />             <xsl:param name="colPad" select="$padSpace" />             <!-- template calls itself until all the required padding               is included -->             <xsl:if test="$padCount > 0">                   <xsl:value-of select="$colPad" />                   <xsl:call-template name="textPad">                         <!-- decrement the parameter -->                         <xsl:with-param name="padCount" select="$padCount -                           1" />                         <xsl:with-param name="colPad" select="$colPad" />                   </xsl:call-template>             </xsl:if>       </xsl:template> </xsl:stylesheet> 
end example



Filemaker Pro 6 Developer's Guide to XML(s)XSL
FileMaker Pro 6 Developers Guide to XML/XSL (Wordware Library for FileMaker)
ISBN: 155622043X
EAN: 2147483647
Year: 2003
Pages: 100
Authors: Beverly Voth

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net