N341 Home Work 4 - Project |
Modified: |
Thanks to Ken Bell and Ryan Hughes for suggesting to use variables to simplify embedding values from XML into HTML. Much simpler than my method. The source reference is: http://www.w3.org/TR/xslt20/#attribute-value-templates
<FORM NAME=ONE>
<INPUT type=text name="TWO" >
</form>but has the following errors as XML/XSL:
- ONE must be quoted,
- text must be quoted,
- INPUT requires a matching end tag </INPUT>
- </form> must match <FORM>
Below is valid XML/XSL:
<FORM NAME="ONE">
<INPUT type="text" name="TWO"/>
</FORM>
IE caches files by default which can prevent opening of a later version. The effect is particularly noticeable during repeated tests when XML references an XSL file that has been changed but is not opened because of a cached version of the XSL.
The solution is to require IE to check for new versions on every visit to a page. In IE: Tools | Internet Options | Temporary Internet Files | Settings | Every Visit to Page
The following error may occur when accessing XML files downloaded from one computer to another such as the ZIP files for the assignment. Vista (and perhaps XP) blocks access to files, presumably attempting to protect you from using files you have copied to your computer.Unblock access to individual files by the following:
- Open in Windows Explorer the directory containing the file, either the XML file or one referenced by the XML.
- Right click on the file and open Properties.
- Click Unblock.
The XML page cannot be displayed
Cannot view XML input using XSL style sheet. Please correct the error and then click the Refresh button, or try again later.
Access is denied. Error processing resource 'file:///W:/N341/Project/TraderSummaryContent.htm'.
Unblock access to all files in a directory by the following:
- Download Streams, copy Streams.exe to Windows directory if possible.
- To unblock all the files in directory c:\temp and any subdirectories enter:
Streams –d –s c:\temp
The stock trading site has two main functions: managing access to the site
and managing site functions.

Managing access - Home work 3 completed the user interface for registration and logging in of stock traders and logging out the current trader out. The user view to manage access appears at right.

Managing function - This home work will complete the bulk of the user interface for the site function. The user view to manage site function appears at right. The new left menu provides access to the functions after user login, the center provides display of function results.
Our concern will be the user interface exclusively; managing the data and maintaining system integrity (i.e. programming logic) is the responsibility of software development. In the following, we will develop methods that allow testing each user interface module without the programming logic.
There are three main site functions.
User Interface - A common user interface structure with site navigation at top, application navigation at left and content in the center. Navigation will be completed in a later assignment.
For now, the major user interface content is implemented by the following style sheets:
The portfolio is the list of an individual's stock SYMBOL, stock NAME, SHARES owned, PRICE, STOCK VALUE and TOTAL worth. The PortfolioContent.htm style sheet transforms the following XML data set to the HTML rendering below.
Portfolio.XML<?xml-stylesheet type="text/xsl" href="PortfolioContent.htm"?>
<xml xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema">
<rs:data>
<z:row SYMBOL="MSFT" NAME="Microsoft" SHARES="100" PRICE="10.0000" STOCKVALUE="1000.0000"/>
<z:row SYMBOL="FORD" NAME="Ford Motor" SHARES="500" PRICE="15.6700" STOCKVALUE="7835.0000"/>
<z:row SYMBOL="IBM" NAME="IBM" SHARES="10" PRICE="15.0500" STOCKVALUE="150.5000"/>
</rs:data>
</xml>
|
PortfolioContent.htm <xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml"
xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema">
<xsl:output method="html" />
<xsl:template name="PortfolioContent">
<h1>Portfolio Summary</h1>
<xsl:for-each select="xml/rs:data/z:row">
<xsl:value-of select="@SYMBOL" /> - <xsl:value-of select="@SHARES" /> -
<xsl:value-of select="@PRICE" /> - <xsl:value-of select="@STOCKVALUE" /> <br />
</xsl:for-each>
</xsl:template>
<xsl:template match="/">
<xsl:call-template name="PortfolioContent" />
</xsl:template>
</xsl:stylesheet>
|
Portfolio SummaryMSFT - 100 - 10.0000 - 1000.0000FORD - 500 - 15.6700 - 7835.0000 IBM - 10 - 15.0500 - 150.5000 |
The key points to review are:
This is how all XML trees are defined (i.e. node names) when generated using the Microsoft MSXML2.DOMDocument class from a database in ASP programs.
|
The key improvement we will make is:
PortfolioContent.htm <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema">
<xsl:output method="html" />
<xsl:template name="PortfolioContent">
<h1>Portfolio</h1>
<table border="1">
<tr>
<td>Symbol</td>
<td>Shares</td>
<td>Price</td>
<td>Value</td>
</tr>
<xsl:for-each select="xml/rs:data/z:row">
<tr>
<td><xsl:value-of select="@SYMBOL" /></td>
<td><xsl:value-of select="@SHARES" /></td>
<td><xsl:value-of select="format-number(@PRICE, '$#,###,###.00')" /></td>
<td><xsl:value-of select="format-number(@STOCKVALUE, '$#,###,###.00')" /></td>
</tr>
</xsl:for-each>
<tr>
<td></td>
<td></td>
<td>Total</td>
<td>
<xsl:value-of select="format-number(sum(xml/rs:data/z:row/@STOCKVALUE), '$#,###,###.00')" />
</td>
</tr>
</table>
</xsl:template>
<xsl:template match="/">
<xsl:call-template name="PortfolioContent" />
</xsl:template>
</xsl:stylesheet>
|
||||||||||||||||||||||||||||||||
Portfolio
|
|
The trader summary is the account information of trader's ID, FIRSTNAME, LASTNAME, and BALANCE.
The XML below for testing has been copied to the Project directory. TraderSummaryContent.htm remains for you to create.
TraderSummary.XML<?xml-stylesheet type="text/xsl" href="TraderSummaryContent.htm"?> <xml xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema"> <rs:data> <z:row ID="Ray" FIRSTNAME="Raymond" LASTNAME="Wisman" BALANCE="990.0000"/> </rs:data> </xml> |
|
Trader Summary
ID First Last Balance Ray Raymond Wisman $990.00

<form name="StockListForm" method="get" action="BuyStock.asp">
The XML below for testing has been copied to the Project directory.
BuyList.XML<?xml-stylesheet type="text/xsl" href="BuyListContent.htm"?> <xml xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema"> <rs:data> <z:row SYMBOL="MSFT" NAME="Microsoft" PRICE="10.0000"/> <z:row SYMBOL="GMC" NAME="General Motors" PRICE="38.1000"/> <z:row SYMBOL="FORD" NAME="Ford Motor" PRICE="15.6700"/> <z:row SYMBOL="UAL" NAME="United Airlines" PRICE="7.6400"/> <z:row SYMBOL="IBM" NAME="IBM" PRICE="15.0500"/> </rs:data> </xml> |
|
Sample HTML generated
| <h1>Buy Stock</h1> <form name="StockListForm" method="get" action="BuyStock.asp"> <table border="1"> <tr> <td>Symbol</td> <td>Name</td> <td>Price</td> <td>Number</td> </tr> <tr> <td>MSFT</td> <td>Microsoft</td> <td>$10.00</td> <td> <input Type="TEXT" Name="MSFT" value="0" size="4"/> </td> </tr> <tr> <td>GMC</td><td>General Motors</td><td>$38.10</td><td> <input Type="TEXT" Name="GMC" value="0" size="4"/> </td> </tr> </table> <input type="submit"/> </form> |
Debugging
Often we need to see the HTML produced by the style sheet for debugging. The browser source view only displays the XML file, not useful when debugging style sheets.
|

<form name="StockSellForm" method="get" action="SellStock.asp">
The below XML for testing has been copied to the Project directory.
SellList.XML<?xml-stylesheet type="text/xsl" href="SellListContent.htm"?> <xml xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema"> <rs:data> <z:row SYMBOL="MSFT" NAME="Microsoft" SHARES="100" PRICE="10.0000" STOCKVALUE="1000.0000"/> <z:row SYMBOL="FORD" NAME="Ford Motor" SHARES="500" PRICE="15.6700" STOCKVALUE="7835.0000"/> <z:row SYMBOL="IBM" NAME="IBM" SHARES="10" PRICE="15.0500" STOCKVALUE="150.5000"/> </rs:data> </xml> |
The solution is nearly the same as BuyListContent.htm.
|

<form name="CartListForm" method="get" action="CartEdit.asp">
The below XML for testing has been copied to the Project directory.
CartSummary.XML<?xml-stylesheet type="text/xsl" href="CartSummaryContent.htm"?> <xml xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema"> <rs:data> <z:row TRADEID="95" ID="Ray" SYMBOL="IBM" PRICE="20.0000" SHARES="5" BUY="False"/> <z:row TRADEID="100" ID="Ray" SYMBOL="MSFT" PRICE="10.0000" SHARES="10" BUY="True"/> <z:row TRADEID="101" ID="Ray" SYMBOL="MSFT" PRICE="10.0000" SHARES="100" BUY="False"/> </rs:data> </xml> |
The solution is similar to BuyListContent.htm and SellListContent.htm.
|
Sample HTML generated
| <h1>Stock Cart Contents</h1> <form name="CartEditForm" method="get" action="CartEdit.asp"> <table border="1"> <tr> <td>Trade</td><td>Symbol</td><td>Number</td><td>Price</td><td>Buy/Sell</td><td>Remove</td> </tr> <tr> <td>95</td><td>IBM</td><td>5</td><td>$20.00</td><td>Sell</td><td><input Type="checkbox" Name="95"/></td> </tr> <tr> <td>100</td><td>MSFT</td><td>10</td><td>$10.00</td><td>Buy</td><td><input Type="checkbox" Name="100"/></td> </tr> </table> <input type="submit"/> </form> |
The improvement below adds JavaScript to generate a line chart showing price of each stock in the portfolio.
PortfolioContent.htm <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns="http://www.w3.org/1999/xhtml"
xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema">
<xsl:output method="html" />
<xsl:template name="PortfolioContent">
<h1>Portfolio</h1>
<table border="1">
<tr>
<td>Symbol</td>
<td>Shares</td>
<td>Price</td>
<td>Value</td>
</tr>
<xsl:for-each select="xml/rs:data/z:row">
<tr>
<td><xsl:value-of select="@SYMBOL" /></td>
<td><xsl:value-of select="@SHARES" /></td>
<td><xsl:value-of select="format-number(@PRICE, '$#,###,###.00')" /></td>
<td><xsl:value-of select="format-number(@STOCKVALUE, '$#,###,###.00')" /></td>
</tr>
</xsl:for-each>
<tr>
<td></td>
<td></td>
<td>Total</td>
<td>
<xsl:value-of select="format-number(sum(xml/rs:data/z:row/@STOCKVALUE), '$#,###,###.00')" />
</td>
</tr>
</table>
</xsl:template>
<xsl:template match="/">
<xsl:call-template name="PortfolioContent" />
</xsl:template>
</xsl:stylesheet>
|
|
|
Portfolio.xml <?xml-stylesheet type="text/xsl" href="PortfolioContent.htm"?>
|
Hints
|
Explanation of JavaScript
In Homework 3 we saw how to access a XML file and how to produce a hard-coded Google chart, here we combine these ideas to produce the chart dynamically from the XML data.Associative arraysIn JavaScript, simply using an array creates the entry.x[3] = "IBM";One new concept used here is associative arrays. Arrays are indexed, commonly by an integer:x[3] = "IBM";y[ i ] = 130.75;JavaScript also supports associative arrays which can be indexed by a string:s["PRICE"] = 130.75;z["SYMBOL"] = "IBM";One difference of associative arrays is iterating, since the index can be any string, the index is not predefined.A for-statement that returns the index can be used, for example:labels["MSFT"] = 10; labels["FORD"] = 20; labels["IBM"] = 30;for(var i in labels) document.write( i + " is " + labels[ i ] + "<br/>");writes:MSFT is 10 FORD is 20 IBM is 30
The key JavaScript concepts are:
| elementArray = xmlDoc.getElementsByTagName('xml/rs:data/z:row'); |
Create array with the elements for each row of the XML. You can think of elementArray[0] with the values from the first row of the XML:
|
|
| labels = new Array(); | Create an array named labels. | |
| elementArray[ 0 ].attributes.getNamedItem("SYMBOL").value | From the first XML row, i=0, the value is "MSFT". | |
| for(i=0; i != elementArray.length; i++) labels[elementArray[i].attributes.getNamedItem("SYMBOL").value]=0; |
Purpose is to create and initialize labels array entries to 0. Iterate over all the 0, 1, 2 rows, elementArray.length is 3 for the XML below. When i=0, we set: labels["MSFT"]=0 |
|
| elementArray[i].attributes.getNamedItem("PRICE").value | From the first XML row, i=0, the PRICE value is "10.0000". Convert to a float value. |
|
| for(i=0; i != elementArray.length; i++) labels[elementArray[i].attributes.getNamedItem("SYMBOL").value]= labels[elementArray[i].attributes.getNamedItem("SYMBOL").value] + parseFloat(elementArray[i].attributes.getNamedItem("PRICE").value); |
Sum the PRICE for each SYMBOL. labels["MSFT"] = labels["MSFT"] + 10.0 |
|
| max = Math.max( max,labels[elementArray[i].attributes.getNamedItem("SYMBOL").value]); |
Google charts does not automatically scale data. Scale from 0 to maximum. |
|
| for( var i in labels ) { chartLabels = chartLabels + i + " $" + labels[i]+"|"; chartData = chartData + labels[i]+","; } |
The index, i, is MSFT, etc. then
label[i] is 1000.00, etc. Create chart labels by concatenating: "MSFT" + "$" + "10.0000" + "|", or "MSFT $10.0000|" MSFT $10.00|FORD $15.67|IBM $15.05| Create chart data by concatenating: "10.00" + ",", or "10.00," 10,15.67,15.05, |
|
| chartData=chartData.substring(0,chartData.length-1); chartLabels=chartLabels.substring(0,chartLabels.length-1); |
Remove the extra "|" and ",". | |
| Final result, note that the & of the JavaScript are converted to &. |
<img src="http://chart.apis.google.com/chart?cht=lc&chs=375x150& chl=MSFT $10.00|FORD $15.67|IBM $15.05&chd=t:10,15.67,15.05&chds=0,15.67 "/> |
Portfolio.XML <?xml-stylesheet type="text/xsl" href="PortfolioContent.htm"?> <xml xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema"> <rs:data> <z:row SYMBOL="MSFT" NAME="Microsoft" SHARES="100" PRICE="10.0000" STOCKVALUE="1000.0000"/> <z:row SYMBOL="FORD" NAME="Ford Motor" SHARES="500" PRICE="15.6700" STOCKVALUE="7835.0000"/> <z:row SYMBOL="IBM" NAME="IBM" SHARES="10" PRICE="15.0500" STOCKVALUE="150.5000"/> </rs:data> </xml>
Enhancement understanding
For testing purposes, we GET a XML file:req.open("GET", "Portfolio.xml", false);In practice, even though the same file name (Portfolio.xml) is used for XSL and JavaScript, a Web server would over-write the same file with data for different users.The correct solution is for the server to execute a program to produce the XML for the current user.The change is minor to execute PortfolioXML.asp and generate the most up-to-date XML:req.open("GET", "PortfolioXML.asp", false);Of course, someone would need to implement the on PortfolioXML.asp the server, perhaps the N342 class? The ASP script using the project database would be:
PortfolioXML.asp <%@ Language=JScript%>
<%
conn = Server.CreateObject("ADODB.Connection");
conn.Mode = 3;
conn.Open ("DRIVER={Microsoft Access Driver (*.mdb)};DBQ=" +
Server.MapPath("Project.mdb"));
rs = conn.Execute("SELECT * FROM PORTFOLIO");
var xmlDoc = Server.CreateObject("Msxml2.DOMDocument");
xmlDoc.async = false;
rs.Save (xmlDoc, 1) ; // Convert rs recordset to xmlDoc as XML tree
xmlDoc.Save (Response, 1); // Output XML as Response
conn.Close();
%>
- Modify listing of current stock holdings to include stock name (PortfolioContent.htm) and a pie chart of stock values.
- List the trader summary (TraderSummaryContent.htm).
- List available stocks to buy (BuyListContent.htm).
- List stocks owned to sell (SellListContent.htm).
- List shopping cart contents (CartSummaryContent.htm).