<% Class XmlForm Private m_Doc Private m_IsValid Private m_FileName Private m_Log Public Sub Class_Initialize() Set m_Doc = CreateObject("MSXML2.DOMDocument.4.0") Set m_Log = New Logger : m_Log.Level = "ERROR" : m_Log.BufferOutput = True : m_Log.Name = "XmlForm" m_IsValid = True End Sub ' Loads the definition from an XML file. Public Function Load(FileName) m_FileName = Server.MapPath(FileName) Load = m_Doc.Load(m_FileName) If Not Load Then Dim Error : Set Error = m_Doc.parseError m_Log.Error "Xml parsing error at line " & Error.Line _ & ", char " & Error.LinePos & ": " & Error.Reason _ & "
" & Error.SrcText End If End Function ' Loads the definition from a string. Public Function LoadXml(XmlString) LoadXml = m_Doc.LoadXml(XmlString) If Not LoadXml Then Dim Error : Set Error = m_Doc.parseError m_Log.Error "Xml parsing error at line " & Error.Line _ & ", char " & Error.LinePos & ": " & Error.Reason _ & "
" & Error.SrcText End If End Function ' Returns whether the form is valid or not. Public Property Get IsValid IsValid = m_IsValid End Property ' Returns text that you can insert into a web page to display the form. Public Function ToString() Dim NewDoc, Hidden, Node, FormNode, Action ' If the form hasn't got an action, set the action to the current page. Set FormNode = m_Doc.selectSingleNode("/form") If FormNode.getAttribute("action") = "" Or IsNull(FormNode.getAttribute("action")) Then Action = Request.ServerVariables("URL") If FormNode.getAttribute("method") = "POST" Then Action = Action & "?" & Request.QueryString End If FormNode.setAttribute "action", Action End If ' Clone the document so we can remove elements that should be hidden, ' without modifying the original document Set NewDoc = m_Doc.cloneNode(True) Set Hidden = NewDoc.selectNodes("//node()[@hidden='1']") For Each Node In Hidden Node.parentNode.removeChild Node Next ToString = NewDoc.Xml End Function ' Populates the form with data submitted by the browser. Public Sub Grab() Dim Config, Form, Method ' Get the element that describes the form, and the form itself. Set Config = m_Doc.selectSingleNode("/form/config") Set Form = m_Doc.selectSingleNode("/form") If Form Is Nothing Or Config Is Nothing Then m_IsValid = False Else Method = Form.getAttribute("method") ' See if the browser posted any form data. If not, then there is no ' point trying to set element values. If GetBrowserData(Method, "formSanityCheck") = "" Then m_IsValid = False Else ' For each element described in the config element, get the element or ' list of elements in the form, and populate them with the browser's ' data. Dim Node For Each Node In m_Doc.DocumentElement.selectNodes("/form/config/element") SetValue Node.getAttribute("name"), GetBrowserData(Method, Node.getAttribute("name")) Next End If End If End Sub ' Gets a value from the form, by name Public Function GetValue(Name) Dim Config, Node, Val, Options, Child, Result(), i Set Config = m_Doc.selectSingleNode("/form/config/element[@name='" & Name & "']") If Config Is Nothing Then m_Log.Error "The form element '" & Name & "' is not defined in the config." Exit Function End If ' Get the element's value If Config.getAttribute("type") = "array" Then If Config.getAttribute("tag-name") = "input" Then ' It's a CheckBox Set Options = m_Doc.selectNodes("//input[@type='checkbox' and @checked='1' and @name='" & Name & "']") ReDim Result(Options.Length - 1) For i = 0 To Options.Length - 1 Result(i) = Options(i).Attributes.getNamedItem("value").Text Next GetValue = Result ElseIf Config.getAttribute("tag-name") = "select" Then Set Node = m_Doc.selectSingleNode("//select[@id='" & Config.getAttribute("element-id") & "']") Set Options = Node.selectNodes("option[@selected='1']") ReDim Result(Options.Length - 1) For i = 0 To Options.Length - 1 Result(i) = Options(i).Attributes.getNamedItem("value").Text Next GetValue = Result End If ElseIf Config.getAttribute("element-id") <> "" Then ' It's a scalar that's not a radio button or checkbox array Set Node = m_Doc.selectSingleNode("//node()[@id='" & Config.getAttribute("element-id") & "']") If Not Node Is Nothing Then If Node.nodeName = "select" Then ' Find the correct child node of the element and get its value For Each Child In Node.selectNodes("option") If Child.getAttribute("selected") <> "" Then GetValue = Child.getAttribute("value") End If Next ElseIf Node.nodeName = "input" Then ' It's a TextBox, Password, Hidden, Button, Submit, or Reset Select Case Node.getAttribute("type") Case "checkbox" If Not IsNull(Node.getAttribute("checked")) And Not IsNull(Node.getAttribute("value")) Then If Node.getAttribute("checked") = "1" Then GetValue = Node.getAttribute("value") Else GetValue = "" End If End If Case Else If Not IsNull(Node.getAttribute("value")) Then GetValue = Node.getAttribute("value") Else GetValue = "" End If End Select Else ' Textarea GetValue = Node.Text End If End If Else ' It's a scalar that's a radio button, or *scalar* checkbox array Set Options = m_Doc.selectNodes("//input[@name='" & Name & "' and @checked='1']") If Options.Length > 0 Then GetValue = Options(0).Attributes.getNamedItem("value").Text End If End If If IsArray(GetValue) Then m_Log.Debug "Got value for " & Name & ". Result: ('" & Join(GetValue, "', '") & "')" Else m_Log.Debug "Got value for " & Name & ". Result: " & GetValue End If End Function ' Sets the value of a form element Public Sub SetValue(Name, Value) Dim Config, Node, Checkboxes, Child, OneVal, Radios, Options ' If the value isn't a string, stringify it If Not IsArray(Value) Then Value = CStr(Value) End If ' If the element isn't defined in the config, quit Set Config = m_Doc.selectSingleNode("/form/config/element[@name='" & Name & "']") If Not Config Is Nothing Then ' There are two types of form elements: arrays and scalars. If Config.getAttribute("type") = "array" Then ' An array means that there could be multiple values submitted ' for this element. Form elements that are arrays by nature ' are ' * CheckBox ' * SelectMultiple ' First array-ize the value If Not IsArray(Value) Then Value = Array(Value) End If ' Find out what kind of form element it is If Config.getAttribute("tag-name") = "input" Then ' It's a CheckBox array. Uncheck everything there's no data for, and ' check everything there is Set Checkboxes = m_Doc.selectNodes("//input[@name='" & Name & "' and @type='checkbox']") For Each Child In Checkboxes If InArray(Value, Child.getAttribute("value")) Then Child.SetAttribute ("checked"), 1 Else Child.RemoveAttribute ("checked") End If Next Else ' It's a that's not multiple ' Find the correct child node of the element with a value ' of whatever value it is, and set its "selected" attribute ' to "1". All others get their "selected" attribute removed. Set Options = Node.GetElementsByTagName("option") For Each Child In Options If Child.getAttribute("value") = Value Then Child.SetAttribute "selected", "1" Else Child.RemoveAttribute "selected" End If Next ElseIf Node.nodeName = "textarea" Then Node.Text = Value Else m_Log.Error "Node " & Name & " has nodeName of '" & Node.nodeName & "'" End If End If End If ' Not Node Is Nothing End If ' Element is a scalar End If End Sub ' Returns true if a value exists in an array Private Function InArray(Coll, Value) InArray = False Dim Item For Each Item In Coll If CStr(Item) = Value Then InArray = True Exit Function End If Next End Function ' Gets the data that the browser sent Private Function GetBrowserData(Method, Name) Dim Result(), i If LCase(Method) = "get" Then If Request.QueryString(Name).Count > 1 Then ReDim Result(Request.QueryString(Name).Count) For i = 1 To Request.QueryString(Name).Count Result(i) = Request.QueryString(Name)(i) Next GetBrowserData = Result Else GetBrowserData = Request.QueryString(Name) End If Else If Request.Form(Name).Count > 1 Then ReDim Result(Request.Form(Name).Count) For i = 1 To Request.Form(Name).Count Result(i) = Request.Form(Name)(i) Next GetBrowserData = Result Else GetBrowserData = Request.Form(Name) End If End If End Function ' Validates a required element Private Function ValidateRequired(ConfigNode) Dim Node, Child, Options, XPath ValidateRequired = False m_Log.Debug "Validating for " & ConfigNode.getAttribute("name") ' First, discover whether it's an array or a scalar. If a value is ' required, a scalar must have a value; an array must have a value for ' at least one of its elements. If ConfigNode.getAttribute("type") = "array" Then m_Log.Debug ConfigNode.getAttribute("name") & " is an array" If ConfigNode.getAttribute("element-id") <> "" Then ' It's a SelectMultiple. Requires that the element be identified by ID. XPath = "//select[@id='" & ConfigNode.getAttribute("element-id") & "']" Set Node = m_Doc.selectSingleNode(XPath) If Not Node Is Nothing Then If Node.selectNodes("option[@selected and @value != '']").length > 0 Then ValidateRequired = True End If Else m_Log.Error "Could not find node with XPath " & XPath End If Exit Function Else ' It's a CheckBox array. Get an array of elements and check ' that at least one has the "checked" attribute. Find elements ' by getting all elements ' where {name} comes from the "name" attr of the ' element. For Each Node In m_Doc.selectNodes("//input[@name='" & ConfigNode.getAttribute("name") & "' and @type='checkbox']") If Node.getAttribute("checked") <> "" Then ValidateRequired = True Exit Function End If Next Exit Function End If Else ' type = "array" m_Log.Debug ConfigNode.getAttribute("name") & " is a scalar" ' The type is scalar (this is the default). There are 3 kinds of ' scalar elements: ,