Charles Heinemann
Program Manager, XML
Microsoft Corporation
Updated April 22, 1999
Download the source code for this article (zipped, 1.65K)
The following article was originally published in the Site Builder Network Magazine "Extreme XML" column (now MSDN Online Voices Extreme XML).
In the wake of the Marmite incident last month, I've been doing what I could to get back into the good graces of my boss, the Englishman. It should come as no surprise, then, that I've developed a newfound interest in English crossword puzzles. I must say, however, that they're not as easy as I assumed they would be. In fact, the following clue had me stumped:
ACROSS
1. Dog's body alien to World Wide Web (8)
I was wrestling with this clue when the latest addition to our group, the intern, entered the office.
"Sir," the intern asked, "what's the exchange rate for the Canadian dollar?"
The intern, an Ottowan, had been commissioned to write an application with Microsoft Visual Basic®, using the new XML parser we shipped with Internet Explorer 5. One goal of the project was to calculate currency-exchange values; the other, to demo new features of the parser -- in this case, the addition of data type support.
For the demo, the intern was creating his own XML file, consisting of currency exchange information. Hence his interest in the Canadian dollar.
There are two ways of typing XML nodes: through an XML Schema and on the instance. To type the value of an XML node through an XML Schema, the datatypes (dt) namespace must be declared within the schema and the type defined on the ElementType or AttributeType declaration. For our purposes here, we will only be typing element values.
In the schema below, a rate element is declared and assigned the data type "fixed.14.4" or the currency data type:
<Schema xmlns="urn:schemas-microsoft-com:xml-data" xmlns:dt="urn:schemas-microsoft-com:datatypes"> <ElementType name="rate" content="textOnly" dt:type="fixed.14.4"/> <ElementType name="country" content="textOnly"/> <ElementType name="symbol" content="textOnly"/> <ElementType name="currency" content="eltOnly" model="closed"> <element type="symbol"/> <element type="country"/> <element type="rate"/> </ElementType> <ElementType name="currencies" content="eltOnly" model="closed"> <element type="currency" maxOccurs="*"/> </ElementType> </Schema>
This schema can now be used to type the rate elements in the following XML document:
<currencies xmlns="x-schema:currencySchema.xml"> <currency> <symbol>AWG A0-FX</symbol> <country>Aruba Guilder</country> <rate>1.79</rate> </currency> <currency> <symbol>CRC A0-FX</symbol> <country>Costa Rica Colones</country> <rate>228.93</rate> </currency> <currency> <symbol>HTG A0-FX</symbol> <country>Haiti Gourde</country> <rate>16.26</rate> </currency> <currency> <symbol>PAB A0-FX</symbol> <country>Panama Balboa</country> <rate>1</rate> </currency> </currencies>
The other method of typing element values is to declare the datatypes namespace on the XML document directly and use the "dt" prefix and the "dt" attribute on the instance of the element:
<currencies xmlns:dt="urn:schemas-microsoft-com:datatypes"> <currency> <symbol>AWG A0-FX</symbol> <country>Aruba Guilder</country> <rate dt:dt="fixed.14.4">1.79</rate> </currency> <currency> <symbol>CRC A0-FX</symbol> <country>Costa Rica Colones</country> <rate dt:dt="fixed.14.4">228.93</rate> </currency> <currency> <symbol>HTG A0-FX</symbol> <country>Haiti Gourde</country> <rate dt:dt="fixed.14.4">16.26</rate> </currency> <currency> <symbol>PAB A0-FX</symbol> <country>Panama Balboa</country> <rate dt:dt="fixed.14.4">1</rate> </currency> </currencies>
The intern's Visual Basic app loads this document and accesses the string values and typed values within it. Using the typed value of the "rate" element and input from a text box, he converts a user-specified amount of foreign currency to United States dollars. For instance, in the following code the Aruban guilder is converted to American dollars:
Private Sub Convert1_Click() Dim xml As DOMDocument Dim docRoot As IDOMNode Dim ArubanRate As IXMLDOMNode Dim rate As Currency Dim forDollars As Currency Dim amDollars As Currency forDollars = CCur(amount.Text) 'Input from a text box Set xml = New DOMDocument xml.Load "currencies.xml" Set docRoot = xml.documentElement Set ArubanRate = docRoot.childNodes.Item(0).childNodes.item(2) rate = ArubanRate.nodeTypedValue amDollars = forDollars / rate End Sub
Using the XML Object Model for Internet Explorer 5, the intern calls the nodeTypedValue property on IXMLDOMNode to get the typed (as opposed to string) value of the "rate" element. Returning a value of type currency to the rate variable, he then divides forDollars (the amount of foreign dollars) by the rate to arrive at amDollars (the amount of United States dollars after conversion).
Although I was reluctant to admit it to the Canadian, this was all pretty interesting. A cousin of mine had recently crossed the border, and was still struggling with currency issues. (He nearly laid out a hot-dog vendor when he mistakenly thought that the man had called him a "loony.")
"Hey," I asked the intern, "can you do this in script so I can throw it in a Web page? I've got a guy who might be interested in accessing a program like this via the Internet."
"Sure can," said the intern, and with that he quickly constructed a Web page. Using HTML, he created a text box that allowed the user to enter the amount of foreign currency she possessed. Using Visual Basic Scripting Edition (VBScript), he dynamically populated a select box, took in the type and amount of foreign currency, and did the conversion:
<BODY> <XML ID=xmlDoc></XML> <SCRIPT LANGUAGE=VBScript> <!-- Sub window_onload() xmlDoc.async=false xmlDoc.load("currencies.xml") Set countries = xmlDoc.documentElement.childNodes firstRate = countries.item(0).childNodes.item(2).nodeTypedValue firstName = countries.item(0).childNodes.item(1).text str = "<SELECT NAME=currencies SIZE=4><OPTION SELECTED VALUE=" & firstRate & ">" & firstName & "</OPTION>" children = xmlDoc.documentElement.childNodes.length For i=1 To children - 1 curRate = countries.item(i).childNodes.item(2).nodeTypedValue curName = countries.item(i).childNodes.item(1).text str = str & "<OPTION VALUE=" & curRate & ">" & curName & "</OPTION>" Next str = str & "</SELECT>" document.all.selectBox.innerHTML = str End Sub --> </SCRIPT> <H1>Currency Calculator</H1> <P>Select a currency:</P> <DIV ID="selectBox"></DIV> <BR> <P>Enter the amount of foreign currency you want to exchange:</P> <INPUT TYPE=TEXT NAME=forAmount> <INPUT TYPE=BUTTON VALUE="CONVERT" onclick="convert()"> <SCRIPT LANGUAGE=VBScript> <!-- Sub convert() rate = currencies.value conAmount = CLng((forAmount.value / rate) * 100) / 100 Msgbox("Amount in American Dollars: $" & conAmount) End Sub --> </SCRIPT> </BODY>
Seeing what the intern had done, I quickly drafted an e-mail to my cousin, telling him his problems would soon be solved. It suddenly occurred to me, however, that in order for the app to be useful, we'd need to have our XML source reflect daily updates of the exchange rates.
I knew some guy, somewhere, mentioned this in an article -- but for the life of me, I could not remember who or where. Well, I thought, maybe there's a business opportunity here. Maybe I could support "currencies.xml," providing it with regular updates, and sell my North-going kin subscriptions to it. I know one who might pay dearly.
"And the exchange rate for the Canadian dollar?" asked the intern once more.
"Oh yeah." I thought for a second. "Let me see if I can get hold of my cousin."
Apparently too impatient to sit through a phone call, the intern said that it was okay -- that he'd check with others around the office.
"Oh, by the way," the intern muttered on his way out of the office, "one across is 'Internet.'"
Charles Heinemann is a program manager for Microsoft's Weblications team. Coming from Texas, he knows how to think big.
Charles answers:
No. However, it is possible with the parser shipped with Internet Explorer 5. From the IXMLDOMDocument object, you can call the loadXML(wstring) method.