Delivering Information With XML

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.

[ Figure A ]

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: