(c) 2002 Visual Studio Magazine
Fawcette Technical Publications

Issue: May 2002
Section: Create Robust Components With XML
Author: Gerardo Villeda

VB6	Load Schemas Dynamically
Listing 1	Your components should load the schemas they require dynamically to provide the most flexibility possible. This code loads a configuration XML file (settings.xml). The file contains a list of schemas, including their namespace and physical location. The code loads the schema files into an XMLSchemaCache40 object and assigns the list to a DOMDocument40's schemas property to provide the required validation.

Dim oDom As DOMDocument40
Dim oElm As IXMLDOMElement
Dim oNL As IXMLDOMNodeList
Dim oSchemas As XMLSchemaCache40

Set oDom = New DOMDocument40
Set oSchemas = New XMLSchemaCache40

oDom.async = False
oDom.Load "settings.xml"
Set oNL = oDom.selectNodes("//Schemas")
For Each oElm In oNL
	oSchemas.Add _
		oElm.selectSingleNode("uri").Text, _
		oElm.selectSingleNode("file").Text
Next

'This works even if there are no schemas
Set oDom.schemas = oSchemas

VB6, MSXML 4	Use This Template to Get Started
Listing 2	This template is a starting point for you to use. Use this with your components to provide automatic support for XML schema validation.

Public Function BCPerson(ByVal strIn As String) _
	As String

	Dim strSettings As String
	Dim strF As String

	Dim oSchemas As XMLSchemaCache40
	Dim oSchema As IXMLDOMElement
	Dim oSList As IXMLDOMNodeList

	Dim oSettings As DOMDocument40
	Dim oInp As DOMDocument40
	Dim oOut As DOMDocument40
	Dim oNode As IXMLDOMElement

	Set oSettings = New DOMDocument40
	Set oOut = New DOMDocument40
	Set oInp = New DOMDocument40
	oSettings.async = False
	oOut.async = False
	oInp.async = False

	'Load an empty envelope used for the response.
	oOut.Load App.Path & "\Envelope.xml"

	'Load schema information if available
	strSettings = App.Path & "\" & App.EXEName & _
		".xml"
	If oSettings.Load(strSettings) Then
		Set oSList = oSettings.selectNodes( _
			"//Schemas/*")
		If oSList.length > 0 Then
			Set oSchemas = New XMLSchemaCache
			For Each oSchema In oSList
				'Set Relative path accordingly
				strF = Trim( _
					oSchema.getAttribute("file"))
				If InStr(strF, ".\") = 1 Then
					strF = Replace(strF, ".\", _
						App.Path & "\")
				End If
				oSchemas.Add _
					oSchema.getAttribute("uri"), strF
				Next
			Set oInp.schemas = oSchemas
		End If
	End If

	'Load request string into dom object
	If oInp.loadXML(strIn) Then
		'Your business execution goes here...
	Else
		Set oNode = _
			oOut.selectSingleNode("Envelope/Output")
		oNode.appendChild parseErrorElement(oInp)
	End If

	BCPerson = oOut.xml

	Set oInp = Nothing
	Set oSettings = Nothing
	Set oSchemas = Nothing
	Set oSchema = Nothing
	Set oSList = Nothing
	Set oOut = Nothing
End Function

Private Function parseErrorElement(oDom As _
	DOMDocument40) As IXMLDOMElement
	Dim oEle As IXMLDOMElement
	Set oEle = oDom.createElement("ParseError")
	With oDom.parseError
		oEle.setAttribute "errorCode", .errorCode
		oEle.setAttribute "filepost", .filepos
		oEle.setAttribute "line", .Line
		oEle.setAttribute "linepos", .linepos
		oEle.setAttribute "url", .url
		oEle.Text = Trim$(.reason) & _
			"[" & Trim$(.srcText) & "]"
	End With
	Set parseErrorElement = oEle
	Set oEle = Nothing
End Function

Sample XSD Schema

<schema
xmlns="http://www.w3.org/2001/XMLSchema" 
xmlns:gv="urn:gvilleda.vsm"
targetNamespace="urn:gvilleda.vsm" 
elementFormDefault="unqualified" 
attributeFormDefault="unqualified">
	<element name="Person">
		<complexType>
		<sequence>
			<element name="FirstName">
				<simpleType>
				<restriction base="string">
					<maxLength value="15"/>
				</restriction>
		</simpleType>
			</element>
			<element name="LastName">
				<simpleType>
				<restriction base="string">
					<maxLength value="25"/>
				</restriction>
				</simpleType>
			</element>
			<element name="MI"
				minOccurs="0" 
				maxOccurs="1">
				<simpleType>
				<restriction base="string">
				<length value="1"
					fixed="true"/>
				</restriction>
				</simpleType>
			</element>
			<element name="EMail"
				minOccurs="0"
				maxOccurs="unbounded">
				<simpleType>
				<restriction base="string">
				<pattern 
value="[\p{L}_-]+(\.[\p{L}_-]+)*@[\p{L}_]+(\.[\p{L}_]+)+"/>
				</restriction>
				</simpleType>
			</element>
		</sequence>
		<attribute name="Nationality"
			use="required">
			<simpleType>
			<restriction base="string">
			<enumeration value="USA"/>
			<enumeration value="CAN"/>
			<enumeration value="MEX"/>
			</restriction>
			</simpleType>
		</attribute>
	</complexType>
	</element>
</schema>

Sample XML File

<Envelope>
	<Input>
		<gv:Person xmlns:gv="urn:gvilleda.vsm"
			Nationality="MEX">
			<gv:FirstName>Gerardo</gv:FirstName>
			<gv:LastName>Villeda</gv:LastName>
			<gv:EMail>gvilleda@seic.com</gv:EMail>
			<gv:EMail>gerardovilleda@hotmail.com
				</gv:EMail>
		</gv:Person>
	</Input>
</Envelope>

Sample Settings File

<Settings>
	<Schemas>
		<Schema uri="urn:gvilleda.vsm" 
			file=".\gv_person.xsd"/>
	</Schemas>
</Settings>

Empty Return File

<Envelope>
	<Output>
	</Output>
</Envelope>
