Creating a DTD on the Fly

The ViewRecords method calls EmitDTD (a method in the SQLXML component), which creates a Document Type Definition (DTD) for the XML stream. EmitDTD receives two parameters: the recordset oRS, which ViewRecords creates and populates, and oResponse, which is an ASP Response object. Within EmitDTD, code runs to assemble a string (sRec) that contains a DTD for the current recordset. This code can emit a DTD for any recordset.

The following four steps create and emit a DTD:

  1. Initialize sRec with a string that contains the DOCTYPE name (xmldata in the following code fragment) and the definition of the root element of the DTD (also xmldata). Note that the DOCTYPE name must match the root element of the document. The definition shown here specifies that the xmldata element contains one or more record elements as indicated by the "+". A Sample DTD contains a complete DTD that is generated from a very simple recordset, using the following code:
    sRec = "<!DOCTYPE xmldata [" & vbCrLf & vbCrLf & _
              "<!ELEMENT xmldata (record)+>" & vbCrLf & _
              "<!ELEMENT record ("
    
  2. Code loops through the fields in the recordset and concatenates sRec with each field name. If the Attributes property of oField (an ADODB.Field object) is adFldIsNullable, indicating the field accepts null values, code appends a "?" to sRec. An element with a "?" suffix is an optional element.
    sSep = ""
    For Each oField In oRs.Fields
       sRec = sRec & sSep & oField.name
       If oField.Attributes And adFldIsNullable Then
          sRec = sRec & "?"
       End If
       sSep = ","
    Next
    sRec = sRec & ")>" & vbCrLf
    
  3. Code loops through the fields in the recordset again. This time, the code adds an element for each field to the DTD. The string (#PCDATA ) means the element contains parsed character data and any reserved XML characters are ignored. The # indicates that PCDATA is a reserved word.
    For Each oField In oRs.Fields
       sRec = sRec & "<!ELEMENT " & oField.name & " (#PCDATA)>" & vbCrLf
    …
    Next
    
  4. Code concatenates a string to sRec specifying that the record element must contain an id attribute. In the following code fragment, id is the attribute and ID is an intrinsic XML data type. Converting a Recordset to XML describes how the Convert method assigns the value of the primary key for a record to the id attribute. NodeFromID vs. SelectSingleNode discusses how the nodeFromId method of the XML DOM document object uses the id attribute of a record.
    sRec = sRec & vbCrLf & _
                  "<!ATTLIST record" & vbCrLf & _
                  "          id ID #REQUIRED" & vbCrLf & _
                  " >" & vbCrLf & vbCrLf & _
                  "]>" & vbCrLf & vbCrLf 
    

The following code calculates the delay before data is written to the browser based on the approximate size of the record. The flushCount variable is a private variable that contains the value of the delay.

flushCount = CInt(4096 / recSize) + 1