N342 ASP ADO XML XSL

Modified

Note

IE caches files by default which can prevent opening of a later version. The effect is particularly noticeable during repeated tests of HTML forms referencing ASP files that have been changed but are not opened because of a cached version of the HTML.

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

 

Basics

Mixing ASP JavaScript, HTML, SQL, etc. in ASP scripts produces hard to write and read scripts that entangle the logic with the user interface. We have also seen that XML data can be transformed by XSL to generate HTML, very useful in separating representation data from its presentation.

Our goal is to separate the program logic from the user interface, allowing programmers and user interface designers to work somewhat independently. With data maintained mostly in databases, we will develop patterns for transforming the database tables into the dynamic part of the user interface. Our end result will be an ASP program to interact with the user and access data bases and XSL to present the user interface and data.

First an example of ASP and databases that combines the logic and user interface then a review of database tables, XML and XSL.

Access Database

Let's examine an Access database table first. The Portfolio table at right has 3 traders, 6 records, each with 4 fields: STOCKID, ID, SYMBOL and SHARES. Generally our ASP programs will be reading and updating the tables but, of course, we can use the Access application to do the same operations.

Exercise  0 - Access

  1. Open Access from Start | Programs | Microsoft Access

  2. Open File | Open... and select W:\N342\Project\Project.mdb

  3. Select Tables | PORTFOLIO

  4. Add 3 new records with fields ID, SYMBOL and SHARES

  5. Save and close the table.

 

ASP and Database

We will use the Portfolio table from the Stock Trading project as an example case.

To display the table contents in HTML for a browser we will need to:

  1. Select the records and fields to recordset named rs
     
  2. Iterate through all records
     
  3. Transform the data into HTML for a table
Portfolio.ASP

<%@ Language=JScript%>
<%
 var conn = Server.CreateObject("ADODB.Connection");
 conn.Open ("DRIVER={Microsoft Access Driver (*.mdb)};DBQ=" +
                    Server.MapPath("Project.mdb"));

 var rs = conn.Execute("SELECT * FROM Portfolio;");

 Response.Write(
      "<table border='1'><tr>" +
     "  <td>ID</td><td>Symbol</td></tr>");

 while (!rs.EOF) {
     Response.Write(
           "<tr><td>" + rs("ID")+ "</td>" +
           "<td>" + rs("SYMBOL") + "</td></tr>");
     rs.MoveNext();
 }

 Response.Write("</table>");
 conn.Close();
%>

Table and
partial HTML produced

 
ID Symbol
Ray IBM
Ray MSFT
Harold FORD
Robin UAL
<table border="1" >
  <tr>
	<td>ID</td>
	<td>Symbol</td>
  </tr>
  <tr>
	<td>Ray</td>
	<td>IBM</td>
  </tr>
  <tr>
	<td>Ray</td>
	<td>MSFT</td>
  </tr>
  <tr>
	<td>Harold</td>
	<td>FORD</td>
  </tr>
  <tr>
	<td>Robin</td>
	<td>UAL</td>
  </tr>

Although a table is produced, the weakness of this solution is that program logic and generation of the user interface (e.g. the table) are combined.

Program logic requires a programmer; the user interface requires the user interface designer to design and test the interface; and a programmer must make any changes to the code.

For greater separation of the programming logic and the user interface, the programmer implementing the program logic and the interface designer implementing the interface need to be able to work only on their separate parts of the system.

Exercise  0.5 - ASP

  1. Open FrontPage

  2. Open File | New

  3. Copy, paste and save the above Portfolio.asp to a virtual drive (e.g. W:\N342\Project).

  4. Test by loading Portfolio.asp into the browser (e.g. http://iu-uits-ediwp1.ads.iu.edu/username/N342/Project/Portfolio.asp).
     

  5. Change the Portfolio.asp to display SHARES also.

  6. Test by loading Portfolio.asp into the browser (e.g. http://iu-uits-ediwp1.ads.iu.edu/username/N342/Project/Portfolio.asp)

 

XML and XSL Transformations - A Review

We will again use the Portfolio table from the Stock Trading project as an example case. The table with three traders appears at right.

The Portfolio database table can be represented as the XML structure below:

We have seen how Portfolio.xml can be transformed using XSL to HTML for the browser.

The following is the PortfolioContent.xsl to perform the transformation, yielding the same result as Portfolio.ASP earlier.

Portfolio.XML
<?xml-stylesheet type="text/xsl"
      href="PortfolioContent.xsl"?>
<xml
   xmlns:rs="urn:schemas-microsoft-com:rowset"
   xmlns:z="#RowsetSchema">
   <rs:data>
     <z:row ID="Ray" SYMBOL="IBM" SHARES="10"/>
     <z:row ID="Ray" SYMBOL="MSFT" SHARES="100"/>
     <z:row ID="Harold" SYMBOL="FORD" SHARES="15"/>
     <z:row ID="Robin" SYMBOL="UAL" SHARES="230"/>
     <z:row ID="Robin" SYMBOL="FORD" SHARES="100"/>
     <z:row ID="Harold" SYMBOL="GMC" SHARES="20"/>
   </rs:data>
</xml>
 


ID Symbol
Ray IBM
Ray MSFT
Harold FORD
Robin UAL
Robin FORD
Harold GMC
HTML output

<table border="1" >
  <tr>
         <td>ID</td>
         <td>Symbol</td>
  </tr>
  <tr>
         <td>Ray</td>
         <td>IBM</td>
  </tr>
  <tr>
         <td>Ray</td>
         <td>MSFT</td>
  </tr>
  <tr>
         <td>Harold</td>
         <td>FORD</td>
  </tr>
  <tr>
         <td>Robin</td>
         <td>UAL</td>
  </tr>
  <tr>
         <td>Robin</td>
         <td>FORD</td>
  </tr> 
  <tr>
         <td>Harold</td>
         <td>GMC</td>
  </tr>
 </table>
PortfolioContent.xsl

 <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>Exercise 1 and 2</h1>
   <table border="1">
     <tr>
       <td>ID</td>
       <td>Symbol</td>
 
    </tr>

    <xsl:for-each select="xml/rs:data/z:row">
     <tr>
        <td><xsl:value-of select="@ID" /></td>
        <td><xsl:value-of select="@SYMBOL" /></td>

     </tr>
    </xsl:for-each>

   </table>
  </xsl:template>

  <xsl:template match="/">
       <xsl:call-template name="PortfolioContent" />
  </xsl:template>

</xsl:stylesheet>

 

At this point, we used the IE browser to combine XML and XSL to display a HTML page.

The approach is illustrated below where the XML file references the XSL file when loaded to display a table based upon the data structure defined in XML. 

How it works 

  1. IE browser loads and parses the XML file into a tree. 
  2. XSL style sheet file is loaded and parsed to transform the tree.
  3. Transformed XML by XSL produces an HTML result.
  4. IE renders the HTML to display.

Exercise  1 - XML XSL

  1. Copy and paste the above Portfolio.xml and PortfolioContent.xsl to a virtual drive (e.g. W:\N342\Project).

  2. Test by loading Portfolio.xml into the IE browser (e.g. http://iu-uits-ediwp1.ads.iu.edu/username/N342/Project/Portfolio.xml).
     

  3. Change the PortfolioContent.xsl to display SHARES also.

  4. Test by loading Portfolio.xml into the IE browser.

 

ASP with XML and XSL

Combining XML and XSL on the browser has several drawbacks:

  1. The browser may not be XML-capable for performing the XML/XSL to HTML transformation

  2. XML data is static rather than extracted dynamically from a database.

Combining XML and XSL on the server running an ASP program rather than on the browser client has three key advantages:

  1. The XML can be generated dynamically by the server through user interaction, extraction from a database, etc.

  2. HTML can be produced as a result of the XML/XSL transformations, the browser does not need to be XML-capable.

  3. The XML/XSL tree can be modified before writing to the client.

The simplest use is to combine XML and XSL on the server in ASP to apply the transformations and write out the result as HTML. The following ASP example:

  1. builds the XML tree named xml from the Portfolio.xml file: xml.load(Server.MapPath("Portfolio.xml"));

  2. builds the XSL tree named xsl from the PortfolioContent.xsl file: xsl.load(Server.MapPath("PortfolioContent.xsl"));

  3. transforms the XML tree to HTML by applying the XSL: xml.transformNode(xsl)

  4. writes the transformed tree to browser as HTML: Response.Write

Portfolio.asp

<%@ LANGUAGE = JScript %>
<%
  // Load the XML
  var xml = Server.CreateObject("MSXML2.DOMDocument");
  xml.async = false;
  xml.load(Server.MapPath("Portfolio.xml"));

  // Load the XSL
  var xsl = Server.CreateObject("MSXML2.DOMDocument");
  xsl.async = false;
  xsl.load(Server.MapPath("PortfolioContent.xsl"));

  Response.Write( xml.transformNode( xsl ) );
%>


Portfolio.XML
<?xml-stylesheet type="text/xsl"
      href="PortfolioContent.xsl"?>
<xml
   xmlns:rs="urn:schemas-microsoft-com:rowset"
   xmlns:z="#RowsetSchema">
   <rs:data>
     <z:row ID="Ray" SYMBOL="IBM" SHARES="10"/>
     <z:row ID="Ray" SYMBOL="MSFT" SHARES="100"/>
     <z:row ID="Harold" SYMBOL="FORD" SHARES="15"/>
     <z:row ID="Robin" SYMBOL="UAL" SHARES="230"/>
     <z:row ID="Robin" SYMBOL="FORD" SHARES="100"/>
     <z:row ID="Harold" SYMBOL="GMC" SHARES="20"/>
   </rs:data>
</xml>
PortfolioContent.xsl

 <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>Exercise 1 and 2</h1>
   <table border="1">
     <tr>
       <td>ID</td>
       <td>Symbol</td>
 
    </tr>

    <xsl:for-each select="xml/rs:data/z:row">
     <tr>
        <td><xsl:value-of select="@ID" /></td>
        <td><xsl:value-of select="@SYMBOL" /></td>

     </tr>
    </xsl:for-each>

   </table>
  </xsl:template>

  <xsl:template match="/">
       <xsl:call-template name="PortfolioContent" />
  </xsl:template>

</xsl:stylesheet>
 

 

 


 

 

Exercise  2 - ASP XML XSL

  1. Copy and paste the above Portfolio.ASP to a virtual drive (e.g. W:\N342\Project).

  2. Test by loading Portfolio.ASP into the browser (e.g. http://iu-uits-ediwp1.ads.iu.edu/username/N342/Project/Portfolio.asp).
     

  3. Results should be the same as Exercise 1.

  4. In IE browser, Page | View Source, to examine the HTML output from the ASP.

 

XML and Database

XML can be dynamically generated dynamically from a database rather than loading static XML from a file. The following example:

  1. selects all records from the Portfolio database table - "SELECT ID, SYMBOL FROM Portfolio"
  2. constructs the XML parse tree xmlDoc from the table - rs.Save (xmlDoc, 1);
  3. Saves the XML tree, not necessary but useful to understand the database to XML conversion - xmlDoc.save(Server.MapPath("FromPortfolio.xml"))
  4. applies the XSL transformations from file PortfolioContent.xsl to the xmlDoc tree. The transformation generates a table of ID and SYMBOL - xmlDoc.transformNode(xsl)
  5. writes the transformed tree to the browser as HTML

Note that database table field names are transformed to XML attributes.

For example, the first table row entry for fields ID and SYMBOL is XML:

 <z:row ID="Ray" SYMBOL="IBM"/>.

Portfolio.ASP

<%@ Language=JScript%>
<%
   conn = Server.CreateObject("ADODB.Connection");
   conn.Open ("DRIVER={Microsoft Access Driver (*.mdb)};DBQ=" +
                      Server.MapPath("Project.mdb"));

   rs = conn.Execute("SELECT ID, SYMBOL FROM Portfolio");

   var xmlDoc = Server.CreateObject("Msxml2.DOMDocument");
   xmlDoc.async = false;

   rs.Save (xmlDoc, 1) ;    
 
        // Convert rs recordset to XML tree
         // Save as XML (not required)
  xmlDoc.save(Server.MapPath("FromPortfolio.xml"))

   var xsl = Server.CreateObject("Msxml2.DOMDocument");
   xsl.async = false;          
   
      // Convert XML tree using XSL  

   xsl.load(Server.MapPath("PortfolioContent.xsl"))
        // Write tree as HTML
   Response.Write( xmlDoc.transformNode( xsl ) );
   conn.Close();
%>

Portfolio Table and HTML produced 


 

 


ID Symbol
Ray IBM
Ray MSFT
Harold FORD
Robin UAL
Robin FORD
Harold GMC
HTML output

<table border="1" >
  <tr>
         <td>ID</td>
         <td>Symbol</td>
  </tr>
  <tr>
         <td>Ray</td>
         <td>IBM</td>
  </tr>
  <tr>
         <td>Ray</td>
         <td>MSFT</td>
  </tr>
  <tr>
         <td>Harold</td>
         <td>FORD</td>
  </tr>
  <tr>
         <td>Robin</td>
         <td>UAL</td>
  </tr>
  <tr>
         <td>Robin</td>
         <td>FORD</td>
  </tr> 
  <tr>
         <td>Harold</td>
         <td>GMC</td>
  </tr>
 </table>
PortfolioContent.xsl

 <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>Exercise 1 and 2</h1>
   <table border="1">
     <tr>
       <td>ID</td>
       <td>Symbol</td>
 
    </tr>

    <xsl:for-each select="xml/rs:data/z:row">
     <tr>
        <td><xsl:value-of select="@ID" /></td>
        <td><xsl:value-of select="@SYMBOL" /></td>

     </tr>
    </xsl:for-each>

   </table>
  </xsl:template>

  <xsl:template match="/">
       <xsl:call-template name="PortfolioContent" />
  </xsl:template>

</xsl:stylesheet>
XML saved to file FromPortfolio.xml by rs.Save (xmlDoc, 1);   
<xml xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882"
    xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882"
    xmlns:rs="urn:schemas-microsoft-com:rowset" xmlns:z="#RowsetSchema">


 <s:Schema id="RowsetSchema">
     <s:ElementType name="row" content="eltOnly">
        <s:AttributeType name="ID" rs:number="1" rs:nullable="true" rs:write="true">
           <s:datatype dt:type="string" dt:maxLength="20"/>
        </s:AttributeType>
        <s:AttributeType name="SYMBOL" rs:number="2" rs:nullable="true" rs:write="true">
           <s:datatype dt:type="string" dt:maxLength="5"/>
        </s:AttributeType>
        <s:AttributeType name="SHARES" rs:number="3" rs:nullable="true" rs:write="true">
           <s:datatype dt:type="int" dt:maxLength="4" rs:precision="10" rs:fixedlength="true"/>
         </s:AttributeType>
         <s:extends type="rs:rowbase"/>
      </s:ElementType>
 </s:Schema>

 <rs:data>
   <z:row ID="Ray" SYMBOL="IBM" SHARES="10"/>
   <z:row ID="Ray" SYMBOL="MSFT" SHARES="100"/>
   <z:row ID="Harold" SYMBOL="FORD" SHARES="15"/>
   <z:row ID="Robin" SYMBOL="UAL" SHARES="230"/>
   <z:row ID="Robin" SYMBOL="FORD" SHARES="100"/>
   <z:row ID="Harold" SYMBOL="GMC" SHARES="20"/>
 </rs:data>
</xml>

 

Exercise  3 - ASP XML XSL Database

  1. Copy and paste Portfolio.ASP to a virtual drive (e.g. W:\N342\Project). Modify to select SHARES also.
  2. Copy and paste PortfolioContent.xsl same directory. Modify to output a column for SHARES.
     
  3. Test by loading Portfolio.ASP into the browser (e.g. http://iu-uits-ediwp1.ads.iu.edu/username/N342/Project/Portfolio.asp).
  4. In browser, Page | View Source, to examine the HTML output from the ASP.

Portfolio.ASP generated XML and saved as FromPortfolio.xml, the recordset produced by: SELECT ID, SYMBOL FROM Portfolio

Below we'll again let the IE browser apply the transformations of PortfolioContent.xsl to the XML in FromPortfolio.xml file.

  1. Open FromPortfolio.xml in FrontPage. This was produced by Portfolio.ASP from the Portfolio database table.
  2. Insert as the top line:
    • <?xml-stylesheet type="text/xsl"  href="PortfolioContent.xsl"?>
  3. Test by loading FromPortfolio.xml into browser (i.e. http://iu-uits-ediwp1.ads.iu.edu/username/N342/Project/FromPortfolio.xml).
  4. The results should be identical to executing the Portfolio.ASP script.

 

Join Database Tables

Combining or joining data from several database table sources is a fundamental operation of relational database systems. For the project, we will often need to combine data from two or more table through defined relationships.

Consider the data needed to produce a portfolio.

The complete portfolio includes a list of stock symbols, number of shares and total value of each stock.

The necessary data is held in the two tables: Portfolio and Stock.

The two tables share a common field, SYMBOL, that defines a many to one relation from Portfolio to Stock (i.e. there are many FORD symbols in Portfolio to one FORD symbol in Stock).

To produce trader Harold's portfolio requires data from both tables, ID='Harold', SHARES and SYMBOL from Portfolio; and PRICE for the corresponding SYMBOL from Stock table.

Logically, we first need all the "Harold" Portfolio records and all the Stock records where the SYMBOL matches.

In database terms, we need a new table from joining the tables when the Portfolio SYMBOL = Stock SYMBOL.

The SQL statement giving all fields from records with SYMBOL matching in the Portfolio and Stock tables is:

SELECT * FROM STOCK INNER JOIN PORTFOLIO ON STOCK.SYMBOL = PORTFOLIO.SYMBOL;

Reducing the fields to those needed:

SELECT PORTFOLIO.ID, PORTFOLIO.SYMBOL, PORTFOLIO.SHARES, STOCK.NAME, STOCK.PRICE

    FROM STOCK INNER JOIN PORTFOLIO ON STOCK.SYMBOL = PORTFOLIO.SYMBOL;

and produces the following new table of records.

The INNER JOIN is also know more intuitively as the EQUI-JOIN.

Since we wanted Harold's portfolio, we need to keep only records where ID='Harold' by:

SELECT PORTFOLIO.ID, PORTFOLIO.SYMBOL, PORTFOLIO.SHARES, STOCK.NAME, STOCK.PRICE

           FROM STOCK INNER JOIN PORTFOLIO ON STOCK.SYMBOL = PORTFOLIO.SYMBOL WHERE ID='Harold';

The figure at right illustrates that the Stock and Portfolio tables are input to the Portfolio program which outputs the results of applying PortfolioContent.

The ASP and XSL to produce Harold's portfolio is given below.

Notice that only the SELECT statement changed in the ASP from our previous example. Here we only need the SYMBOL and PRICE.

The XSL file, PortfolioContent.xsl must be changed to accommodate displaying the PRICE field.

Note also that the SELECT must specify both the table and field when the field is defined in both tables (e.g. Portfolio.SYMBOL).

Portfolio.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 PORTFOLIO.SYMBOL, PRICE " +
     "FROM STOCK INNER JOIN PORTFOLIO ON " +
     "STOCK.SYMBOL = PORTFOLIO.SYMBOL " +
     "WHERE ID='Harold';");

   var xmlDoc = Server.CreateObject("Msxml2.DOMDocument");
   xmlDoc.async = false;
   rs.Save (xmlDoc, 1) ;             // Convert recordset to XML
                                             // Save as XML
   var xsl = Server.CreateObject("Msxml2.DOMDocument");
   xsl.async = false;                 // Convert XML tree using XSL  
   xsl.load(Server.MapPath("PortfolioContent.xsl"))
                                             // Write tree as HTML
   Response.Write(xmlDoc.transformNode(xsl));
   conn.Close();
%>

Table and partial HTML produced

Symbol Price
GMC 38.1000
FORD 15.6700
<table border="1">
 <tr>
	<td>Symbol</td>
	<td>Price</td>
 </tr>
 <tr>
	<td>GMC</td> <td>38.1000</td>
 </tr>
 <tr>
	<td>FORD</td> <td>15.6700</td>
 </tr>
</table>
PortfolioContent.xsl

<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>Exercise 4</h1>
   <table border="1">
     <tr>
       <td>Symbol</td>
       <td>Price</td>
     </tr>
     <xsl:for-each select="xml/rs:data/z:row">
        <tr>
         <td><xsl:value-of select="@SYMBOL" /></td>      
           <td><xsl:value-of select="@PRICE" /></td>
        </tr>
      </xsl:for-each>
    </table>
  </xsl:template>

  <xsl:template match="/">
       <xsl:call-template name="PortfolioContent" />
  </xsl:template>
</xsl:stylesheet>

Partial XML produced by rs.Save (xmlDoc, 1);   
<xml>
 <rs:data>
    <z:row SYMBOL="GMC" PRICE="38.1000"/>
    <z:row SYMBOL="FORD" PRICE="15.6700"/>
 </rs:data>
</xml>

 

Exercise  4 - ASP XML XSL Database Join

SQL

  1. Open the Project.mdb file in Access
  2. Click on Create | Query Design
  3. Close the Show Table dialog.
  4. Click in menu: SQL | View | SQL View
  5. Copy and paste the following.

    Change 'Harold' to an ID in your Portfolio table:

SELECT * FROM STOCK INNER JOIN PORTFOLIO ON STOCK.SYMBOL = PORTFOLIO.SYMBOL WHERE ID='Harold'
  1. Click in menu: Run
  2. Click in menu: View | SQL View
  3. Modify to select only PRICE, SHARES, Portfolio.SYMBOL and ID.
  4. Click in menu: Run

ASP/XSL

  1. Copy and paste Portfolio.ASP to a virtual drive (e.g. W:\N342\Project). Modify to select SHARES also.
  2. Copy and paste PortfolioContent.xsl same directory. Modify to output a column for SHARES.
  3. Test by loading Portfolio.ASP into the browser (e.g. http://iu-uits-ediwp1.ads.iu.edu/username/N342/Project/Portfolio.asp).
  4. In browser, Page | View Source, to examine the HTML output from the ASP.

 

Computing New Fields

The portfolio still needs a total value of each stock requiring the computation: STOCKVALUE = SHARES * PRICE. The SQL statement is:

The ASP and XSL to produce Harold's portfolio is given below. Notice that only the SELECT statement changed inx the ASP from our previous example.

Here we only need the SYMBOL, PRICE and computed STOCKVALUE.

The XSL file, PortfolioContent.xsl must be changed to display the STOCKVALUE field.

Portfolio.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 PORTFOLIO.SYMBOL, PRICE,  " +
     "SHARES*PRICE as STOCKVALUE " +
     "FROM STOCK INNER JOIN PORTFOLIO ON " +
     "STOCK.SYMBOL = PORTFOLIO.SYMBOL " +
     "WHERE ID='Harold';");

   var xmlDoc = Server.CreateObject("Msxml2.DOMDocument");
   xmlDoc.async = false;
   rs.Save (xmlDoc, 1) ;        // Convert rs recordset to XML tree
   xmlDoc.save(Server.MapPath("FromPortfolio.xml"))
                                          
   var xsl = Server.CreateObject("Msxml2.DOMDocument");
   xsl.async = false;              // Convert XML tree using XSL   
   xsl.load(Server.MapPath("PortfolioContent.xsl"))
                                            // Write tree as HTML
   Response.Write(xmlDoc.transformNode(xsl)); 
   conn.Close();
%>

Partial XML produced by rs.Save (xmlDoc, 1);  

<xml>
 <rs:data>
   <z:row SYMBOL="GMC" PRICE="38.1000" STOCKVALUE="762.0000"/>
   <z:row SYMBOL="FORD" PRICE="15.6700" STOCKVALUE="235.0500"/>
 </rs:data>
</xml>

 

Exercise  4.5 - Computing New Fields

  1. Open the Project.mdb file in Access
  2. Click on Create | Query Design
  3. Close the Show Table dialog.
  4. Click in menu: SQL | View | SQL View
  5. Copy and paste the following. Change 'Harold' to an ID in your Portfolio table:
SELECT * FROM STOCK INNER JOIN PORTFOLIO ON STOCK.SYMBOL = PORTFOLIO.SYMBOL WHERE ID='Harold'
  1. Click in menu: Run
  2. Click in menu: View | SQL View
  3. Modify the query to compute the STOCKVALUE field.
  4. Click in menu: Run
     
  5. Modify PortfolioContent.xsl to display STOCKVALUE in the table.

 

Editing the Tree

We've seen that XML can be generated dynamically in ASP from a database and transformed to HTML by XSL. This section examines how to modify the XML, XSL or HTML in a parse tree directly. For example, a user name can be used to personalize a HTML page; the HTML file is parsed into the tree, a node for user name inserted, and the HTML then output to produce the personalized HTML page. 

Editing nodes

In the example below, the <Name> element text of file NameEdit.xsl is assigned new text of 'Ray Wisman' and written to browser.

Points of note:

  1. Assign HTML document parse tree root - var root = htmlDOC.documentElement;
  2. Select the node to access - var node = root.selectSingleNode("body/Name")
  3. Modify the node text - node.text = 'Ray Wisman';
  4. Write the document tree to browser - Response.Write(htmlDOC.xml);
<%@ LANGUAGE = JScript %>
<%
  		// Load the HTML file into parse tree
  var htmlDOC = Server.CreateObject("MSXML2.DOMDocument");
  htmlDOC.async = false;
  htmlDOC.load(Server.MapPath("EditNode.xsl"));
		// root of document
  var root = htmlDOC.documentElement;
                       // Make current node "body/Name"
  var node = root.selectSingleNode("body/Name"); 
                      	// Assign current node text to 'Ray Wisman'
  node.text = 'Ray Wisman';
                    	// Write tree as XML
  Response.Write(htmlDOC.xml);
%>
EditNode.xsl

<html xmlns="http://www.w3.org/1999/xhtml">
  <body>
     Welcome <Name>Anonymous</Name>
     to the personalized Web page.
  </body>
</html>


HTML output

<html xmlns="http://www.w3.org/1999/xhtml">
  <body>
     Welcome <Name>Ray Wisman</Name>
     to the personalized Web page.
  </body>
</html>

 

Creating XML data

We have automatically converted relational database tables into XML trees before transforming using XSL, allowing us to focus on the logic in ASP rather than the user interface. XML trees can also be constructed directly. The following example defines an XML tree in which values are inserted to be displayed by XSL.

Points of note:

  1. var area=height*width; - calculates the area of a rectangle from the height and width,
  2. xmlData.loadXML(
                "<RECTANGLE><AREA/><WIDTH/><HEIGHT/></RECTANGLE>");

    Creates a XML tree with nodes RECTANGLE, AREA, WIDTH, HEIGHT
     
  3. var node = root.selectSingleNode("AREA"); - selects the AREA node in the XML tree.
  4. node.text = area; - stores the area value as text in XML tree for AREA node,
  5. Response.Write(xmlData.transformNode(xslStyle)); - transforms the XML with XSL to HTML

 

 Tree construction 

 xmlData.loadXML("<RECTANGLE>"    +
                    "<AREA/>"     +
                    "<WIDTH/>"    +
                    "<HEIGHT/>"   +
                 "</RECTANGLE>");

 Tree with text nodes added 

    var node = root.selectSingleNode("HEIGHT");
    node.text = 23.5;


CreateXML.asp                                                                Rectangle.xsl
<%@ Language=JScript%>
<%	   
  var height=23.5;
  var width=10.0;
  var area=height*width;
  
  var xmlData = Server.CreateObject("Microsoft.XMLDOM");
  xmlData.async = false;
 xmlData.loadXML("<RECTANGLE>"    +
                    "<AREA/>"     +
                    "<WIDTH/>"    +
                    "<HEIGHT/>"   +   
                 "</RECTANGLE>");
 
  var xslStyle = Server.CreateObject("Microsoft.XMLDOM");
  xslStyle.async = false;
  xslStyle.load(Server.MapPath("Rectangle.xsl"));

  var root = xmlData.documentElement;	      // Root of XML tree

  var node = root.selectSingleNode("AREA");    // AREA node
  node.text = area;			                //<AREA>235</AREA>

  var node = root.selectSingleNode("HEIGHT"); 	
  node.text = height;

  var node = root.selectSingleNode("WIDTH"); 
  node.text = width;

  Response.Write(xmlData.transformNode( xslStyle ));   
%>
<xsl:stylesheet version="2.0" 
   xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
   xmlns="http://www.w3.org/1999/xhtml">
   <xsl:output method="html" />

   <xsl:template match="/">
       Area of Rectangle
       <xsl:value-of select="RECTANGLE/AREA" />=
       <xsl:value-of select="RECTANGLE/HEIGHT" />*
       <xsl:value-of select="RECTANGLE/WIDTH" />
   </xsl:template>
</xsl:stylesheet>

XML data after editing AREA, HEIGHT, WIDTH

<RECTANGLE>
   <AREA>235</AREA>
   <WIDTH>10</WIDTH>
   <HEIGHT>23.5</HEIGHT>
</RECTANGLE>


HTML output

Area of Rectangle 235= 23.5 * 10

 

Exercise  4.75 - Nodes and Elements

  1. Copy and paste CreateXML.ASP and Rectangle.xsl to a virtual drive (e.g. W:\N342).
  2. Test by:
    • iu-uits-ediwp1.ads.iu.edu/username/N342/CreateXML.asp
  3. Define XML with:
    1. Root: PERSON
    2. Elements: NAME and AGE
  4. Set the text of NAME and AGE elements to your name and age similar to:
    • var node = root.selectSingleNode("HEIGHT");
    • node.text = height;
  5. Modify Rectangle.xsl to display AGE and NAME.
    • The XSL style sheet should have:    <xsl:output method="html" />
  6. Test by loading CreateXML.ASP into the browser.
  7. In browser, View | Source, to examine the HTML output from the ASP.

 

Deleting nodes

This approach can be used with user input from HTML forms to tailor an otherwise static HTML page for a specific purpose. In the following example, if a user makes a purchase, the <Nosale> node is deleted; if they do not make a purchase the <Sale> node is deleted. 

The script consists of two parts, one to handle a sale and a no sale.

Nosale:

  1. When the user request is empty
  2. select the node "body/Sale" 
  3. remove it from the tree

Sale:

  1. When user request is not empty, for example, contains 
    "Purchase=surf board"
  2. select the "body/Nosale" node
  3. remove from tree
  4. select the "body/Sale/Purchase" node
  5. add "surf board" text

The tree is then output as HTML.

DeleteNode.asp                                               DeleteNode.xsl
<%@ LANGUAGE = JScript %>
<%
  // Load the HTML
  var htmlDOC = Server.CreateObject("MSXML2.DOMDocument");
  htmlDOC.async = false;
  htmlDOC.load(Server.MapPath("DeleteNode.xsl"));
  var root = htmlDOC.documentElement;

  if(Request("Purchase").count == 0) {      // No Purchase
      var node = root.selectSingleNode("body/Sale"); 
      var parent = node.parentNode; 
      parent.removeChild(node);
  }
  else {
      var node = root.selectSingleNode("body/Nosale"); 
      var parent = node.parentNode; 
      parent.removeChild(node);
      var node = root.selectSingleNode("body/Sale/Purchase"); 
      node.text = Request("Purchase");
  }
  Response.Write(htmlDOC.xml);
%>

DeleteNode.asp?Purchase=surf board

<html xmlns="http://www.w3.org/1999/xhtml">
  <body>
     We <b>appreciate</b> your business.
     <Sale>
          Thanks for your money. 
          Your 
            <Purchase></Purchase> 
           will be in the mail.
      </Sale>
      <Nosale>
           Sorry that we didn't have what you wanted.
      </Nosale>
   </body>
</html>

HTML output

<html xmlns="http://www.w3.org/1999/xhtml">
  <body>
      We <b>appreciate</b> your business.
      <Sale>
          Thanks for your money. 
          Your 
            <Purchase>surf board</Purchase> 
           will be in the mail.
      </Sale>
   </body>
</html>

Points of note:

  1. Remove either the <Sale> or <Nosale> node by locating the parent and removing the child:
  2. Modify the <Purchase> node adding the text of user input - node.text = Request("Purchase");

 

Adding Text Nodes

A text node consists of text but not an element (i.e. <element>). In the following a text node is added whether or not a purchase is made, with appropriate text of the node. The appropriate place to add the node here is as a child of the <body> node. 

The tree is then output as HTML.

AddNode.asp                                         AddNode.xsl
<%@ LANGUAGE = JScript %>
<%
  // Load the HTML
  var htmlDOC = Server.CreateObject("Microsoft.XMLDOM");
  htmlDOC.async = false;
  htmlDOC.load(Server.MapPath("AddNode.xsl"));
  var root = htmlDOC.documentElement;

  var parent = root.selectSingleNode("body"); 
  var textNode;

  if(Request("Purchase").count == 0) {        // No Purchase
    textNode = htmlDOC.createTextNode(
                          "Sorry we didn't have what you wanted.");	 
  }
  else {
    textNode = htmlDOC.createTextNode(
                       "Thanks for purchasing the " 
                      + Request("Purchase"));
  }
  parent.appendChild(textNode);
  Response.Write(htmlDOC.xml);
%>

<html xmlns="http://www.w3.org/1999/xhtml">
  <body>
      We <b>appreciate</b> your business.
  </body>
</html>


HTML output

<html xmlns="http://www.w3.org/1999/xhtml">
 <body>
  We <b>appreciate</b> your business.
  Thanks for purchasing the surf board
 </body>
</html>


AddNode.asp?Purchase=surf board


Points of note:

  1. Locate the parent node <body>.
  2. Create a new text node in the tree:
  3. Add the text node as a child of <body>, by default as the last child.

 

Adding Elements

An element in XML is <element> </element>. An element and a text node is <element> text </element>. For simplicity, we have only diagrammed elements in the parse tree. The previous example added a text node to the tree, this example adds an element and appends a text node to the element. A node is added whether or not a purchase is made, through the text of the node is different. The appropriate place to add the node is as a child of the <body> node. 

The tree is then output as HTML.

AddElement.asp                                                   AddElement.xsl
<%@ LANGUAGE = JScript %>
<%
  var htmlDOC = Server.CreateObject("Microsoft.XMLDOM");
  htmlDOC.async = false;
  htmlDOC.load(Server.MapPath("AddElement.xsl"));
  var root = htmlDOC.documentElement;

  var parent = root.selectSingleNode("body"); 
  var element = htmlDOC.createElement("response");

  var textNode;

  if(Request("Purchase").count == 0) {     // No Purchase
     textNode = htmlDOC.createTextNode(
          "Sorry we didn't have what you wanted.");	 
  }
  else {
      textNode = htmlDOC.createTextNode(
     "Thanks for purchasing the " + Request("Purchase"));
  }
 			            	// AppendChild <response> 
  element.appendChild(textNode);  // to parent <body>
  parent.appendChild(element);

  Response.Write(htmlDOC.xml);
%>
<html   xmlns="http://www.w3.org/1999/xhtml">
  <body>
    We <b>appreciate</b> your business.
  </body>
</html>

HTML output

<html xmlns="http://www.w3.org/1999/xhtml">
 <body>
   We <b>appreciate</b> your business.
   <response xmlns="">
      Thanks for purchasing the boat
   </response>
  </body>
</html>


AddElement.asp?Purchase=boat

 

Points of note:

  1. Create an element named <response>.
  2. Append the text node to the <response> element.
  3. Append the <response> element as a child to the parent.

Exercise  5 - Nodes and Elements

  1. Copy and paste AddElement.ASP and AddElement.xsl to a virtual drive (e.g. W:\N342).
  2. Test with and without user input by:
    • iu-uits-ediwp1.ads.iu.edu/username/N342/AddElement.asp?Purchase=boat
    • iu-uits-ediwp1.ads.iu.edu/username/N342/AddElement.asp
  3. Add element
    1. Modify the ASP script to add an element when the user gives input. 
    2. The element name is the user input.
    3. Append the text node to the element.
  4. Delete the <b> element.
  5. Test by loading AddElement.ASP into the browser.
  6. In browser, View | Source, to examine the HTML output from the ASP.

 

Putting it all together

Editing the XSL/HTML parse tree before applied to transform XML allows us to control at runtime the result of the transform. The following example deletes the element <FIRST> from the XSL parse tree, then applies the XSL tree to the XML to output as HTML.

EditXSL.asp                                                           EditXSL.xsl
<%@ LANGUAGE = JScript %>
<%
  var xmlData = Server.CreateObject("Microsoft.XMLDOM");
  xmlData.async = false;
  xmlData.load(Server.MapPath("Portfolio.xml"));

  var xslDoc = Server.CreateObject("Microsoft.XMLDOM");
  xslDoc.async = false;
  xslDoc.load(Server.MapPath("EditXSL.xsl"));
  var root = xslDoc.documentElement;

  var node = root.selectSingleNode(
          "body/table/xsl:for-each/tr/FIRST"); 
  var parent = node.parentNode; 
  parent.removeChild(node);
  			// Apply transformations
  Response.Write(xmlData.transformNode(xslDoc));
%>

Portfolio.xml

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" 
      href="EditXSL.xsl"?>

 <Portfolio>
    <STOCKID>1
	<ID>Ray</ID><SYMBOL>IBM</SYMBOL>
    </STOCKID>
    <STOCKID>2
	<ID>Ray</ID><SYMBOL>MSFT</SYMBOL>
    </STOCKID>
    <STOCKID>3
	<ID>Harold</ID><SYMBOL>FORD</SYMBOL>
    </STOCKID>
    <STOCKID>4
	<ID>Robin</ID><SYMBOL>UAL</SYMBOL>
    </STOCKID>
    <STOCKID>5
	<ID>Robin</ID><SYMBOL>FORD</SYMBOL>
    </STOCKID>
</Portfolio>  
<html xsl:version="2.0"
         xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
         xmlns="http://www.w3.org/1999/xhtml">
 <body>
  <table border="1">
    <tr>
      <td>ID</td>
      <td>SYMBOL</td>
    </tr>
    <xsl:for-each select="Portfolio/STOCKID"> 
       <tr>
           <FIRST> 
              <td><xsl:value-of select="ID"/></td>
           </FIRST>
           <td><xsl:value-of select="SYMBOL"/></td>
       </tr>
     </xsl:for-each>
   </table>
 </body>
</html>

Resulting XSL

<html xsl:version="2.0"
         xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
         xmlns="http://www.w3.org/1999/xhtml">
 <body>
   <table border="1">
     <tr>
        <td>ID</td>
        <td>SYMBOL</td>
     </tr>
     <xsl:for-each select="Portfolio/STOCKID">
       <tr>
          <td><xsl:value-of select="SYMBOL" /></td>
       </tr>
     </xsl:for-each>
    </table>
  </body>
</html>

Points of note:

  1. The element <FIRST> in EditXSL.xsl file.
  2. Locate the <FIRST> element node:
  3. Apply transform to produce HTML: