by Paul Parry
In today's environment of complex enterprises involving data stored in many locations, a challenge sits before the Web developer community: how to deliver information from various data sources without bothering the user with the details of where each is stored. A number of technologies are available that can supply this information efficiently, but XML is emerging as the standard structure for delivering this kind of heterogeneous data--and with minimal overhead. In this article, we'll build on our recipe application. We'll combine the recipe data, stored in our local SQL Server, with the catalog of our food service providers, stored in our corporate purchasing system, to calculate the cost of making a meal for a large number of people. What is XML? XML stands for eXtensible Markup Language. As the next generation language, it's a re-merger of two standards that have diverged over the last few years:
The aim of XML is a classic application of the 80/20 rule: provide 80 percent of the power and functionality of SGML, with only 20 percent of its complexity. The code in Listing A provides an example of XML structure
Listing A: A typical XML structure.
:
<?XML version="1.0"?>
<ISSUE>
<TITLE>Active Server Developer's
èJournal</TITLE>
<VOLUME>2</VOLUME>
<NUMBER>5</NUMBER>
<MONTH>May 1998</MONTH>
<ARTICLE>
<TITLE>Transactional Active Server
èPages</TITLE>
<AUTHOR>Susie Adams</AUTHOR>
<P>Two-tier windows applications...</P>
<H1>Why MTS2.0/IIS4.0/ASP?</H1>
<P>The Microsoft Transaction Server...</P>
...
</ARTICLE>
<ARTICLE>
<TITLE>Using XML to deliver data from
èmultiple sources</TITLE>
<AUTHOR>Paul Parry</AUTHOR>
<P>Today's environment...</P>
<H1>What is XML?</H1>
<P>XML ...</P>
...
</ARTICLE>
</ISSUE>
Although XML is being positioned as the next generation Web-delivery standard, the language still has a long way to go before it's in common use. HTML and DHTML maintain the seats of honor at the W3C table, but XML is useful today for several applications, including delivering heterogeneous data sets across the Internet.
Using ASPs to combine data In our sample catering enterprise, our recipes are stored in a SQL server, and the catalogs of our vendors are stored in our company's purchasing system. Our Web-based application lets individual franchisees plan menus and budget meal costs via the Web. To cut down on network round-trips, we'll deliver all of the data for a meal using XML, then use a combination of Java Applets and Jscript on the Internet Explorer 4 browser to let the user manipulate the data. To those who have some experience building HTML pages with ASP, creating an XML page presents no new challenge. In this example, we assume the user has posted a request for a certain set of recipes comprising a meal. We open ADO recordsets from each source and build the XML for the requested servings, as you can see in Listing B.
Listing B: Building the XML for the Thanksgiving meal
<%@ LANGUAGE = VBScript %>
<?XML VERSION="1.0"?>
<MEAL>
<MEALNAME><%=Request.Form("MealName")%>
è</MEALNAME>
<% sMealCost = 0
Set RecipeConn =
èServer.CreateObject("ADODB.Connection")
Set CatConn =
èServer.CreateObject("ADODB.Connection")
RecipeConn.Open
è "Recipes","Franchise134","PW"
CatConn.Open
è"FSCatalog","Franchise134","PW"
szSQL = "SELECT * FROM Recipe Where
èRecipe_ID in
è("&Request.Form("mslRecipes")&")"
Set RecipeRS = RecipeConn.Execute(szSQL)
Do While Not RecipeRS.EOF
%> <RECIPE>
<% sRecCost = 0
`Calculate how much we have to
`multiply each ingredient by
sYieldFactor =
è Request.Form("txtServings")/
è RecipeRS("Yield") %>
<RECNAME><%=RecipeRS("Name")
è %></RECNAME>
<SOURCE><%=RecipeRS("Source") %></SOURCE>
<YIELD><%=RecipeRS("Yield") %></YIELD>
<INGREDIENTS>
<% szSQL = "select * from Rec_Ingred
è where Recipe_ID = " &
è RecipeRS("Recipe_ID")
Set IngredRS = RecipeConn.Execute(szSQL)
Do While Not IngredRS.EOF
%> <INGREDIENT>
<QUANTITY><%=IngredRS("QUANTITY")
è *sYieldFactor %></>
<UNIT><%=IngredRS("UNIT")%></>
<NAME><%=IngredRS("NAME")%></>
<PROVIDERS>
<% sIngCost = MAX_SINGLE
szSQL = "select * from Catalog where
è Item_ID = " & IngredRS("Item_ID")
Set PvdrRS = CatConn.Execute(szSQL)
Do While Not PvdrRS.EOF
sTotCost = PvdrRS("COSTPER")*
è IngredRS("QUANTITY")*sYieldFactor
`Find the lowest cost item
If sTotCost < sIngCost Then sInqCost
è = sTotCost
%> <PROVIDER>
<PROVNAME><%= PvdrRS("PROVNAME")
è %></>
<COSTPER><%= PvdrRS("COSTPER")%></>
<TOTALCOST><% =sTotCost %></>
</PROVIDER>
<% PvdrRS.MoveNext
Loop
%> </PROVIDERS>
</INGREDIENT>
<% sRecCost = sRecCost + sIngCost
IngredRS.MoveNext
Loop
%> </INGREDIENTS>
<STEPS>
<% szSQL = "select * from Rec_Step where
è Recipe_ID = " & RecipeRS("Recipe_ID")
Set StepRS = RecipeConn.Execute(szSQL)
Do While Not StepRS.EOF
%> <STEP>
<NUMBER><%=StepRS("NUMBER")%></>
<TEXT><%=StepRS("TEXT")%></>
</STEP>
<% IngredRS.MoveNext
Loop
%> </STEPS>
<RECIPECOST><%=sRecCost%></RECIPECOST>
<% sMealCost = sMealCost + sRecCost %>
</RECIPE>
<% RecipeRS.MoveNext
Loop
%><MEALCOST><%= sMealCost %></MEALCOST>
</MEAL>
Presenting the data in Internet Explorer 4.0 (IE4) Internet Explorer 4 includes a version of Microsoft's Java XML Parser Applet. Because it's built into the SDK, you can call this applet without a CODEBASE attribute. If you want to see debug information as the applet parses data, set the height and width parameters to show positive numbers, as we've done in the following applet:
<APPLET code="com.ms.xml.dso.XMLDSO.class"
id="xmldso"
width="0"
height="0"
mayscript=TRUE>
<PARAM NAME="URL" VALUE="recipe_xml.asp">
</APPLET>
To
bind the actual data within your HTML, use the DATASRC attribute of the
<TABLE> tag together with the DATAFLD attribute of the <DIV> tag.
The code in Listing C shows a sample set of nested HTML tables that
display our menu cost analysis.
Listing C: Nested HTML tables
<table id=table datasrc=#xmldso border=1
èwidth=100% cellpadding=3>
<tr><td valign=top>Meal: <div
èdatafld=MEALNAME dataformatas=HTML></div>
</td>
</tr>
<tr><td valign=top>
<table border=2 width=100% cellpadding=3
datasrc=#xmldso datafld=RECIPE>
<tr><td valign=top><div datafld=RECNAME
dataformatas=HTML><BR>
From: <div datafld=SOURCE
è dataformatas=HTML><BR>
Lowest Cost: <div
è datafld=RECIPECOST
dataformatas=HTML></td>
<td valign=top>
<table border=2 width=100%
è cellpadding=3
datasrc=#xmldso
è datafld=RECIPE.INGREDIENT>
<tr><td valign=top><div
è datafld=QUANTITY
dataformatas=HTML>
</td>
<td valign=top><div
è datafld=UNIT
dataformatas=HTML>
</td>
<td valign=top><div
è datafld=NAME
dataformatas=HTML>
</td>
<td valign=top>
<table border=2 width=100%
è cellpadding=3
datasrc=#xmldso
datafld=
è RECIPE.INGREDIENT.
è PROVIDER>
<tr><td valign=top><div
è datafld=PROVNAME
dataformatas=HTML>
</td>
<td valign=top><div
è datafld=COSTPER
dataformatas=HTML>
</td>
<td valign=top><div
è datafld=TOTALCOST
dataformatas=HTML>
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
<tr><td valign=top>Lowest Cost of
èIngredients:
<div datafld=MEALCOST
è dataformatas=HTML>
</div>
</td>
</tr>
</table>
You can see the resulting menu plan in
Figure A.
Figure A: The XML data bound in an HTML table provides us with the cost of preparing
Thanksgiving dinner.
Conclusion
This article provides a taste of what XML can do for Web developers. XML actually offers many more features, including Data-Type Definitions (DTDs) and Schemas, that can make this application even more powerful. For further information, check out these URLs: