Parsing is at the core of any XML application. Behind the scenes of an XML application there is a parser that takes data and puts it in a format that the application can understand.
There are two types of XML parsers: those that validate documents and those that just ensure that the document is well formed. A validating parser ensures that the document conforms to the DTD specified within it -- for SPAN XML files it would be the spanrisk.dtd file. A nonvalidating parser simply checks that the document is well-formed, i.e. begins with an XML declaration ( e.g. <?xml version="1.0"?> ) and contains properly nested and marked-up elements. Validating parsers tend to be much larger than nonvalidating parsers and require more RAM and processing power.
One of the best available free tools to view XML files is Microsoft® XML Notepad that can be downloaded from the web. It is based on a nonvalidating parser. With XML Notepad, developers can quickly create XML prototypes in an iterative mode. It offers an intuitive and simple user interface that graphically represents the tree structure of XML data. This tool can be used to view any XML files, and we definitely would recommend it for quick checking and browsing of SPAN XML files outside the PC-SPAN 4 environment.
For more thorough checking of XML data, a validating parser should be used. XML <PRO> -- an XML editor from Vervet Logic is one of the first tools of this type available on the market. It combines the power of XML with an intuitive user interface that allows users to easily create and edit XML-based documents, regardless of previous experience with XML.
The Microsoft® MSXML Parser is a validating XML parser written in Java. The parser checks for well-formed documents and optionally permits checking of the documents' validity against a DTD. Once parsed, the XML document is exposed as a tree through a simple set of Java methods. There is also a nonvalidating version of this parser written in C++. It is optimized for speed and efficiency and is distributed as an ActiveX control with IE4.
IBM supports an extensive web site devoted to XML. It offers a number of XML development tools including a free validating XML parser written in Java. The package (com.ibm.xml.parser) contains classes and methods for parsing, generating, manipulating, and validating XML documents.
Microsoft IE4 was the first browser to support XML. To accomplish this, IE4 uses the external MSXML parser that can break a document's XML tags into an object tree. Values contained in structured tag sets are exposed as objects that can be manipulated within the browser by JavaScript. The next generation of browsers, however, will natively recognize and parse XML documents.
Microsoft IE 5 Beta features significant updates to the XML-related components offered in IE 4.0. It supports the following key features:
The first version of Netscape browser to support XML will be version 5. Netscape has already committed to displaying native XML documents in Navigator and Communicator 5.0 browsers.
Since the XML data can be represented in the browser's object model, it is possible to write a script to manipulate and display the data. At this time, however, even in IE4, in order to load an XML file, you need to use the MSXML ActiveX control.
The following example shows how, for example, a JavaScript can be used to manipulate a SPAN XML file to generate a Currency Conversion report. This is a simplified version of the actual script that is used in PC-SPAN version 4 to produce an XML-based report. It takes into account a specific XML file structure described in the spanrisk.dtd file.
The script first creates an ActiveX object representing a MSXML parser. Then it loads an XML file, parses it, and passes the root of the XML document to the makeReport function. Having the root element, it is quite easy to get any XML element in question and its value and then to dynamically generate a report. At the end, the script writes the entire HTML to the document. To run this script, you need to have IE4 installed on your system.
<SCRIPT LANGUAGE="JavaScript">
// Create an ActiveX object representing an XML document
var objXml = new ActiveXObject("MSXML");
// Specify a SPAN XML file to parse
objXml.URL = "http://www.cme.com/span/span4_xml_default.xml";
// Get the root object
var root = objXml.root;
// Make the report
var content;
if ( root != null)
content = makeReport(root)
else
content = "<P>Can't get the root element</P>";
// Write the entire HTML to the document
document.write(content);
function makeReport(elem)
// Given the root element, returns a specific report
{
// get <pointInTime> and <clearingOrg> objects
elem = getElement(elem, "pointInTime");
if (elem == null) return "<P class=error>Can't find <pointInTime>";
date = getElementValue(elem, "date");
isSetl = getElementValue(elem, "isSetl");
setlQualifier = getElementValue(elem, "setlQualifier");
run = getElementValue(elem, "run");
elem = getElement(elem, "clearingOrg");
if (elem == null) return "<P class=error>Can't find <clearingOrg>";
ec = getElementValue(elem, "ec");
// get a collection of <curConv> elements
elem = getElement(elem, "curConv");
if (elem == null) return "<P class=error>Can't find <curConv>";
// for each <curConv> element
var content = "";
for (var i = 0; i < getSize(elem); i++) {
var obj = getElemFromCol(elem,i);
content += "<TR><TD>"
+ getElementValue( obj, "fromCur" )
+ "</TD><TD>"
+ getElementValue( obj, "toCur" )
+ "</TD><TD>"
+ getElementValue( obj, "factor" )
+ "</TD></TR>";
;
}
var headings =
"<TR><TH>From Currency</TH><TH>To Currency</TH><TH>Conversion Rate</TH></TR>";
return ( "<TABLE>" + headings + content + "</TABLE>" );
}
function getElement(obj, tagName) {
// Returns a requested element from a container
if (obj == null || tagName == null)
return null;
tagName = tagName.toUpperCase();
var children = obj.children; // get all children
if (children != null) {
// check if a requested element is among children
for (var i = 0; i < children.length; i++) {
if (children.item(i).tagName == tagName)
return obj.children.item(tagName);
}
return null;
} else
return null;
}
function getElementValue(elem, tagName) {
// Returns an element's attribute value
elem = getElement(elem, tagName);
if (elem != null)
return elem.text;
else
return "n/a";
}
function getSize(elem) {
// Returns a collection size
if (elem == null) return null;
else if (elem.length > 1) return elem.length;
else return 1;
}
function getElemFromCol(elem, i) {
// Returns an element from a collection at index 'i'
if (getSize(elem) > 1) return elem.item(i);
else return elem;
}
</SCRIPT>
All major database venders are working on tools to facilitate import/export data to/from databases that will become available in the forthcoming upgrades. At the mean time, however, we can address an issue of importing data from an XML file into a MS Access database in a similar manner to what we did in the JavaScript example.
The following example demonstrates how to import data from an XML file to an Access database. In this particular case, we will extract Currency Conversion data from a sample Span XML file and populate a Currency Conversion Rates table. To run this example, you will need to download the file span4_xml_access.zip (that contains an Access .mdb file and a sample XML file) to your local drive, unzip it, and then open an .mdb file. The 'Action...' menu on the first screen gives you a choice of parsing an XML file and populating a Currency Conversion Rates table. In any case, you will need first to chose an XML file to parse -- specify the sample XML file that comes with this example. Other menu choices allow to view prebuild forms and reports.
The following excerpt of a VBA code from this example explains the details of exporting data from an XML format to an Access database. The first step is to create an ActiveX object representing a MSXML parser. Then we need to parse an XML file of interest and get the root of the XML document. Having the root element, it is quite easy to get any XML element in question and its value and then to dynamically populate the database. To run this example, you need to have a MSXML parser (that comes with IE4) installed on your system. The VBA code is very similar to the code in the JavaScript example, and it can be easily elaborated to populate a database of any complexity.
Option Compare Database
Option Explicit
Public root As Object 'XML file root object
Public FileName As String 'XML file to parse
Function parseXmlFile() As Object
'Create an ActiveX object representing an XML document
Dim xml As Object
Set xml = CreateObject("msxml")
'Specify the SPAN XML file to parse
DoCmd.OpenForm ("CommonDialog")
DoCmd.Close acForm, "CommonDialog"
xml.URL = FileName
'Get the root object
Set root = xml.root
If Not root Is Nothing Then
MsgBox "Successfully parsed XML file " + FileName
Else
MsgBox "Failed to parse XML file " + FileName
End If
'Set a return value
Set parseXmlFile = root
End Function
Function updateCurConvTable()
'Check if an XML file has already been parsed
If root Is Nothing Then
Set root = parseXmlFile()
End If
Dim elem As Object
'Get "pointInTime" and "clearingOrg" objects
Set elem = root.Children.Item("pointInTime")
Dim busDate As String
busDate = elem.Children.Item("date").Text
Set elem = elem.Children.Item("clearingOrg")
Dim ec As String
ec = elem.Children.Item("ec").Text
'Get a collection of "curConv" elements
Set elem = elem.Children.Item("curConv")
Dim length As Integer
length = elem.length - 1
Dim obj As Object
Dim fromCur As String
Dim toCur As String
Dim convRate As String
Dim db As Database
Set db = CurrentDb()
'Delete data from database
DoCmd.SetWarnings False
Dim strsql As String
strsql = "Delete * From curConv;"
DoCmd.RunSQL strsql
DoCmd.SetWarnings True
Dim rs As Recordset
Set rs = db.OpenRecordset("curConv", dbOpenDynaset)
Dim retVal
Dim i As Integer
'For each "curconv" element add a new record to the table
For i = 0 To length
Set obj = elem.Item(i)
fromCur = obj.Children.Item("fromCur").Text
toCur = obj.Children.Item("toCur").Text
convRate = obj.Children.Item("factor").Text
retVal = utilFunc.addNewRecord(rs, busDate, ec, fromCur, toCur, convRate)
Next i
rs.Close
Set db = Nothing
DoCmd.OpenForm ("Currency Conversion Rates")
End Function
Function addNewRecord(rs As Recordset, _
busDate As String, _
ec As String, _
fromCur As String, _
toCur As String, _
convRate As String)
rs.AddNew ' Add new record.
rs!busDate = busDate ' Add data.
rs!clearingOrg = ec
rs!fromCurrency = fromCur
rs!toCurrency = toCur
rs!convRate = convRate
rs.Update ' Save changes.
End Function