Export (0) Print
Expand All

Web Services

As of December 2011, this topic has been archived. As a result, it is no longer actively maintained. For more information, see Archived Content. For information, recommendations, and guidance regarding the current version of Internet Explorer, see Internet Explorer Developer Center.

Michael Wallent
Microsoft Corporation

March 6, 2000

Contents

Important Bits
The New Sample
Why Was This Worth It?
Wrapping It Up

Before I get into the topic of Web Services, I have a pledge. I promise not to "diss" or "burble" or write about anything that causes people to send angry mail to Bill Gates. At least not this month.

One of the interesting phenomena that the Web has created is the wholesale ability to create seemingly nonsensical terms, such as "Web Services." (Although my personal favorite is "SheCommerce"). What does "Web Services" mean? Clearly, sites such as Amazon.com provide a service. FedEx provides a package tracking service. In fact, virtually any site on the Web could be thought of as providing a service. Information delivery is a service, just as providing a physical thing (a book or an airline ticket) is a service. Now that I've defined Web Services to be just about anything on the Web, that's probably not going to cut it. Writing about everything may be the inverse of writing for Seinfeld, but it's not a useful place to start this discussion.

Web Services become interesting when two or more services are added together to create something new—for example, comparison shopping sites. These sites aggregate data from multiple sources in a way that adds unique value. That's one example. Another would be the ability to purchase a book online from your favorite merchant and get shipping status on the same page as the order status. This is the new age of the Web Service—where data is king.

For example, in this new world of Web Services, the cool HTML front end you spent all that time on is far less valuable than a common XML schema that allows data collection about your current inventory levels. Now, the sites that add value are the ones that provide the best data aggregation services. The best travel site is the one that not only gets you the roundtrip to Toledo on the cheap, but also fills out your calendar, and collects info on the best restaurants to visit while you are there.

There are some challenges here. Sites may not want to expose their critical business data in the open way necessary to become commodities. They may not want to compete on price and delivery schedule alone. They may still be dealing with the "old" (I hesitate to say this, knowing it's the "current" thinking in many cases) model of customer lock-in. This attempted heel-digging might be the analog of buggy whip vendors trying to deflate the tires on motor cars, or it could be the Beta versus VHS scenario again (with Web Services playing the role of Beta). In any case, the potential reward for customers is huge, and, even given the barriers, Web Services are worth a look.

Important Bits

To have an effective Web Service, you first need to expose your data in a common mechanism. In most cases, the preferred method is XML with a common schema (such as BizTalk). Once you have the data, it needs to be created on request, and then be updatable. When the data is generated, it also needs to be presented visually. Preferably, it would be interesting to aggregate multiple data sets together. Others may discuss using XSL and server-side techniques to create that visualization—but here in the DHTML Dude dominion, I'll discuss how it can be done on the client.

Back in November, I talked about a two-way XML data-binding example. I've made some modifications to that sample to show integration across multiple data sources, and have fleshed out the "Delta Management" model.

The New Sample

Check out this sample.

Note how, initially, you get a table of stock holdings, and then the market values fill in. The portfolio information and the stock information are coming from two different sources.

In a data-bound table, you can bind only one data-source object. However, if you nest tables, each table can have a different data-source reference. In this case, the table looks like this:

<TABLE BORDER="0" ID=CustPortfolio datasrc=#portfolio
       STYLE="width: 95%; border: 1px solid black; ">
  <COL WIDTH=*>
  <COL WIDTH=100>
  <COL WIDTH=100>
  <COL WIDTH=100>
  <THEAD>
    <TR>
      <TD>Stock Name</TD>
      <TD>Symbol</TD>
      <TD>Held</TD>
      <TD>Market Value</TD>
    </TR>
  </THEAD>
  <TBODY>
    <TR>
      <TD>
        <DIV DATAFLD=name></DIV>
      </TD>
      <TD>
        <DIV ID=ActiveSymbol datafld=symbol></DIV>
      </TD>
      <TD>
        <DIV DATAFLD=quantity></DIV>
      </TD>
      <TD>
        <TABLE ID=OuterTable border="0"
                  STYLE="position: relative;">
          <TR STYLE="position: absolute; top: -11; left: 0;">
            <TD><SPAN ID=TheStock></SPAN></TD>
          </TR>
        </TABLE>
      </TD>
    </TR>
  </TBODY>
</TABLE>

The second table—the table with id=OuterTable—is where the second data-source reference will be inserted. Since every OuterTable is going to have a different dataFld property to indicate the associated stock ticker value, the dataFld property for each row must be set as that row is added. Once the CustPortfolio table changes shape, the init() method is called. The init() method iterates through all instances of OuterTable (there would be many, because as the rows are repeated, the OuterTable object gets repeated as well). For each instance of OuterTable, the <SPAN> with id=TheStock is located, and the setupStock() method is called with that element as the parameter.

function init() {
  if (CustPortfolio.readyState == "complete") {
    var t, o, i;
    t = OuterTable;

    for (i=0; i<OuterTable.length; i++) {
      o = OuterTable[i];
      setupStock(o.all.TheStock);
    }
  }
}

function setupStock(e) {
 var y;
 var stock;

 try {
   stock = e.parentElement.parentElement.parentElement.

parentElement.parentElement.parentElement.all.ActiveSymbol;

   if (stock) {
     if (e.set != "true") {
       if (stock.innerText != "" ) {
         e.dataFld = stock.innerText;
         e.parentElement.parentElement.parentElement.
           parentElement.dataSrc = "#stockvalues";
         e.set = "true";
       }
     }
   }
 }
 catch(x) {
 }
}

In the setupStock() method, the symbol for the current row is determined (that's the long walk through the parentElement chain, where the "stock" member is set). Once the stock symbol for the row is determined, the dataSrc and dataFld of the OuterTable of the current row is set. This enables the binding for the value of the stock.

Why Was This Worth It?

You might ask: "Why not simply look up the value in the XML data set and manually set it? This seems like a huge hassle just to set up data binding."

It is somewhat convoluted—but we're in a great situation here. We now can take advantage of value changes in the XML to update our portfolio automatically. As a stock value changes, the new value will be shown. As new portfolio information comes in, it also will update automatically.

You might have noticed the two buttons on the bottom of the page: Stocks Value Change and Portfolio Change. Click the Portfolio Change button. Note that two additional rows were inserted, and the "Held" column on "Aardvark Industries" changed.

Let's take a look at how this happened.

function updatePortfolio() {
  portfoliodelta.ondatasetcomplete = doPortfolioUpdate;
  portfoliodelta.load("portfolio4d.xml");
}

function doPortfolioUpdate() {
  var xmld, xmld2;

    xmld = portfoliodelta.XMLDocument.documentElement;
    xmld2 = portfolio.XMLDocument.documentElement;

    doUpdate(xmld, xmld2);
}

function doUpdate(xmld, xmld2) {
  var fc, nfc, i, j;

  for (i=0; i<xmld.childNodes.length; i++) {
    fc = xmld.childNodes[i];
    updateNode = findMatchingNode(xmld2, fc);

    if (!updateNode) {
      nfc = fc.cloneNode(true);
      xmld2.insertBefore(nfc, null);
    } else {
      for (j=0; j<fc.attributes.length; j++) {
        updateNode.attributes[j].nodeValue =
fc.attributes[j].nodeValue;
    }
   }
  }
}

function findMatchingNode(xmld2, node) {
  var i, fc;
  for (i=0; i<xmld2.childNodes.length; i++) {
    fc = xmld2.childNodes[i];

    if ((fc.attributes[0].nodeName == node.attributes[0].nodeName) &&
       (fc.attributes[0].nodeValue == node.attributes[0].nodeValue))
      return fc;
  }
  return null;
}

In the head of the document, there are four data islands. Two contain the initial data sets for the portfolio and stock data, and two are "delta" data islands. The delta data islands are used to load the delta data sets. These data sets are then compared and merged into the primary data set to which the tables are bound. As node values change, or as nodes are added or removed, the bound view automatically updates. This automatic update is the feature that was worth going through all the trouble to bind the stock values.

When the Update Portfolio button is clicked, a delta XML file is loaded. Once the data is loaded, the doUpdate() method walks through the tree, looking for changes and applying them back into the primary data tree.

Now, check out how the Stocks Value Change button works. You can experiment with different changes by modifying the delta XML files. Note how the delta file can be very small—as opposed to reloading an entire data set or an entire page. Ah, the benefit of the rich client.

Wrapping It Up

You can play both sides of the Web Services game. Work to expose your data as XML common schemas, and then also think of cool ways to aggregate that data together to create interesting scenarios for your users. It's kind of scary to think of data as that kind of commodity, but it's clearly a huge win for your customers. In the end, that's what we get paid for.

 

DHTML Dude

Michael Wallent is Microsoft's product unit manager for Internet Explorer.


  
Show:
© 2014 Microsoft