[thelist] xml vs. regular database
David.Cantrell at Gunter.AF.mil
David.Cantrell at Gunter.AF.mil
Fri Jan 17 10:13:01 CST 2003
>what kinda of custom VBScript class? Could you give me an example?
Sure. :)
I was going to release this on the web at some point anyway, just haven't
gotten around to it. It's something that works for me.
And I blatantly ripped off an old Microsoft article in doing it, but their's
was kludged in Javascript, I converted it to VBScript and cleaned it up and
enhanced it so it's not exactly plagiarism. ;)
This may wrap in your e-mail system -- if so I can send it directly to you
as an attachment.
***** BEGIN CLASS SNIPPET *****
#FILENAME: class.XmlUtilsObject.asp
<%
'===========================================================================
==========================================
' XmlUtilsObject
' Provides enhanced Xml capabilities, such as simplified transformation,
Recordset-to-Xml capabilities, etc.
' Base methods were taken from MSDN "Beyond ASP" article.
' AddXslParameter function added later.
'===========================================================================
==========================================
Class XmlUtilsObject
'===========================================================================
==========================================
' Public Methods
'===========================================================================
==========================================
'---------------------------------------------------------------------------
------------------------------------------
'Title: AddXmlNode
'About: Adds a new DomNode to the XmlDomDocument object passed in, as a
child to the parent node specified.
'Accepts: XmlDomDocument. Msxml.XmlDomDocument. Required. XML document to
which the node will be added.
'Accepts: ParentNode. DomNode. Required. The XML Node that will be the
parent of the added node.
'Accepts: Name. String. Required. The name of the node to create.
'Accepts: Value. String. Required. The value of the node that is created.
'Returns: XmlDomNode object.
Public Function AddXmlNode( oXmlDomDocument, oParentNode, sName, sValue )
Set AddXmlNode = AddXmlNodeEx( oXmlDomDocument, oParentNode, sName,
sValue, "" )
End Function
'---------------------------------------------------------------------------
------------------------------------------
'Title: AddXmlNodeEx
'About: Adds a new DomNode to the XmlDomDocument passed in, as a child to
the parent node specified.
'Remarks: AddXmlNodeEx allows the caller to specify a custom namespace for
the created node.
'Accepts: XmlDomDocument. Type=Msxml.XmlDomDocument. Required. XML document
to which the node will be added.
'Accepts: ParentNode. Type=DomNode. Required. The XML Node that will be the
parent of the added node.
'Accepts: Name. String. Required. The name of the node to create.
'Accepts: Value. String. Required. The value of the node that is created.
'Accepts: Namespace. String. Optional. The namespace of the string that will
be created.
'Returns: XmlDomNode object.
'Effects: Namespace is returned as attribute value, e.g. <name
xmlns="namespace">value</name>.
Public Function AddXmlNodeEx( oXmlDomDocument, oParentNode, sName, sValue,
sNamespace )
dim oNode : Set oNode = oXmlDomDocument.CreateNode( 1, Lcase( sName ),
sNamespace )
If Not Len( sValue ) = 0 then
oNode.Text = Trim( sValue )
End If
oParentNode.AppendChild oNode
Set AddXmlNodeEx = oNode
If Len( sNamespace ) > 0 then
End If
End Function
'---------------------------------------------------------------------------
------------------------------------------
'Title: RecordsetToXml
'About: Processes a flat (non-hierarchical) recordset and returns a
populated XmlDomDocument object.
'Remarks: The document is in this format:
' <pre>NodeNames
' NodeName
' Value
' Value
' ...</pre>
' Where NodeNames is the name passed in with an "s" added, and
NodeName is simply the name passed in.
'Accepts: Recordset. Adodb.Recordset. Required. Recordset containing the
data to convert.
'Accepts: NodeName. String. Required. NodeName used in description above.
'Returns: XmlDomDocument object.
'Assumes: Recordset cursor is not set to EOF.
Public Function RecordsetToXml( oRs, sNodeName )
dim oXml : Set oXml = Server.CreateObject(
"Msxml2.DomDocument.4.0" )
dim oNodeCol : Set oNodeCol = AddXmlNode( oXml, oXml, sNodeName & "s",
"" )
dim oNode
dim oField
Do until oRs.Eof
Set oNode = AddXmlNode( oXml, oNodeCol, sNodeName, "" )
For Each oField in oRs.Fields
AddXmlNode oXml, oNode, oField.Name, Trim( oField.Value )
Next
oRs.MoveNext
Loop
Set RecordsetToXml = oXml
End Function
'---------------------------------------------------------------------------
------------------------------------------
'Title: GetXmlDoc
'About: Retrieves the specified Xml document as a DomDocument object.
'Remarks: The document may be either a well-formed fragment, a full Xml
document, or a relative path to a file.
'Accepts: XmlDoc. Variant. Required. String containing XSL or relative path
to XSL file, or XmlDomDocument object.
'Returns: XmlDomDocument object.
Public Function GetXmlDoc( vXmlDoc )
Set GetXmlDoc = GetXmlDocEx( vXmlDoc, "Normal" )
End Function
'---------------------------------------------------------------------------
------------------------------------------
'Title: GetFreeThreadedXmlDoc
'About: Retrieves the specified Xml document as a FreeThreadedDomDocument
object.
'Remarks: The document may be either a well-formed fragment, a full Xml
document, or a relative path to a file.
'Accepts: XmlDoc. Variant. Required. String containing XSL or relative path
to XSL file, or XmlDomDocument object.
'Returns: XmlDomDocument object.
Function GetFreeThreadedXmlDoc( vXmlDoc )
Set GetFreeThreadedXmlDoc = GetXmlDocEx( vXmlDoc, "FreeThreaded" )
End Function
'---------------------------------------------------------------------------
------------------------------------------
'Title: AddXslParameter
'About: Adds parameters for the stylesheet.
'Remarks: Parameters are added to an internal list and set in XSL when
document is transformed -- XSL is NOT edited interactively.
'Remarks: Bear in mind that, as you are dealing with an XML document, you
may need to escape the values you pass in the parameters.
'Accepts: ParameterName. String. Required. Name of the parameter to set.
'Accepts: ParameterValue. String. Required. Value of the parameter being
set.
'Returns: Nothing.
'Assumes: Nothing.
'Ensures: Internal list is updated with new name & value.
'Effects: If the specified parameter already exists in the list, the
original value is overwritten.
Sub AddXslParameter( sParameterName, sParameterValue )
If Not IsObject( oXSL_PARAMETERS ) then
Set oXSL_PARAMETERS = Server.CreateObject( "Scripting.Dictionary" )
End If
oXSL_PARAMETERS.Add sParameterName, sParameterValue
End Sub
'---------------------------------------------------------------------------
------------------------------------------
'Title: TransformXml
'About: Transforms the specified xml document using the specified xsl
document.
'Remarks: Xml and Xsl documents can be well-formed fragments, entire
documents, XmlDomDocument objects, or relative paths to files.
'Accepts: SourceXml. Variant. Required. String containing XML or relative
path to XML file, or XmlDomDocument object.
'Accepts: SourceXsl. Variant. Required. String containing XSL or relative
path to XSL file, or XmlDomDocument object.
'Returns: String containing the transformed output.
Public Function TransformXml( vSourceXml, vSourceXsl )
dim sReturn 'the return value
dim oXml 'the xml object
dim oXsl 'the xsl object
dim bHasParameters 'switch to determine processing path
'loads XML object and checks for errors
Set oXml = GetXmlDoc( vSourceXml )
CheckForParseError oXml
Validate oXml
'determines if parameters were passed before this method was called
If IsObject( oXSL_PARAMETERS ) then
'ubound will return -1 if no keys (parameter names ) exist
If Ubound( oXSL_PARAMETERS.Keys() ) >= 0 then
bHasParameters = true
Else
bHasParameters = false
End If
Else
bHasParameters = false
End If
'if parameters were specified, passes them to the stylesheet
'otherwise simply transforms the document using the provided stylesheet
If bHasParameters then
Set oXsl = GetFreeThreadedXmlDoc( vSourceXsl )
'parameters exist, creates XSL template and processor, adds parameters
to stylesheet, and transforms using processor
dim oXslt : Set oXslt = Server.CreateObject( "Msxml2.XslTemplate.4.0" )
Set oXslt.Stylesheet = oXsl
dim oProc : Set oProc = oXslt.CreateProcessor()
oProc.Input = oXml
'loops through parameters in dictionary and adds them to the stylesheet
dim aKey : aKey = oXSL_PARAMETERS.Keys()
dim aItem : aItem = oXSL_PARAMETERS.Items()
dim i
For i = 0 to Ubound( aKey )
oProc.AddParameter aKey( i ), aItem( i )
Next
oProc.Transform
sReturn = oProc.Output
Set oProc = Nothing
Set oXslt = Nothing
Else
Set oXsl = GetXmlDoc( vSourceXsl )
sReturn = oXml.TransformNode( oXsl )
End If
TransformXml = sReturn
End Function
'===========================================================================
==========================================
' Initialization and Termination Routines
'===========================================================================
==========================================
Private Sub Class_Initialize
End Sub
'---------------------------------------------------------------------------
------------------------------------------
Private Sub Class_Terminate
'if XSL parameter dictionary exists, it is destroyed
If IsObject( oXSL_PARAMETERS ) then
Set oXSL_PARAMETERS = Nothing
End If
End Sub
'===========================================================================
==========================================
' Private Properties
'===========================================================================
==========================================
Private oXSL_PARAMETERS 'Scripting.Dictionary object containing XSL
parameters
'===========================================================================
==========================================
' Private Methods
'===========================================================================
==========================================
'Title: GetXmlDocEx
'About: Retrieves the specified Xml document as either a DomDocument or
FreeThreadedDomDocument object.
'Remarks: The document may be either a well-formed fragment, a full Xml
document, or a relative path to a file.
'Accepts: XmlDoc. Variant. Required. String containing XSL or relative path
to XSL file, or XmlDomDocument object.
'Accepts: Type. String. Required. Type of document to return. Possible
values are "FreeThreaded" and "Normal". Default is "Normal".
'Returns: XmlDomDocument object.
Private Function GetXmlDocEx( vXmlDoc, sType )
dim oXml
If IsObject( vXmlDoc ) then
'uses the object passed in
Set oXml = vXmlDoc
Else
If Lcase( Trim( sType ) ) = "freethreaded" then
'creates a FreeThreadedDomDocument object
Set oXml = Server.CreateObject( "Msxml2.FreeThreadedDomDocument.4.0" )
Else
'type is "Normal", creates a normal DomDocument object
Set oXml = Server.CreateObject( "MsXml2.DomDocument.4.0" )
End If
If InStr( vXmlDoc, "<" ) > 0 then
'this is an Xml string because < is not valid in a filename
oXml.LoadXml vXmlDoc
ElseIf InStr( vXmlDoc, "\" ) > 0 then '"' comment to fix stupid
homesite color bug
'this is a physical path because \ only occurs in physical paths
oXml.Load vXmlDoc
Else
oXml.Load Server.MapPath( vXmlDoc )
End If
End If
Set GetXmlDocEx = oXml
End Function
'---------------------------------------------------------------------------
------------------------------------------
'Title: CheckForParseError
'About: Checks the passed XML object for any parsing errors. If any exist,
they are reported using ReportParseError.
'Accepts: Xml. MsxmlDomDocument. Required. The XML object to check for a
parsing error.
'Returns: Nothing.
'Assumes: Nothing.
'Ensures: Error is raised if encountered.
Private Sub CheckForParseError( oXml )
'check for parse errors
If Not oXml.ParseError = 0 then
response.write ReportParseError( oXml.ParseError )
End If
End Sub
'---------------------------------------------------------------------------
------------------------------------------
'Title: Validate
'About: Validates the passed XML object. If invalid, ReportParseError is
called.
'Accepts: oXml. MsxmlDomDocument. Required. The XML object to check for
validity.
'Returns: Nothing.
Private Sub Validate( oXml )
dim oErr : Set oErr = oXml.Validate()
If Not oErr Is Nothing then
ReportParseError oErr
End If
End Sub
'---------------------------------------------------------------------------
------------------------------------------
'Title: ReportParseError
'About: Reports a parse error.
'Accepts: Error. XmlDomDocument.ParseError. Required. Object containing XML
ParseError information.
'Returns: String containing formatted parse error.
Private Function ReportParseError( oError )
dim s
dim i
For i = 1 to oError.LinePos
s = s & " "
i = i + 1
Next
dim sResult
sResult = "<h1>XML Error loading '" & oError.Url & "'</h1>"
sResult = sResult & "<div style='font-family: Verdana; font-size: 10pt;'>"
sResult = sResult & "<b>Error Code:</b> " & oError.ErrorCode
sResult = sResult & "<br><b>Reason:</b> " & oError.Reason
sResult = sResult & "<br><b>Source:</b> Line " & oError.Line & ",
Character " & oError.LinePos
sResult = sResult & "<br>" & oError.SrcText
sResult = sResult & "</div>"
ReportParseError = sResult
End Function
End Class
%>
***** END CLASS SNIPPET *****
Here's an example ASP script where it might be used:
***** BEGIN ASP SNIPPET *****
<%
Option Explicit
%>
<!--#include virtual="/path/to/class.XmlUtilsObject.asp"-->
<%
Server.Execute ( "header.asp" )
dim oConn : Set oConn = Server.CreateObject ( "connectionString" )
dim oRs : Set oRs = oConn.Execute ( "select * from employees" )
dim XmlUtils : Set XmlUtils = New XmlUtilsObject
Response.Write XmlUtils.TransformXml ( XmlUtils.RecordsetToXml ( oRs,
"employee" ), "employees.xsl" )
oRs.Close
Set oRs = Nothing
oConn.Close
Set oConn = Nothing
Server.Execute ( "footer.asp" )
%>
***** END ASP SNIPPET *****
The above code selects all records from the "employees" table and then
passes that recordset through the XmlUtils object. The
XmlUtils.RecordsetToXml() function takes the recordset (oRs) and a string
called "sNodeName" in the function definition in the class. It then builds
the XML document in the following format:
<employees>
<employee>
<id>1</id>
<name>John Doe</name>
<deptid>45</deptid>
</employee>
<employee>
...
</employee>
</employees>
It takes the sNodeName of "employee" passed in the function and creates the
XML document with a root node of sNodeName+s, then each row is created as a
child element with a name of sNodeName, i.e. given an sNodeName of
"employee" the root element is "employees" and each row returned is captured
in an element named "employee". Each column in the recordset is then created
as an element underneath the appropriate row element (the "employee"
element).
Also, all elements are created in lower case format, to minimize typos.
Then you just pass that through a stylesheet, like this:
***** BEGIN XSL SNIPPET *****
#FILENAME: employees.xsl
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="1.0">
<xsl:output method="html"/>
<xsl:template match="/">
<h1>Employee Listing</h1>
<ul>
<xsl:apply-templates select="/employees/employee"/>
</ul>
</xsl:template>
<xsl:template match="employee">
<li>
<p>
ID: <xsl:value-of select="id"/>
<br/>
Name: <xsl:value-of select="name"/>
<br/>
Dept Id: <xsl:value-of select="deptid"/>
</p>
</li>
</xsl:template>
</xsl:stylesheet>
***** END XSL SNIPPET *****
Does any of this make sense? :)
Now to answer your other question(s):
>I thought it went like this
>XML - your data file
>XSL - your language file (this is where you stick your html that goes
around
>the data in the XML file - right?)
>XSD - your definition file for your xml file...
The XML doesn't have to reside in a file -- it's just a document, just like
HTML or any other. It's created in memory, passed through a stylesheet, and
the output is written to the browser. The XSLT is Extensible Stylesheets
Language for Transformations -- yes, it's where you convert it to HTML. Or
PDF, or plain-text, or any other text format. It's just a templating system.
As for XSD, I don't really use it. I messed with it for a while, but for
what I do (which is NOT large-scale development) I don't have a need for it.
The complexity of XSD for me outweighs the benefits.
HTH,
-dave
More information about the thelist
mailing list