Chapter 10
Server-Side XML Through VB ASP Components
In this chapter:
XML Basics
Formatting XML
Working with XML in ASP Applications
XML and ADO: Saving Recordsets as XML
There are few technologies that have excited developers as much as XML--Extensible Markup Language. I've heard people talk about XML as a replacement for everything from HTML to SQL. If you view available jobs on the Internet, you'll find few having anything to do with web applications that don't also mention the use of XML in some capacity.
ASP application developers are not immune to the lure of XML, yet there is confusion about how XML can be used with a server-side technology such as ASP, especially when writing ASP components.
This chapter provides an overview of XML, as well as XML formatting techniques, because it's necessary to have an understanding of XML before working on the examples in the second part of the chapter. These examples and their related discussions cover working with XML in ASP components written in Visual Basic. Some of the examples we'll look at include accessing and creating XML through the Microsoft XML parser (MSXML), working with XML through ADO, and mixing ASP processing with XML content.
TIP: XML is a recommended specification from the World Wide Web Consortium, otherwise known as the W3C. You can access the specification at the W3C web site at http://www.w3.org/.
XML is a simple-to-use basic markup language that is a subset of the more complex SGML--or Standard Generalized Markup Language. The specification was created primarily due to insufficiencies of the HTML standard and particularly the difficulties inherent in introducing a new element into the HTML standard.
For instance, mathematicians have a unique professional grammar and syntax that they use to describe their work, but there are no tags within the HTML specification that could be used for this effort. However, to expand HTML just for mathematicians--or musicians, physicists, and so on--isn't efficient.
This problem became very apparent when Netscape began to introduce elements into its rendering of HTML--elements such as FONT
for defining font characteristics. By introducing new elements outside of the HTML specification, pages that were created to work with Netscape Navigator didn't work well with Internet Explorer or other browsers.
Another limitation of HTML is that there is an assumed presentation and layout associated with the elements in an HTML document, but not all rendering engines (browsers) provide identical element presentations. The HTML standard just doesn't provide a means of defining every aspect of how an element is shown on the page. A problem associated with combining presentation as well as content within the same specification is that the specification can either become overly large and complex, or pages created using the specification don't always look the same across different browsers, different operating systems, or both.
XML was created as a solution to both of these HTML limitations.
First, XML is a way of creating a document that can contain an arbitrary set of elements--defined with unique element tags--but still be accessible to document parsers that weren't created specifically to work with the page's elements. The reason that parsers can process the page is that the page and the elements follow a specific set of rules.
Secondly, there is no presentation or layout associated with XML elements. This is provided, instead, by separate standards, specifically by Cascading Style Sheets (CSS) or Extensible Stylesheet language (XSL). Separating presentation from content enables anyone to create their own set of XML elements, provide their own presentation with CSS or XSL, and have the page appear the same regardless of what browser parsed the page.
TIP: This chapter barely touches on the subjects of the XML, CSS, and XSLT specifications--just enough to introduce the examples. For more detailed information, check the XML SDK that's available at the Microsoft web site at http://msdn.microsoft.com/xml/.
A Well-Formed XML Document
One reason XML has become so popular is that it's relatively easy to understand the rules governing this markup language. By following the rules, a web developer creates a "well-formed" document that can be parsed by any XML parser, including those built into browsers such as IE, Mozilla, and Navigator 6.0. When the rules aren't followed, the parser can't process the document, and an error results--the parser does not attempt to recover from the error.
TIP: Another problem with HTML parsers is that they can be very forgiving at times, and web page developers have developed some bad habits as a consequence. A case in point is people using opening tags such as the paragraph (<P>
) or list (<LI>
) tag in their document but without providing a closing tag for the content.
The first line of an XML document can contain the XML declaration, though this isn't required:
<? xml version='1.0' ?>
This line consists of the XML document tag, in addition to the version of XML used in the document. At this time, there is only one version of XML, but you should use the 1.0 version number to differentiate the XML used in the document from future versions of XML.
The XML declaration can also include the character encoding used in the document, such as UTF-8 or EUC-JP. Not all XML processors can process all encodings, and an error results if you use an encoding the processor doesn't recognize.
All XML elements must either be empty tags or have both beginning and closing tags. For instance, if your XML document has an element such as the following, with attributes but no content, then the element must be defined as an empty tag and have a forward slash at the end of the element:
<template attribute="process" />
If your element defines content, then you'll need to use both a beginning and an ending element tag:
<city>Boston</city>
Not providing either the forward slash for an empty tag or the closing tag results in an XML processor error.
Another XML rule is that any Document Type Definition (DTD) files or rules must be specified before any other element in the document. DTDs provide grammar or additional application-specific rules that can be applied to the XML document. Though not required, providing a DTD file makes the XML document valid as well as well-formed:
<!DOCTYPE template SYSTEM "template.dtd">
An additional rule for the XML document is that the elements contained in it must not overlap. This means that you can nest elements, but a nested element must be closed with the appropriate closing tag (or be an empty tag) before the closing tag of the outer element is reached:
<template>
<inner>
</inner>
</template>
Overlapping elements result in an XML processor error.
XML is case-sensitive, so the case used for the opening tag of an element must match the case used for the closing tag. Otherwise, again, an XML processor error results.
Additionally, there are certain characters that should not be used within attribute values or content, characters such as angle brackets (< and >) or the ampersand (&). These characters have special meaning in XML, just as they do in HTML documents.
Other rules are that element attributes must not repeat within a tag, and they must not reference external entities.
A Valid XML Document
Earlier I mentioned that an XML document with an associated DTD file is considered a valid document. The reason for this is that the DTD file provides the grammar and rules to validate the XML used in the document.
For instance, if an element can contain data, a rule could be added to the DTD file for the XML document, similar to the following:
<! ELEMENT template (#PCDATA)>
As efficient as DTD files are, a problem with them is that the syntax used to define the document grammar differs from the syntax for the XML documents, forcing a person to become familiar with two syntaxes. Efforts are underway to define XML schemas to provide for XML entity and attribute descriptions. XML schemas, unlike DTD files, use XML to describe the XML data.
XML Namespaces
XML is first and foremost extensible. This means that more than one set of XML elements for more than one purpose could be included within the same XML document. However, if the same element name is used with two differing components, you have element collision. To prevent something like this from happening, the W3C provided the XML Namespaces specification in 1999.
Namespaces are identified with URIs and are then used as an alias for elements and element attributes within that namespace. With this approach, a document can contain elements from several difference namespaces, and though the names of the elements are the same, the namespaces prevent collision.
For instance, a namespace could be defined with the following:
xmlns:mine='http://www.somecompany.com/namespc'
And used as is shown in the following:
<mine:book>
...
</mine:book>
No document needs exist at the namespace URI--the URI itself is the key to defining the namespace.
XML by itself has no presentation or formatting information associated with it. It's used to define elements and their relationships with each other (as in container and contained). Other W3C-recommended specifications are then used to provide formatting, layout, and presentation information about the XML document elements.
Using CSS to Format Content
CSS can be used to provide both layout and presentation information to an XML processor to define how an XML document is presented. CSS has been used with HTML documents to provide additional formatting information. However, unlike using CSS with HTML, there is no built-in display information for any XML element--you have to provide all display characteristics.
To add CSS to an XML document, add the stylesheet using the following syntax:
<?xml-stylesheet type="text/css" href="asp1001.css" ?>
To demonstrate using XML with CSS, create a new XML document, name it asp1001.xml, and add the contents of Example 10-1 to it. The document contains the XML declaration and a statement to include a CSS file. An outer element with a default namespace is defined to hold the document's contents.
Example 10-1: XML Document
<?xml version='1.0'?>
<?xml-stylesheet type="text/css" href="asp1001.css" ?>
<doc xmlns='http://www.yasd.com/doc' >
<p>
Example of "paragraph", as formatted with CSS.
</p>
<UL>
<LI>one</LI>
<LI>two</LI>
</UL>
<table>
<tr>
<td>first cell</td>
<td>second cell</td>
</tr>
</table>
</doc>
The elements in this example resemble those found in HTML, such as <p>
for paragraph and <table>
for table. However, unlike HTML, there is no built-in formatting for these elements; you have to provide it all in the CSS file.
Create the CSS file next, and name it asp1001.css; Example 10-2 has the complete contents for the CSS file. The file provides CSS style definitions for all of the elements, including providing a display
attribute setting for each. The display
attribute is used to define whether the element is displayed inline or in block format or is displayed as a list item, table element, or other. Several other style settings are set to provide borders, margins, and padding.
Example 10-2: CSS File Providing Formatting/Layout Info for an XML Document
p {
display: block;
border-style: groove;
border-width: 2px;
border-color: red;
width: 90%;
margin-left: 20px;
margin-top: 10px;
padding: 10px;
}
UL {
display: block;
margin-left: 30px;
margin-top: 30px;
}
LI {
display: list-item;
list-style-type: circle
}
table {
display: table;
border-width: 1px;
border-style: solid;
border-color: #CCCCCC;
margin: 50px
}
tr {
display: table-row;
}
td {
display: table-cell;
padding: 5px;
border-style: solid;
border-width: 1px;
border-color: #CCCCCC;
}
You can open the XML document directly into a browser. However, if you use Internet Explorer 5.x to open the file, you'll find that most of the CSS settings have no impact on the elements. The reason is that Microsoft has not implemented much of the CSS functionality for XML contents at this time (the company focuses more on XSL, discussed in the next section).
However, if you open the document with something that has broader CSS support for XML, like Mozilla or Navigator 6.0, you'll find that the CSS style settings do work with the elements, as shown in Figure 10-1.
TIP: By the time you read this book, Microsoft may have improved the support of CSS in XML documents in Internet Explorer, and the Mozilla browser may have a different look than that shown in Figure 10-1. Such is life in the web fast lane.
Figure 10-1.CSS-formatted XML, displayed in the Mozilla browser
Using XSLT to Transform XML
A second technique to format XML documents is XSL--Extensible Stylesheet Language. XSL consists of several specifications; we'll take a look at one of them, Extensible Stylesheet Language Transformations (XSLT).
Unlike using CSS with XML, XSLT is a template-based specification. You create an XML document, which is used to provide the data, and then you create the XSLT document that provides the template to process the data. The template uses HTML elements to provide data layout information, but the format of the XSLT document is XML.
The XSLT document begins with the XML declaration line, followed by the namespace definition for XSLT:
<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">
To begin processing the contents, a root element is defined for the entire document. This root element references content with a forward slash:
<xsl:template match="/">
There are specific elements with associated behaviors defined in XSLT. To process every occurrence of an element in the XML document, you can use the for-each
element:
<xsl:for-each select="element">
The for-each
element processes every occurrence of the target element in the page. To access the value of an element, you can use the value-of
element:
<xsl:value-of select="element">
The value-of
element differs from the for-each
element in that the former returns only the first occurrence of an element within a given content.
Other XSLT elements can be used to provide decision support as well as processing instructions.
To add an XSLT template to an XML document, use the following line, adjusted for the name of your own XSLT file:
<?xml-stylesheet type="text/xsl" href="asp1002.xsl"?>
To demonstrate how XML and XSLT work together, create a new XML document, and name this one asp1002.xml. In the document, add the XML shown in Example 10-3. Note that the contents are very similar to those shown in Example 10-1, except that <span>
tags surround the contents of the list and table cell elements, and the CSS stylesheet reference has been replaced by one for the XSLT document.
Example 10-3: An XML Document That Uses an XSLT Document for Presentation
<?xml version='1.0'?>
<?xml-stylesheet type="text/xsl" href="asp1002.xsl"?>
<doc xmlns='http://www.yasd.com/doc' >
<P>
Example of "paragraph", as formatted with XSL.
</P>
<UL>
<LI><span>one</span></LI>
<LI><span>two</span></LI>
</UL>
<table>
<tr>
<td><span>first cell</span></td>
<td><span>second cell</span></td>
</tr>
</table>
</doc>
Create a second document and name it asp1002.xsl. This document contains the XSLT to process the page contents, providing a visual display similar to that shown in Figure 10-1; Example 10-4 has the complete contents of the XSLT file.
In the template, the HTML tags to create a document and attach a stylesheet block are added to the page, just as they would be added to an HTML document. The differences occur where the XML contents are referenced.
First, the single paragraph element's value is accessed using an XSLT value-of
element. Since there is only one paragraph element in the page, the value-of
element processes this. If there were more, the additional paragraph elements would be discarded.
Both the <LI>
and the table elements repeat, so a for-each
XSLT element is used for them. As the elements that repeat are processed in the external for-each
statement, the actual value of the list item or the table cell is output by accessing the content's <span>
tag. This is why the contents had to be enclosed in another element, though the <span>
element didn't have to be used--you could make one of your own.
Example 10-4: An XSLT Document
<?xml version='1.0'?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl">
<xsl:template match="/">
<HTML>
<BODY>
<STYLE type="text/css">
P { border-style: groove;
border-width: 2px;
border-color: red;
width: 90%;
margin-left: 20px;
margin-top: 10px;
padding: 10px;
}
UL { margins: 20px }
LI { list-style-type: circle
}
TABLE { margin: 50px }
</STYLE>
<P><xsl:value-of select="doc/P" /></P>
<UL>
<xsl:for-each select="doc/UL/LI" >
<LI><xsl:value-of select="span" /></LI>
</xsl:for-each>
</UL>
<table border="1px" cellspacing="0" cellpadding="5px">
<xsl:for-each select="doc/table/tr">
<TR>
<xsl:for-each select="td">
<td><xsl:value-of select="span" /></td>
</xsl:for-each>
</TR>
</xsl:for-each>
</table>
</BODY>
</HTML>
</xsl:template>
</xsl:stylesheet>
In an XSLT-capable browser, when the XML document is accessed, the XSLT template is used to process the contents and the results are returned as a web page. Figure 10-2 shows the results of accessing the XML page shown in Example 10-3 within IE 5.x.
Figure 10-2.XML document formatted with XSLT template file
This is a very brief introduction to some of the XML-based technologies, which you will need as we look at working with XML in ASP applications, next.
Microsoft has an XML parser, MSXML, that you can access in your ASP components or script. With MSXML, you can open and work with existing XML documents or create new XML content.
The MSXML parser is based on the W3C's DOM (Document Object Model) specification, though Microsoft has extended the DOM to provide additional methods, properties, and objects to support XML processing efforts.
You can access the objects defined in MSXML by attaching the Microsoft XML type library to your VB component project. The following are some of the key objects:
- XMLDOMDocument
-
The top-level XML source object
- XMLDOMNode
-
Represents a single node in the document tree
- XMLDOMNodeList
-
A collection of nodes
- XMLDOMAttribute
-
An element attribute
- XMLDOMText
-
The text content of either an element or an element attribute
- XMLDOMCDataSection
-
XML CDATA sections (text that is not processed as markup)
- XMLDOMComment
-
An XML comment
- XMLDOMDocumentFragment
- Represents part of a document tree
You can load an external XML file with the XMLDOMDocument object and then process the contents using one or more of the other objects.
To demonstrate working with XML using MSXML from Visual Basic components, we'll take a different approach to working with XML. Instead of treating XML as a data source, we'll use XML to actually define a database query.
The document root is a query object that can contain several other elements, each defined for a specific purpose. For instance, the tables for the query are contained within tablename
elements, and the WHERE
clause column-value pairs are defined within the where
element: the column is identified by queryfield
, and the value is identified by queryvalue
. The columns returned from the query are contained within fieldname
elements. Example 10-5 contains an XML file defining a query against the WebPage table, returning the name and filename columns for all records where the page type code is set to HTM
. This XML file is found in the file asp1003.xml, located with the examples.
Example 10-5: XML File Containing a Database Query
<?xml version='1.0'?>
<doc >
<query>
<fields>
<fieldname>name</fieldname>
<fieldname>filename</fieldname>
</fields>
<tablename>WebPage</tablename>
<where>
<queryfield>page_type_cd</queryfield>
<queryvalue>'HTM'</queryvalue>
</where>
</query>
</doc>
To process the XML, create a Visual Basic component and name it asp1001
. Name the generated class xml
. This component has one method, processXMLQuery, shown in Example 10-6, that generates a database query string from the contents of a preexisting XML document. The string is then used to open an ADO recordset that's returned to the ASP page.
To support XML and ADO in the new component, attach the Microsoft XML and Microsoft ADO type libraries to the new project. Since the example uses the ASP built-in Response object, also attach the COM+ Services and the Microsoft Active Server Page Object type libraries. The processXMLQuery method takes as its only parameter a string containing the name and physical location of the XML file.
TIP: There are certain assumptions in the code shown in Example 10-6, such as all WHERE
clause conditions are joined by the AND
keyword, and all conditions are tests of equality.
The code creates an instance of the DOMDocument object (the XMLDOMDocument object) and calls its load method to load the XML file. Once the file is loaded, the getElementsByTagName method pulls in the elements of the query. The XMLDOMNode object's selectSingleNode method accesses the queryvalue and queryfield elements' values--the selectSingleNode method takes an XSL pattern query, which specifies a node name within the context of the node. The contents of the elements are used to generate the query string to open the ADO Recordset.
Example 10-6: Opening an XML File and Generating a Query from Its Contents
Function processXMLQuery(ByVal strFile As String) _
As Recordset
Dim strSelect As String
Dim strFrom As String
Dim strWhere As String
Dim strSQL As String
Dim i As Integer
Dim iCt As Integer
' XML objects
Dim MSXML As New DOMDocument
Dim mslist As IXMLDOMNodeList
' ADO
Dim rs As New Recordset
' load XML file
MSXML.Load (strFile)
' get select fields
Set mslist = MSXML.getElementsByTagName("fieldname")
strSelect = ""
iCt = mslist.length
For i = 0 To iCt - 1
If strSelect <> "" Then
strSelect = strSelect & ", "
Else
strSelect = "select "
End If
strSelect = strSelect & mslist(i).Text
Next
' get tables
Set mslist = MSXML.getElementsByTagName("tablename")
strFrom = ""
iCt = mslist.length
For i = 0 To iCt - 1
If strFrom <> "" Then
strFrom = strFrom & ", "
Else
strFrom = " from "
End If
strFrom = strFrom & mslist(i).Text
Next
' get where clause
Set mslist = MSXML.getElementsByTagName("where")
Dim strField As String
Dim strValue As String
strWhere = ""
iCt = mslist.length
For i = 0 To iCt - 1
If strWhere <> ""
Then
strWhere = strWhere & "
AND "
Else
strWhere = " where
"
End If
strField = mslist.Item(i).selectSingleNode("queryfield").Text
strValue = mslist.Item(i).selectSingleNode("queryvalue").Text
strWhere = strWhere & strField & "=" & strValue
Next
' perform query
strSQL = strSelect & strFrom &
strWhere
rs.CursorLocation = adUseClient
rs.Open strSQL, "Provider=SQLOLEDB;server=FLAME;database=weaver;uid=sa;pwd="
' disconnect recordset
Set rs.ActiveConnection = Nothing
Set processXMLQuery = rs
End Function
To test the example, the ASP test page, asp1001.asp, calls the component's method, passing in the name of the XML file. The file is in the same location as the ASP page, so the script uses the Server object's MapPath method to map the relative location of the file to an actual physical location:
<%
Dim obj
Set obj = Server.CreateObject("asp1001.xml")
Dim rs
Set rs = obj.processXMLQuery(Server.MapPath("asp1003.xml"))
' process records
Dim iCt, i
iCt = rs.Fields.Count
Response.Write "<TABLE>"
While rs.EOF <> True
Response.Write "<TR>"
For i = 0 to iCt - 1
Response.Write "<TD>" & rs.Fields(i) & "</TD>"
Next
Response.Write "</TR>"
rs.MoveNext
Wend
Response.Write "</TABLE>"
%>
Accessing the page results in the recordset contents being displayed within an HTML table.
By defining the query in an XML document and processing the XML elements for the query, you can create more than one query in more than one XML file. Example 10-7 shows a more complex XML file, asp1004.xml, that the asp1001.xml
component can process without modification. Notice in this example that more than one table is joined in the query, and there is more than one condition in the WHERE
clause.
Example 10-7: Second Database Query, Defined Using XML
<?xml version='1.0'?>
<doc>
<query>
<fields>
<fieldname>MediaObject.name</fieldname>
<fieldname>filename</fieldname>
<fieldname>file_size</fieldname>
<fieldname>directory.name</fieldname>
</fields>
<tablename>MediaObject</tablename>
<tablename>directory</tablename>
<where>
<queryfield>directory.id</queryfield>
<queryvalue>18</queryvalue>
</where>
<where>
<queryfield>directory_id</queryfield>
<queryvalue>directory.id</queryvalue>
</where>
<where>
<queryfield>media_type_cd</queryfield>
<queryvalue>'GIF'</queryvalue>
</where>
</query>
</doc>
Try asp1001.xml
with the new XML file, as shown in the following ASP test page, asp1002.asp:
Dim obj
Set obj = Server.CreateObject("asp1001.xml")
Dim rs
Set rs = obj.processXMLQuery(Server.MapPath("asp1004.xml"))
' process records
Dim iCt, i
iCt = rs.Fields.Count
Response.Write "<TABLE>"
While rs.EOF <> True
Response.Write "<TR>"
For i = 0 to iCt - 1
Response.Write "<TD>" & rs.Fields(i) & "</TD>"
Next
Response.Write "</TR>"
rs.MoveNext
Wend
Response.Write "</TABLE>"
The results of the more complex table join XML are displayed in the returned page.
You can also modify XML by replacing or modifying existing contents or creating new contents. As an example, consider the XML document shown in Example 10-5. This XML generates a query that returns the WebPage name and filename columns. You can modify this file and add a new column to the query using MSXML.
To demonstrate, add a second method to the asp1001.xml
component and call it addXML. This method takes two strings, the name of the XML file and the new field to add to the document's fieldnames list.
Add the code for the method, which is shown in Example 10-8. The addXML method first accesses the fieldname
element's parent element, fields
. Next, it creates a new node object using the createNode method and passing in the node type NODE_TYPE
(an enumerated value) as the first parameter and the name of the node, fieldname
, as the second parameter. Passing an empty string as the third parameter defines the element within the default namespace.
Once the node is created, the method inserts it into the XML document using the insertBefore method on the fields
node. The first parameter of this method is the new node, and the second parameter is the child node in front of which the new node is placed, or NULL
, which means that the new mode is placed at the end of the child list. Finally, the method saves the modified XML to the existing XML document.
Example 10-8: Modify Query by Adding New Fieldname to Query XML
' add field
Sub addXML(ByVal strFileName As String, _
ByVal strFieldName As String)
' XML objects
Dim msxml As New DOMDocument
Dim mselement As IXMLDOMNode
Dim msnode As IXMLDOMNode
Dim currnode As IXMLDOMNode
Dim mslist As IXMLDOMNodeList
' load XML file
msxml.Load (strFileName)
' get fields element
Set mslist = msxml.getElementsByTagName("fields")
Set mselement = mslist.Item(0)
' create node, assign node text
' insert into end of fieldname list
Set msnode = msxml.createNode(NODE_ELEMENT, "fieldname", "")
msnode.Text = strFieldName
Set currnode = mselement.insertBefore(msnode, Null)
' save XML file
msxml.save (strFileName)
End Sub
After saving and compiling the component, test it using the asp1003.asp file. The query XML file is called asp1005.xml and is a direct copy of asp1003.xml (shown in Example 10-7). The script in the test ASP file adds the file_size column name to the selection list of the query and then calls the processXMLQuery to process the query:
<%
Dim obj
Set obj = Server.CreateObject("asp1001.xml")
Dim file
file = Server.MapPath("asp1005.xml")
' add new field
obj.addXML file, "file_size"
' do query
Dim rs
Set rs = obj.processXMLQuery(file)
' process records
Dim iCt, i
iCt = rs.Fields.Count
Response.Write "<TABLE>"
While rs.EOF <> True
Response.Write "<TR>"
For i = 0 to iCt - 1
Response.Write "<TD>" & rs.Fields(i) & "</TD>"
Next
Response.Write "</TR>"
rs.MoveNext
Wend
Response.Write "</TABLE>"
%>
When you access the ASP test page, the results of running the query are shown to the page. If you open the modified asp1005.xml file, you should see something similar to the following:
<?xml version="1.0"?>
<doc>
<query>
<fields>
<fieldname>name</fieldname>
<fieldname>filename</fieldname>
<fieldname>file_size</fieldname></fields>
<tablename>WebPage</tablename>
<where>
<queryfield>page_type_cd</queryfield>
<queryvalue>'HTM'</queryvalue>
</where>
</query>
</doc>
Compare this XML with that shown in Example 10-5, and you'll see the addition of the new fieldname element, with the file_size contents. MSXML also nicely formats the output, indenting the elements.
Instead of generating XML by using MSXML, you can also use a new feature in ADO to save the contents of a recordset as XML. This is discussed next.
Converting database data into XML files quickly becomes pretty cumbersome whether you use MSXML or create the files manually. However, saving an ADO recordset as XML is as easy as calling one method--the Save method.
ADO recordsets could be persisted for sometime now, usually in ADTG (Microsoft Advanced Data Tablegram) format. However, you can also persist a recordset in XML format. Not only that, but when you persist the recordset as XML, you can save it to a file, an existing XML document, or even directly to the ASP built-in Response object.
To demonstrate the three ways in which you can persist the data in XML, you'll create three new methods for asp1001.xml
.
Add the code for the first method, which is shown in Example 10-9, to your asp1001.xml
class. This method, saveXMLToDocument, saves the XML-formatted data directly to an XML document. The saveXMLToDocument method creates new MSXML DOMDocument and ADO Recordset objects and sets the Recordset object's CursorLocation property to adUseClient
. The SQL used with the query is passed as a parameter to saveXMLToDocument, as is the name of the XML document the XML document tree will be saved to. Once the recordset is opened, the data is saved using the Recordset object's Save method. The first parameter is the DOMDocument object, and the second is the format type of the data. A value of adPersistXML
is used for this parameter, as well as for the next two component methods you'll create later. Once the XML has been added to the document tree, it's saved to an XML file using the DOMDocument Save method.
TIP: You can use server-side cursors with these examples. However, not all OLE DB providers support the same functionality--using the client-side cursor ensures that these examples work regardless of the OLE DB provider used.
Example 10-9: Saving Recordset Data as XML Directly to an XML Document Tree
' save to XML document
Sub saveXMLToDocument(ByVal strQuery As String, _
ByVal strFile As String)
Dim msxml As New DOMDocument
Dim rs As New Recordset
' perform query
rs.CursorLocation = adUseClient
rs.Open strQuery, "Provider=SQLOLEDB;server=FLAME;database=weaver;uid=sa;pwd="
' disconnect recordset
Set rs.ActiveConnection = Nothing
' save RS to DOM tree
rs.save msxml, adPersistXML
' save MSXML
msxml.save strFile
End Sub
Save the component and recompile it. To test your new method, use the following ASP page, asp1004.asp, which instantiates your component and calls saveXMLToDocument, passing in a query string and the name of the XML document to which the results are to be written:
<%
Dim obj
Set obj = Server.CreateObject("asp1001.xml")
' save using XML document
obj.saveXMLToDocument "select * from directory", _
Server.MapPath("asp1006.xml")
%>
Notice that the method uses Server.MapPath to map the relative filename to the physical location. Once the asp1006.xml document is created, open it with Internet Explorer. You should have a result similar to that shown in Figure 10-3.
Figure 10-3.
XML document created from persisting recordset to XML document tree
Looking at the XML document, you'll notice that not only is the recordset data persisted as XML, but so is the definition of the Recordset object itself. When you persist the Recordset object, you're persisting the entire object--not just the data. You could, if you wished, reopen the recordset from the file into an ADO recordset in another component or in script. If you just want the data, you can copy this directly from the XML document, or you can remove the recordset schema information using MSXML.
TIP: Ever notice how nicely XML documents that don't have associated stylesheets look with Internet Explorer? That's because IE has a built-in default stylesheet used with all XML documents that don't have either an XSL or CSS stylesheet attached.
Next, you'll persist the recordset directly to a file. Create a new method, as shown in Example 10-10, called saveXMLToFile. The method takes two parameters: a query string and the name of the output file. Like SaveXMLToDocument, the saveXMLToFile method again opens the recordset with the provided query, but instead of saving the recordset as XML to an XML document tree, it saves it directly to a file.
Example 10-10: Saving a Recordset as XML Directly to a File
' save XML to file
Sub saveXMLToFile(ByVal strQuery As String, _
ByVal strFile As String)
Dim rs As New Recordset
' perform query
rs.CursorLocation = adUseClient
rs.Open strQuery, "Provider=SQLOLEDB;server=FLAME;" _
& "database=weaver;uid=sa;pwd="
' disconnect recordset
Set rs.ActiveConnection = Nothing
' save RS in XML format to file
rs.save strFile, adPersistXML
End Sub
Try this component with the following ASP test script, found in asp1005.asp:
<%
Dim obj
Set obj = Server.CreateObject("asp1001.xml")
' save using file
obj.saveXMLToFile "select * from MediaObject", _
"c:\datasets\mediaobject.xml"
%>
The result of running this script is an XML file, created in the specified location (adjust the file location for your own environment). Opening the new file, you'll see that the XML in it is the same as that created with the SaveXMLToDocument method in Example 10-9 and shown in Figure 10-3.
TIP: If the file that the recordset is being saved to already exists, you'll get an error. See more on persisting recordsets in Chapter 8, Creating ASP/ADO Components.
Also, be aware of privileges whenever you do any form of file I/O. If your web user doesn't have permission to write or read a file from a given location, an error will occur.
The last component method you'll create for this chapter actually persists the recordset directly to the built-in ASP Response object. This is possible because the Response object supports the OLE DB IStream
interface, required of any object that serves as the destination for the Recordset object's Save method.
Create a new method called saveXMLToResponse, shown in Example 10-11. The method has one parameter, the query string. It instantiates the Response object and then creates and opens the recordset with the given query string. Finally, it writes out the XML declaration using the Response object and then saves the recordset directly to the Response object.
Example 10-11: The saveXMLToResponse Method
' save XML directly to response (stream)
Sub saveXMLToResponse(ByVal strQuery As String)
Dim objContext As ObjectContext
Dim objResponse As Response
Set objContext = GetObjectContext()
Set objResponse = objContext("Response")
Dim rs As New Recordset
' perform query
rs.CursorLocation = adUseClient
rs.Open strQuery, "Provider=SQLOLEDB;server=FLAME;" _
& "database=weaver;uid=sa;pwd="
' disconnect recordset
Set rs.ActiveConnection = Nothing
' save RS to DOM tree
objResponse.Write "<?xml version='1.0' ?>" & vbCrLf
rs.save objResponse, adPersistXML
End Sub
The method must write out the XML declaration first, or the XML returned by the Response object won't be treated as XML. Setting the Response object's ContentType property won't work when you persist the Recordset object directly to the object.
The ASP test page, asp1006.asp, for this last method is pretty simple--it consists of the ASP script to create asp1001.devaspcompxml
and call saveXMLToResponse:
<%
Dim obj
Set obj = Server.CreateObject("asp1001.xml")
' save to response
obj.saveXMLToResponse "select * from WebPage"
%>
The result is a web page with XML defining the recordset and its data.
The end result of persisting the recordset as XML is the same with all three of the techniques used in this section--all that differs is the end location of the recordset and the queries used.
Persisting the recordset by saving it to an XML document, which can then be saved, or by saving it directly to a file provides access to the recordset for other server-side components. Your ASP server-side applications won't be able to access the recordset saved to the Response object, but this approach can be used to pass a recordset to the client when using something such as Remote Data Services (RDS).
TIP: See the documentation provided with the Data SDK from Microsoft on working with RDS.