0704.315 Programming Languages

Homework 5


Due Date

Both Sections: December 10
Submissions by December 7 will be graded by December 10

Form of Submission

Homework can be submitted via email or printout by deadline. Printouts of source code and run transcripts should be included.

Preparation

Assignment

The goal of this assignment is to gain experience with the XSL Transformation (XSLT) language. Your work should be conducted on Elvis, or on your home machine if you are willing and able to install the Saxon XSLT implementation there.

A number of XML and XSL files will be referred to during this assignment. They can be found on Elvis in ~clamen/Public/PL/XSL.

  1. As a test, run addresstest.xsl over the addresses.xml sample source. (Both are available off of the web page.) On Elvis, run the following from the shell:
         
    	cd ~clamen/Public/PL/XSL
    	~clamen/bin/saxon addresses.xml addresstest.xsl
    
    Names of people in addressbook:
    
     - George W. Bush
     - Stewart M. Clamen
     - Osama bin Laden
     - Harry Potter
    
    (done)  
    
    You will use the two files as the basis for the next few exercises.

  2. Modify addresstest.xsl such that it displays the city, state and country (if available) with each name for each addressbook entry. The output should look something like:
    Names of people in addressbook:
    
     - George W. Bush, Washington, DC, USA
     - Stewart M. Clamen, Glassboro, NJ, USA
     - Osama bin Laden
     - Harry Potter, Little Whinging, England, United Kingdom
    
    (done)  
    

    There are numerous ways to accomplish the same task. The excerpts below present just one possible way.

    Rather than include the entire XSL program each time, I've only included the rules that are added or replace ones found in the original addresstest.xsl file.

    
    <xsl:template match="entry">
     - <xsl:value-of select="name" />: <xsl:for-each select="address"> <xsl:value-of select="city" />, <xsl:value-of select="state" />, <xsl:value-
    of select="country" />
     </xsl:for-each>
    </xsl:template>
    
    

  3. Modify your program such that it enumerates the matches, like so (don't worry about getting the spacing exactly right, but include the commas):
     Names of people in addressbook:
    
    1. George W. Bush, Washington, DC, USA
    2. Stewart M. Clamen, Glassboro, NJ, USA
    3. Osama bin Laden
    4. Harry Potter, Little Whinging, England, United Kingdom
    
    (done)  
    

    
    
    <xsl:template match="address">, <xsl:value-of select="city" />, <xsl:value-of select="state" />, <xsl:value-of select="country" />
    
    
    
    <xsl:template match="name">
    <xsl:number count="entry" />. <xsl:value-of select="." /> <xsl:apply-templates />
    </xsl:template>
    
    <!-- This rule adds the newline between entries -->
    <xsl:template match="entry">
    <xsl:apply-templates />
    <xsl:text>
    </xsl:text>
    </xsl:template>
    
    

  4. Modify your program such that it only returns the American entries, like so:
    Names of people in addressbook:
    
    1. George W. Bush, Washington, DC, USA
    2. Stewart M. Clamen, Glassboro, NJ, USA
    
    (done)  
    

    
    
    <xsl:template match="address">, <xsl:value-of select="city" />, <xsl:value-of select="state" />, <xsl:value-of select="country" />
    
    </xsl:template>
    
    <xsl:template match="name">
     <xsl:value-of select="." />
    </xsl:template>
    
    
    <!-- Rule to catch entries with American address -->
    <xsl:template match="entry[address/country = 'USA']">
     <xsl:number count="entry[address/countr = 'USA']" />. <xsl:apply-templates/>
    <xsl:text>
    </xsl:text>
    </xsl:template>
    
    <!-- Rule to catch all other entries -->
    <xsl:template match="entry"/>
    
    
  5. Modify your program such that it only returns the entries with a known address, like so:
    Names of people in addressbook:
    
    1. George W. Bush, Washington, DC, USA
    2. Stewart M. Clamen, Glassboro, NJ, USA
    3. Harry Potter, Little Whinging, England, United Kingdom
    
    (done)  
    

    
    
    <xsl:template match="address">, <xsl:value-of select="city" />, <xsl:value-of select="state" />, <xsl:value-of select="country" />
    
    </xsl:template>
    
    <xsl:template match="name">
     <xsl:value-of select="." />
    </xsl:template>
    
    
    <!-- Rule to catch entries with address subfields -->
    <xsl:template match="entry[address]">
     <xsl:number count="entry[address]" />. <xsl:apply-templates/>
    <xsl:text>
    </xsl:text>
    </xsl:template>
    
    <!-- Rule to catch all other entries -->
    <xsl:template match="entry"/>
    
    

  6. Look at the XML document database.xml in the Public area. It represents a (short) transaction log for a set of bank accounts. bank.xsl is a program which tabulates the withdrawals for a single account.

    Modify bank.xsl such that it tabulates deposits as well.

    Replace the "/BANK_TRANSACTIONS" rule with the following:

    
    <xsl:template match="/BANK-TRANSACTIONS">
    Bank report for Account #<xsl:value-of select="$currentaccount" />:
    
    <xsl:variable name="withdrawals">
    <xsl:value-of select="sum(TRANSACTION[@withdrawal and @account=$currentaccount]/@withdrawal)"/>
    </xsl:variable>
    
    <xsl:variable name="deposits">
    <xsl:value-of select="sum(TRANSACTION[@deposit and @account=$currentaccount]/@deposit)"/>
    </xsl:variable>
    
    <xsl:value-of select="count(TRANSACTION[@deposit and @account=$currentaccount])"/> deposits totalling $<xsl:number value="$deposits"/>
    <!-- insert newline -->
    <xsl:text>
    </xsl:text>
    <xsl:value-of select="count(TRANSACTION[@withdrawal and @account=$currentaccount])"/> withdrawals totalling $<xsl:number value="$withdrawals"/>
    
    .
    </xsl:template>
    
    

  7. Modify your program to consider for the initial bank account balance, and include a tabulation of the bank account's balance. It should look something like:
    Bank report for Account #123456:
    
    1 withdrawals totalling $45
    3 deposits totalling $1501.5
    
    Total balance: $4546.62
    
    .
    

    XSL likes to drop off trailing zeroes by default.

    Replace the "/BANK_TRANSACTIONS" rule with the following:

    
    <xsl:template match="/BANK-TRANSACTIONS">
    Bank report for Account #<xsl:value-of select="$currentaccount" />:
    
    <xsl:variable name="init">
    <xsl:value-of select="INITIALIZE[@account=$currentaccount]/@balance"/>
    </xsl:variable>
    
    <xsl:variable name="withdrawals">
    <xsl:value-of select="sum(TRANSACTION[@withdrawal and @account=$currentaccount]/@withdrawal)"/>
    </xsl:variable>
    
    <xsl:variable name="deposits">
    <xsl:value-of select="sum(TRANSACTION[@deposit and @account=$currentaccount]/@deposit)"/>
    </xsl:variable>
    
    <xsl:value-of select="count(TRANSACTION[@withdrawal and @account=$currentaccount])"/> withdrawals totalling $<xsl:value-of select="$withdrawals" />
    <xsl:text>
    </xsl:text>
    <xsl:value-of select="count(TRANSACTION[@deposit and @account=$currentaccount])"/> deposits totalling $<xsl:value-of select="$deposits" />
    
    Total balance: $<xsl:value-of select="$withdrawals + $deposits + $init"/>
    .
    </xsl:template>
    
    
  8. For bonus points, modify the program such that it says "deposit" ("withdrawal") when the count is 1.

    Replace the "/BANK_TRANSACTIONS" rule with the following:

    
    <xsl:template match="/BANK-TRANSACTIONS">
    Bank report for Account #<xsl:value-of select="$currentaccount" />:
    
    <xsl:variable name="init">
    <xsl:value-of select="INITIALIZE[@account=$currentaccount]/@balance"/>
    </xsl:variable>
    
    <xsl:variable name="withdrawals">
    <xsl:value-of select="sum(TRANSACTION[@withdrawal and @account=$currentaccount]/@withdrawal)"/>
    </xsl:variable>
    
    <xsl:variable name="deposits">
    <xsl:value-of select="sum(TRANSACTION[@deposit and @account=$currentaccount]/@deposit)"/>
    </xsl:variable>
    
    <xsl:variable name="withdrawalsCnt">
    <xsl:value-of select="count(TRANSACTION[@withdrawal and @account=$currentaccount]/@withdrawal)"/>
    </xsl:variable>
    
    <xsl:variable name="depositsCnt">
    <xsl:value-of select="count(TRANSACTION[@deposit and @account=$currentaccount]/@deposit)"/>
    </xsl:variable>
    
    <xsl:value-of select="$withdrawalsCnt"/> withdrawal<xsl:if test="$withdrawalsCnt != 1">s</xsl:if> totalling $<xsl:value-of select="$withdrawals" />
    
    <xsl:value-of select="$depositsCnt"/> deposit<xsl:if test="$depositsCnt != 1">s</xsl:if> totalling $<xsl:value-of select="$deposits" />
    
    Total balance: $<xsl:value-of select="$withdrawals + $deposits + $init"/>
    .
    </xsl:template>