APGen Documentation Previous Topic: Sinking COM Events in APG Scripts Next Topic: Using Other Script Languages Parent Topic: APGen Developer's Guide    APGen Developer's Guide
Developing with XML
See Also:

XML (Extensible Markup Language) is a critical standard for web content.  APGen can be used to generate XML documents as easily as it can be used to generate HTML documents.

APGen is valuable for generating XML content from any data source.  Many data sources do not return content in XML format - APG scripts can be written to access these data sources (via COM) and format the content in any desired XML schema.

XSLT (Extensible Stylesheet Language Transformations) is the standard XML-based language for transforming one class of XML document to another.  While XSLT is often the best choice for XML transformation, Active Server Pages programmers may find APG scripts easier to use for generating web documents.  APGen provides the best of both worlds and ultimate flexibility:

Generating XML

Generating XML in APG scripts is straightforward.  These two pointers should help:

  1. Make sure there isn't any extra whitespace before the beginning of the XML document. For example, this snippet:

    <%# @LANGUAGE="VBScript" #%>
    <%#

    Output.Filename = "quotes.xml"
    ...

    #%>
    <?xml version="1.0" encoding="UTF-8"?>
    <quotes>
        ...

    </quotes>

    will not parse correctly with the Microsoft.XMLDOM, because a return-linefeed exists before the <?xml > directive.  By changing it to: 

    <%# @LANGUAGE="VBScript" #%>
    <%#

    Output.Filename = "quotes.xml"
    ...

    #%><?xml version="1.0" encoding="UTF-8"?>
    <quotes>
        ...

    </quotes>

    the document can be parsed correctly.
  2. Use Util.XMLEncode() to encode content that is not placed in <![CDATA[ ... ]]> blocks.  This will ensure that programmable content will not prevent the XML document from being well-formed:

    <%# @LANGUAGE="VBScript" #%>
    <%#

    Output.Filename = "quotes.xml"

    Dim sQuote, sAuthor
    sQuote = "My mother said to me, ""If you become a soldier " & _
         "you'll be a general; if you become a monk you'll end " & _
         "up as the pope."" Instead, I became a painter and wound " & _
         "up as Picasso."
    sAuthor = "Pablo Picasso"

    #%><?xml version="1.0" encoding="UTF-8"?>
    <quotes>
         <quote author="
    <%# =Util.XMLEncode(sAuthor) #%>"
           >
    <%# =Util.XMLEncode(sQuote) #%></quote>
    </quotes>

Applying XSLT To Generated Output

To apply XSLT transforms to generated XML, you'll want to turn output buffering on:

Output.Buffer = True

Then, after the XML document is generated, the buffered output can be retrieved and replaced using the Output.BufferContents property.  An XSL transform can be applied to the buffered output:

<%#

' Buffer output
Output.Buffer = True

' Generate XML content
#%><?xml version="1.0"?>
<body>
     . . .
</body>
<%#

' Load the buffered output into an XML object
Dim oXML
Set oXML = Script.CreateObject("Microsoft.XMLDOM")
If Not oXML.loadXML(Output.BufferContents) Then
     Log.Write "Error loading XML", apgSeverityFatal
     Script.Abort
End If

' Load an XSL stylesheet
Dim oXSL
Set oXSL = Script.CreateObject("Microsoft.XMLDOM")
If Not oXSL.load(Script.Dir & "transform.xsl") Then
     Log.Write "Error loading XSL", apgSeverityFatal
     Script.Abort
End If

' Overwrite the output buffer with the transformed content
Output.BufferContents = oXML.transformNode(oXSL)

' This flushes the buffer to the file, then closes the file
Output.Close()
#%>

Example

This example shows how to execute APG scripts and use XSLT to transform output to target different browsers or user devices.  In this example each document generates output for uplevel browsers, downlevel browsers, and WAP clients.  Familiarity with XML and XSLT is assumed, and we do not show the XML or XSLT documents used.  This is a generic system for targeting different browsers and devices.

Page content and page-specific logic are separated from device presentation details, which makes web site development and maintenance easier.  Performance is excellent because the page content is not generated for every request, and the device-specific transform is not performed for every request.  By generating static pages only when page data changes, performance is outstanding. 

APG scripts contain the content and page-specific logic for each web page.  The APG scripts generate XML in a "generic" schema that is independent of browser or device details.  Each XSLT transform corresponds to the display rules for different device types - the XSLT is responsible for transforming the generic schema to a browser or device-specific schema.  Only one XSLT page needs to be developed for each targeted device - the same XSLT transform is applied to each APG script in the site.  This generic schema and the device-specific XSLT transforms are out of the scope of this example - they are not shown.

In this example, an array lists the APG scripts to execute, and an array lists the XSLT transforms to apply to the output of each APG script.  Each of the APG scripts is executed, the script's output is loaded into an XMLDOM, then all the XSLT transforms are applied to the XMLDOM. 

An array of filename extensions is used to compute the filename of each output combination.  For example, the downlevel version of the output of contents.apg is named contents_dnl.htm.  The uplevel version of the same document is named contents_upl.htm, and the WAP version is named contents.wml.

<%# @LANGUAGE="VBScript" #%>
<%# Option Explicit #%>
<%#
'------------------------------------------------------
'        MultiBrowser.apg
'
' Description: Executes some APG scripts, which generate
' XML content.  This XML content is transformed using
' several XSLT transforms.  Each XSLT transform corresponds
' to the display rules for different device types.
'
' For example: downlevel.xsl produces output for downlevel
' browsers.  When downlevel.xsl is applied to the output
' from contents.apg, the result is contents_dnl.htm.
'
' Copyright (c) 1999-2001 WebGecko Software
'------------------------------------------------------

' List the APG scripts to execute
' Each of these generates XML
Dim rgScripts
rgScripts = Array("default.apg", _
                  "contents.apg")
                  
' List the XSLT transforms to apply, plus the output file
'  extensions to use
Const nXSLTs = 3 ' The number of XSLTs                  
Dim rgXSLTs() ' Array of info about the XSLTs
ReDim rgXSLTs(nXSLTs-1, 1)

' Targets uplevel browsers (IE 4.0+, Netscape 6+)
rgXSLTs(0,0) = "uplevel.xsl"
rgXSLTs(0,1) = "_upl.htm" ' Uplevel pages end w/ this extension

' Targets downlevel web browsers
rgXSLTs(1,0) = "downlevel.xsl"
rgXSLTs(1,1) = "_dnl.htm" ' Downlevel pages end w/ this extension

' Targets WAP browsers
rgXSLTs(2,0) = "wap.xsl"
rgXSLTs(2,1) = ".wml" ' WAP pages end w/ this extension


' Create an APGen object, and set global settings
Dim oAPGen
Set oAPGen = Script.CreateObject("APGen")

' Place output here
oAPGen.OutputDir = Script.Dir & "output"

' Buffer output for all pages
oAPGen.BufferOutput = True


' Load the XSLT documents
Dim rgXSLTDOMs() ' Array of XSLT DOMs
ReDim rgXSLTDOMs(nXSLTs-1)
Dim i, oXSL, sXSLTFilename
For i = 0 To nXSLTs-1
    ' The name of the XSL file
    sXSLTFilename = rgXSLTs(i, 0)
    
    ' Load a new XMLDOM
    Set oXSL = Script.CreateObject("Microsoft.XMLDOM")
    If Not oXSL.load(Script.Dir & sXSLTFilename) Then
        Err.Raise vbObjectError, "Multibrowser2.apg", "Error loading XSL doc " & sXSLTFilename
    End If
    
    ' Store it in rgXSLTDOMs
    Set rgXSLTDOMs(i) = oXSL
Next


' Execute the APG scripts
Dim sAPGScript
For Each sAPGScript In rgScripts

    ' Open the APG script
    Dim oScript
    Set oScript = oAPGen.OpenScript(sAPGScript)
    
    ' Run it
    oScript.Run
    
    ' Load an XML document from the APG script's output
    Dim oXML
    Set oXML = Script.CreateObject("Microsoft.XMLDOM")
    If Not oXML.loadXML(oScript.Output.BufferContents) Then
        Err.Raise vbObjectError, "Multibrowser2.apg", _
                "Error loading XML from the output of " & sAPGScript
    End If
    oScript.Output.ClearBuffer()
    
    ' Loop through the XSLTs, applying each one to the XML
    For i = 0 To nXSLTs-1
        Dim sExt ' The extension of the output file
        Dim sFilename ' The name of the output file
        sExt = rgXSLTs(i,1)
        
        ' Compute the output filename
        sFilename = Left(sAPGScript, InStr(1, sAPGScript, ".")-1) & sExt
        
        ' Set the output filename
        oScript.Output.Filename = sFilename
        
        ' Obtain the XSL DOM for this stylesheet
        Set oXSL = rgXSLTDOMs(i)
        
        ' Transform the XML document with it
        oScript.Output.BufferContents = oXML.transformNode(oXSL)
        
        ' Flush buffered content to the output file, then close the file
        oScript.Output.Close()
    Next

Next ' For Each sAPGScript

#%>