// WSDLElements.cpp
//
//////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2000 - 2002 Robert Cunnings. All rights reserved.
//
// You may copy, modify, distribute or publish this code free of charge.
//
// NO WARRANTY: This software is provided AS IS, without warranty of any kind.
//
//////////////////////////////////////////////////////////////////////
//
// WSDLElements.h - a collection of event handlers used to process WSDL XML.
// These handlers are pushed onto the processing stack as required by the
// main parser event handler owned by the SOAP processor.
// They are derived from the abstract base class 'WMXMLEventHandler'.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "WSDLElements.h"
#include "WMSOAPWSDLClient.h"
#include "charencode.h"
#include "soap.h"

// WSDL namespace
static wchar_t *g_pwszWebServicesDescNS = L"http://schemas.xmlsoap.org/wsdl/";

inline bool WMWSDLEventHandler::IsXSDType(const wstring& wstrTypeNS)
{
	if (wstrTypeNS == g_pwszXMLSchemaNS2001 ||
		wstrTypeNS == g_pwszXMLSchemaNS1999 ||
		wstrTypeNS == g_pwszXMLSchemaNS2000)
	{
		return true;
	}
	return false;
}
inline bool WMWSDLEventHandler::IsSoapEncType(const wstring& wstrTypeNS)
{
	if (wstrTypeNS == g_pwszSoapEncodingNS || wstrTypeNS == g_pwszSoap12EncodingNS)
	{
		return true;
	}
	return false;
}

inline bool WMWSDLEventHandler::IsWSDLType(const wstring& wstrTypeNS)
{
	if (wstrTypeNS == g_pwszWebServicesDescNS)
	{
		return true;
	}
	return false;
}

inline bool WMWSDLEventHandler::GetXSDAttribute( const wstring& wstrElemAttrNames,
												 WMXMLAttributeMap& mapAttributes,
												 WMXMLAttributeMap::iterator& iter)
{
	wstring wstrKey = g_pwszXMLSchemaNS2001;
	wstrKey += wstrElemAttrNames;
	if ((iter = mapAttributes.find(wstrKey)) != mapAttributes.end())
	{
		return true;
	}
	else
	{
		wstrKey = g_pwszXMLSchemaNS1999;
		wstrKey += wstrElemAttrNames;
		if ((iter = mapAttributes.find(wstrKey)) != mapAttributes.end())
		{
			return true;
		}
		else
		{
			wstrKey = g_pwszXMLSchemaNS2000;
			wstrKey += wstrElemAttrNames;
			if ((iter = mapAttributes.find(wstrKey)) != mapAttributes.end())
			{
				return true;
			}
		}
	}
	return false;
}

void WMFaultHandler::ReadAttributes(WMXMLAttributeMap& mapAttributes, NSPrefixMap& mapNSPrefixes)
{
	// unqualified attribute name expected
	wstring wstrKey = g_pwszWebServicesDescNS;
	wstrKey += L"faultname";
	WMXMLAttributeMap::iterator iter;
	if ((iter = mapAttributes.find(wstrKey)) != mapAttributes.end())
	{
		// get the value
		WMXMLAttribute *pAttr = (*iter).second;
		m_wstrName = pAttr->GetValue();
	}
	else
	{
		// Required attribute missing
		throw new WMWebServicesDescFault(L"WSDL Schema Error",
				L"Required attribute 'name' missing on element: 'fault'");
	}
	// unqualified attribute name expected
	wstrKey = g_pwszWebServicesDescNS;
	wstrKey += L"faultmessage";
	if ((iter = mapAttributes.find(wstrKey)) != mapAttributes.end())
	{
		WMXMLAttribute *pAttr = (*iter).second;
		wstring wstrTemp = pAttr->GetValue();
		wstring::size_type pos = wstrTemp.find(':');
		if (pos != wstring::npos)
		{
			// get NS prefix
			NSPrefixMap::iterator iNS;
			if ((iNS = mapNSPrefixes.find(wstrTemp.substr(0, pos))) != mapNSPrefixes.end())
			{
				m_wstrMessageNS = (*iNS).second;
			}
			else
			{
				// unresolvable namespace prefix
				throw new WMWebServicesDescFault(L"WSDL Schema Error",
					L"Unresolvable namespace for attribute 'message' on element: 'fault'");
			}
			m_wstrMessage = wstrTemp.substr(++pos);
		}
		else
		{
			// default namespace
			NSPrefixMap::iterator iNS;
			if ((iNS = mapNSPrefixes.find(wstring(L""))) != mapNSPrefixes.end())
			{
				m_wstrMessageNS = (*iNS).second;
			}
			else
			{
				// unresolvable namespace prefix
				throw new WMWebServicesDescFault(L"WSDL Schema Error",
					L"Unresolvable namespace for attribute 'message' on element: 'fault'");
			}
			m_wstrMessage = wstrTemp;
		}
	}
	else
	{
		// Required attribute missing
		throw new WMWebServicesDescFault(L"WSDL Schema Error",
				L"Required attribute 'message' missing on element: 'fault'");
	}
}
WMWSDLEventHandler * WMSchemaElemHandler::StartElement(	const wstring& wstrURI,
														const wstring& wstrLocalName,
														const wstring& wstrQualifiedName,
														WMXMLAttributeMap& mapAttributes,
														NSPrefixMap& mapNSPrefixes,
														WMXMLElement *pElement)
{
	if (IsXSDType(wstrURI))
	{
		if (wstrLocalName == L"complexType")
		{
			WMSchemaComplexTypeHandler *pElement = new WMSchemaComplexTypeHandler();
			if (pElement == NULL)
			{
				throw new WMWebServicesDescFault(L"Internal Error",
						L"Memory allocation failure.");
			}
			// store it
			m_pComplexType = pElement;
			pElement->SetTNS(m_wstrTNS);
			pElement->SetNamespace(m_wstrTNS);
			pElement->SetSchema(m_pSchema);
			pElement->SetElemFormDefault(m_bElemFormDefQualified);
			pElement->ReadAttributes(mapAttributes, mapNSPrefixes);
			return pElement;
		}
		else if (wstrLocalName == L"simpleType")
		{
			WMSchemaSimpleTypeHandler *pElement = new WMSchemaSimpleTypeHandler();
			if (pElement == NULL)
			{
				throw new WMWebServicesDescFault(L"Internal Error",
						L"Memory allocation failure.");
			}
			// store it
			m_pSimpleType = pElement;
			pElement->SetTNS(m_wstrTNS);
			pElement->SetNamespace(m_wstrTNS);
			pElement->SetSchema(m_pSchema);
			pElement->SetElemFormDefault(m_bElemFormDefQualified);
			pElement->ReadAttributes(mapAttributes, mapNSPrefixes);
			return pElement;
		}
	}
	return IGNORE_ELEMENT_HANDLER;
}

bool WMSchemaElemHandler::EndElement(	const wstring& wstrURI,
										const wstring& wstrLocalName,
										const wstring& wstrQualifiedName,
										WMXMLElement *pElement)
{
	// elementFormDefault == "qualified" and form not specified locally?
	if (m_bElemFormDefQualified == true && m_wstrElemForm != L"unqualified")
	{
        m_wstrNS = m_wstrTNS;
	}
	// if an anonymous complex type was defined, add to schema
	if (IsAnonComplexType() == true)
	{
		// we will give it a GUID as a name for future reference
		GUID g;
		CoCreateGuid(&g);
		OLECHAR wszBuffer[64];
		StringFromGUID2(g, wszBuffer, 64);
		wszBuffer[37] = 0;
		// insert into complex type map
		m_pSchema->GetComplexTypeMap().insert(map<wstring,
					WMSchemaComplexTypeHandler *>::value_type(wstring(&wszBuffer[1]),
					DetachComplexType()));
		// now we make it our type
		m_wstrType = &wszBuffer[1];
		m_wstrTypeNS = m_pSchema->GetTNS();
	}
	if (IsAnonSimpleType() == true)
	{
		// we will give it a GUID as a name for future reference
		GUID g;
		CoCreateGuid(&g);
		OLECHAR wszBuffer[64];
		StringFromGUID2(g, wszBuffer, 64);
		wszBuffer[37] = 0;
		// insert into simple type map
		m_pSchema->GetSimpleTypeMap().insert(map<wstring,
					WMSchemaSimpleTypeHandler *>::value_type(wstring(&wszBuffer[1]),
					DetachSimpleType()));
		// now we make it our type
		m_wstrType = &wszBuffer[1];
		m_wstrTypeNS = m_pSchema->GetTNS();
	}
	return true;
}

void WMSchemaElemHandler::ReadAttributes(WMXMLAttributeMap& mapAttributes, NSPrefixMap& mapNSPrefixes)
{
	// unqualified attribute name expected
	wstring wstrElemAttr = L"elementname";
	WMXMLAttributeMap::iterator iter;
	if (GetXSDAttribute(wstrElemAttr, mapAttributes, iter) == true)
	{
		// get the value
		WMXMLAttribute *pAttr = (*iter).second;
		m_wstrName = pAttr->GetValue();

		wstrElemAttr = L"elementtype";
		if (GetXSDAttribute(wstrElemAttr, mapAttributes, iter) == true)
		{
			// get the type
			pAttr = (*iter).second;
			// resolve type
			wstring wstrTemp = pAttr->GetValue();
			wstring::size_type pos = wstrTemp.find(':');
			if (pos != wstring::npos)
			{
				// get NS prefix
				NSPrefixMap::iterator iNS;
				if ((iNS = mapNSPrefixes.find(wstrTemp.substr(0, pos))) != mapNSPrefixes.end())
				{
					m_wstrTypeNS = (*iNS).second;
				}
				else
				{
					// unresolvable namespace prefix
					throw new WMWebServicesDescFault(L"WSDL Schema Error",
						L"Unresolvable namespace for attribute 'type' on element: 'element'");
				}
				m_wstrType = wstrTemp.substr(++pos);
			}
			else
			{
				// default namespace
				NSPrefixMap::iterator iNS;
				if ((iNS = mapNSPrefixes.find(wstring(L""))) != mapNSPrefixes.end())
				{
					m_wstrTypeNS = (*iNS).second;
				}
				else
				{
					// unresolvable namespace prefix
					throw new WMWebServicesDescFault(L"WSDL Schema Error",
						L"Unresolvable namespace for attribute 'type' on element: 'element'");
				}
				m_wstrType = wstrTemp;
			}
		}
	}
	else
	{
		// no name... is this a ref?
		wstrElemAttr = L"elementref";
		if (GetXSDAttribute(wstrElemAttr, mapAttributes, iter) == true)
		{
			// get the value
			WMXMLAttribute *pAttr = (*iter).second;
			wstring wstrTemp = pAttr->GetValue();
			wstring::size_type pos = wstrTemp.find(':');
			if (pos != wstring::npos)
			{
				// get NS prefix
				NSPrefixMap::iterator iNS;
				if ((iNS = mapNSPrefixes.find(wstrTemp.substr(0, pos))) != mapNSPrefixes.end())
				{
					m_wstrNS = (*iNS).second;
				}
				else
				{
					// unresolvable namespace prefix
					throw new WMWebServicesDescFault(L"WSDL Schema Error",
						L"Unresolvable namespace for attribute 'ref' on element: 'element'");
				}
				m_wstrName = wstrTemp.substr(++pos);
			}
			else
			{
				// default namespace
				NSPrefixMap::iterator iNS;
				if ((iNS = mapNSPrefixes.find(wstring(L""))) != mapNSPrefixes.end())
				{
					m_wstrNS = (*iNS).second;
				}
				else
				{
					// unresolvable namespace prefix
					throw new WMWebServicesDescFault(L"WSDL Schema Error",
						L"Unresolvable namespace for attribute 'ref' on element: 'element'");
				}
				m_wstrName = wstrTemp;
			}
		}
		else
		{
			// no type, no reference, default to 'anyType'
			m_wstrType = L"anyType";
			m_wstrTypeNS = g_pwszXMLSchemaNS2001;
			return;
		}
		m_bIsRef = true;
	}
    // minOccurs?
	wstrElemAttr = L"elementminOccurs";
	if (GetXSDAttribute(wstrElemAttr, mapAttributes, iter) == true)
	{
		// get the value
		WMXMLAttribute *pAttr = (*iter).second;
		m_wstrMinOccurs = pAttr->GetValue();
    }
    // maxOccurs?
	wstrElemAttr = L"elementmaxOccurs";
	if (GetXSDAttribute(wstrElemAttr, mapAttributes, iter) == true)
	{
		// get the value
		WMXMLAttribute *pAttr = (*iter).second;
		m_wstrMaxOccurs = pAttr->GetValue();
    }
    // form?
	wstrElemAttr = L"elementform";
	if (GetXSDAttribute(wstrElemAttr, mapAttributes, iter) == true)
	{
		// get the value
		WMXMLAttribute *pAttr = (*iter).second;
        m_wstrElemForm = pAttr->GetValue();
		if (m_wstrElemForm == L"qualified")
        {
            m_wstrNS = m_wstrTNS;
        }
        else if (m_wstrElemForm != L"unqualified")
        {
			throw new WMWebServicesDescFault(L"WSDL Schema Error",
				L"Illegal value for attribute 'form' on element: 'element'");
        }
    }
}

WMWSDLEventHandler *WMSequenceHandler::StartElement(const wstring& wstrURI,
													const wstring& wstrLocalName,
													const wstring& wstrQualifiedName,
													WMXMLAttributeMap& mapAttributes,
													NSPrefixMap& mapNSPrefixes,
													WMXMLElement *pElement)
{
	if (IsXSDType(wstrURI))
	{
		if (wstrLocalName == L"element")
		{
			WMSchemaElemHandler *pElement = new WMSchemaElemHandler();
			if (pElement == NULL)
			{
				throw new WMWebServicesDescFault(L"Internal Error",
						L"Memory allocation failure.");
			}
			// append to list
			m_listSchemaElems.push_back(pElement);
			pElement->SetTNS(m_wstrTNS);
			pElement->SetSchema(m_pSchema);
			pElement->SetElemFormDefault(m_bElemFormDefQualified);
			pElement->ReadAttributes(mapAttributes, mapNSPrefixes);
			return pElement;
		}
	}
	return IGNORE_ELEMENT_HANDLER;
}

void WMAttributeHandler::ReadAttributes(WMXMLAttributeMap& mapAttributes, NSPrefixMap& mapNSPrefixes)
{
	// unqualified attribute name expected
	wstring wstrElemAttr = L"attributename";
	WMXMLAttributeMap::iterator iter;
	if (GetXSDAttribute(wstrElemAttr, mapAttributes, iter) == true)
	{
		WMXMLAttribute *pAttr = (*iter).second;
		m_wstrName = pAttr->GetValue();
		wstrElemAttr = L"attributetype";
		if (GetXSDAttribute(wstrElemAttr, mapAttributes, iter) == true)
		{
			// get the type
			pAttr = (*iter).second;
			// resolve type
			wstring wstrTemp = pAttr->GetValue();
			wstring::size_type pos = wstrTemp.find(':');
			if (pos != wstring::npos)
			{
				// get NS prefix
				NSPrefixMap::iterator iNS;
				if ((iNS = mapNSPrefixes.find(wstrTemp.substr(0, pos))) != mapNSPrefixes.end())
				{
					m_wstrTypeNS = (*iNS).second;
				}
				else
				{
					// unresolvable namespace prefix
					throw new WMWebServicesDescFault(L"WSDL Schema Error",
						L"Unresolvable namespace for attribute 'type' on element: 'attribute'");
				}
				m_wstrType = wstrTemp.substr(++pos);
			}
			else
			{
				// default namespace
				NSPrefixMap::iterator iNS;
				if ((iNS = mapNSPrefixes.find(wstring(L""))) != mapNSPrefixes.end())
				{
					m_wstrTypeNS = (*iNS).second;
				}
				else
				{
					// unresolvable namespace prefix
					throw new WMWebServicesDescFault(L"WSDL Schema Error",
						L"Unresolvable namespace for attribute 'type' on element: 'attribute'");
				}
				m_wstrType = wstrTemp;
			}
		}
	}
	else
	{
		// ref attribute?
		wstrElemAttr = L"attributeref";
		if (GetXSDAttribute(wstrElemAttr, mapAttributes, iter) == true)
		{
			WMXMLAttribute *pAttr = (*iter).second;
			wstring wstrTemp = pAttr->GetValue();
			// split qname
			wstring::size_type pos = wstrTemp.find(':');
			if (pos != wstring::npos)
			{
				// get NS prefix
				NSPrefixMap::iterator iNS;
				if ((iNS = mapNSPrefixes.find(wstrTemp.substr(0, pos))) != mapNSPrefixes.end())
				{
					m_wstrRefNS = (*iNS).second;
				}
				else
				{
					// unresolvable namespace prefix
					throw new WMWebServicesDescFault(L"WSDL Schema Error",
						L"Unresolvable namespace for attribute 'ref' on element: 'attribute'");
				}
				m_wstrRef = wstrTemp.substr(++pos);
			}
			else
			{
				// default namespace
				NSPrefixMap::iterator iNS;
				if ((iNS = mapNSPrefixes.find(wstring(L""))) != mapNSPrefixes.end())
				{
					m_wstrRefNS = (*iNS).second;
				}
				else
				{
					// unresolvable namespace prefix
					throw new WMWebServicesDescFault(L"WSDL Schema Error",
						L"Unresolvable namespace for attribute 'ref' on element: 'attribute'");
				}
				m_wstrRef = wstrTemp;
			}
		}
		else
		{
			// no type, no reference, default to 'anyType'
			m_wstrType = L"anyType";
			m_wstrTypeNS = g_pwszXMLSchemaNS2001;
			return;
		}
		m_bIsRef = true;
	}
}

bool WMArrayTypeAttrHandler::GetArrayType(wstring& wstrType, wstring& wstrTypeNS)
{
	wstrType = m_wstrArrayType;
	wstrTypeNS = m_wstrArrayTypeNS;
	return true;
}

unsigned int WMArrayTypeAttrHandler::GetArrayDims()
{
	unsigned int nDims = 1;
	const wchar_t *p = m_wstrArraySize.c_str();
	// count commas to determine nbr of dimensions
	while (*p)
	{
		if (*p++ == wchar_t(','))
		{
			nDims++;
		}
	}
	return nDims;
}

void WMArrayTypeAttrHandler::ReadAttributes(WMXMLAttributeMap& mapAttributes, NSPrefixMap& mapNSPrefixes)
{
	WMAttributeHandler::ReadAttributes(mapAttributes, mapNSPrefixes);
	// qualified attribute name expected
	wstring wstrKey = g_pwszWebServicesDescNS;
	wstrKey += L"arrayType";
	WMXMLAttributeMap::iterator iter;
	if ((iter = mapAttributes.find(wstrKey)) != mapAttributes.end())
	{
		WMXMLAttribute *pAttr = (*iter).second;
		// insert into map
		wstring wstrTemp = pAttr->GetValue();
		wstring::size_type pos = wstrTemp.find(':');
		if (pos != wstring::npos)
		{
			// get NS prefix
			NSPrefixMap::iterator iNS;
			if ((iNS = mapNSPrefixes.find(wstrTemp.substr(0, pos))) != mapNSPrefixes.end())
			{
				m_wstrArrayTypeNS = (*iNS).second;
			}
			else
			{
				// unresolvable namespace prefix
				throw new WMWebServicesDescFault(L"WSDL Schema Error",
					L"Unresolvable namespace for attribute 'arrayType' on element: 'attribute'");
			}
			m_wstrArrayType = wstrTemp.substr(++pos);
		}
		else
		{
			// default namespace
			NSPrefixMap::iterator iNS;
			if ((iNS = mapNSPrefixes.find(wstring(L""))) != mapNSPrefixes.end())
			{
				m_wstrArrayTypeNS = (*iNS).second;
			}
			else
			{
				// unresolvable namespace prefix
				throw new WMWebServicesDescFault(L"WSDL Schema Error",
					L"Unresolvable namespace for attribute 'arrayType' on element: 'attribute'");
			}
			m_wstrArrayType = wstrTemp;
		}
		// split type and asize components
		pos = m_wstrArrayType.rfind('[');
		if (pos != wstring::npos)
		{
			m_wstrArraySize = m_wstrArrayType.substr(pos);
			m_wstrArrayType = m_wstrArrayType.substr(0, pos);
		}
	}
}

bool WMRestrictionHandler::GetArrayType( wstring& wstrType,
										 wstring& wstrTypeNS,
                                         bool& bIsRef)
{
	if (m_bArrayTypeHandlerFound == false)
	{
        if (m_Sequence.GetSchemaElemList().size() == 1)
        {
		    list<WMSchemaElemHandler *>::iterator iter;
		    iter = m_Sequence.GetSchemaElemList().begin();
		    WMSchemaElemHandler *pElement = *iter;
            if (pElement->GetMinOccurs() == L"0" && 
                (pElement->GetMaxOccurs() == L"unbounded" ||
                pElement->GetMaxOccurs() == L"*"))
            {
		        if (pElement->IsRef() == false)
		        {
			        pElement->GetType(wstrType, wstrTypeNS);
			        bIsRef = false;
		        }
		        else
		        {
			        pElement->GetNames(wstrType, wstrTypeNS);
			        bIsRef = true;
		        }
		        return true;
            }
        }
	}
	return m_ArrayTypeHandler.GetArrayType(wstrType, wstrTypeNS);
}

bool WMRestrictionHandler::GetArrayTypeLit( wstring& wstrType,
										    wstring& wstrTypeNS,
                                            wstring& wstrElemName,
                                            wstring& wstrElemNS,
                                            bool& bIsRef)
{
    if (m_Sequence.GetSchemaElemList().size() == 1)
    {
	    list<WMSchemaElemHandler *>::iterator iter;
	    iter = m_Sequence.GetSchemaElemList().begin();
		WMSchemaElemHandler *pElement = *iter;
        if (pElement->GetMinOccurs() == L"0" && 
            (pElement->GetMaxOccurs() == L"unbounded" ||
            pElement->GetMaxOccurs() == L"*"))
        {
		    if (pElement->IsRef() == false)
		    {
			    pElement->GetType(wstrType, wstrTypeNS);
			    bIsRef = false;
		    }
		    else
		    {
			    bIsRef = true;
		    }
		    pElement->GetNames(wstrElemName, wstrElemNS);
		    return true;
        }
    }
	return false;
}

unsigned int WMRestrictionHandler::GetArrayDims()
{
	if (m_bArrayTypeHandlerFound == false)
	{
        return 1;
    }
	return m_ArrayTypeHandler.GetArrayDims();
}

WMWSDLEventHandler *WMRestrictionHandler::StartElement( const wstring& wstrURI,
														const wstring& wstrLocalName,
														const wstring& wstrQualifiedName,
														WMXMLAttributeMap& mapAttributes,
														NSPrefixMap& mapNSPrefixes,
														WMXMLElement *pElement)
{
	if (IsXSDType(wstrURI))
	{
		if (wstrLocalName == L"attribute")
		{
			// unqualified attribute name expected
			wstring wstrElemAttr = L"attributeref";
			WMXMLAttributeMap::iterator iter;
			if (GetXSDAttribute(wstrElemAttr, mapAttributes, iter) == true)
			{
				// get ref and try to resolve value (qname)
				WMXMLAttribute *pAttr = (*iter).second;
				// is it the arrayType attribute?
				wstring wstrBaseType;
				wstring wstrBaseTypeNS;
				wstring wstrTemp = pAttr->GetValue();
				wstring::size_type pos = wstrTemp.find(':');
				if (pos != wstring::npos)
				{
					// get NS prefix
					NSPrefixMap::iterator iNS;
					if ((iNS = mapNSPrefixes.find(wstrTemp.substr(0, pos))) != mapNSPrefixes.end())
					{
						wstrBaseTypeNS = (*iNS).second;
					}
					else
					{
						// unresolvable namespace prefix
						throw new WMWebServicesDescFault(L"WSDL Schema Error",
							L"Unresolvable namespace for attribute 'ref' on element: 'attribute'");
					}
					wstrBaseType = wstrTemp.substr(++pos);
				}
				else
				{
					// default namespace
					NSPrefixMap::iterator iNS;
					if ((iNS = mapNSPrefixes.find(wstring(L""))) != mapNSPrefixes.end())
					{
						wstrBaseTypeNS = (*iNS).second;
					}
					else
					{
						// unresolvable namespace prefix
						throw new WMWebServicesDescFault(L"WSDL Schema Error",
							L"Unresolvable namespace for attribute 'ref' on element: 'attribute'");
					}
					wstrBaseType = wstrTemp;
				}
				if (wstrBaseType == L"arrayType" &&	IsSoapEncType(wstrBaseTypeNS))
				{
					// this is it
                    m_bArrayTypeHandlerFound = true;
					m_ArrayTypeHandler.SetSchema(m_pSchema);
					m_ArrayTypeHandler.ReadAttributes(mapAttributes, mapNSPrefixes);
					return &m_ArrayTypeHandler;
				}
				else
				{
					// not the SOAP-ENC:arrayType ref
					WMAttributeHandler *pAttribute = new WMAttributeHandler();
					if (pAttribute == NULL)
					{
						throw new WMWebServicesDescFault(L"Internal Error",
								L"Memory allocation failure.");
					}
					// append to list
					m_listAttributes.push_back(pAttribute);
					pAttribute->SetSchema(m_pSchema);
					pAttribute->ReadAttributes(mapAttributes, mapNSPrefixes);
					return pAttribute;
				}
			}
			else
			{
				// no 'ref' attribute found
				WMAttributeHandler *pAttribute = new WMAttributeHandler();
				if (pAttribute == NULL)
				{
					throw new WMWebServicesDescFault(L"Internal Error",
							L"Memory allocation failure.");
				}
				// append to list
				m_listAttributes.push_back(pAttribute);
				pAttribute->SetSchema(m_pSchema);
				pAttribute->ReadAttributes(mapAttributes, mapNSPrefixes);
				return pAttribute;
			}
		}
		else if (wstrLocalName == L"sequence" || wstrLocalName == L"all")
		{
			m_Sequence.SetTNS(m_wstrTNS);
			m_Sequence.SetSchema(m_pSchema);
			m_Sequence.SetElemFormDefault(m_bElemFormDefQualified);
			return &m_Sequence;
		}
	}
	return IGNORE_ELEMENT_HANDLER;
}

WMWSDLEventHandler *WMExtensionHandler::StartElement(	const wstring& wstrURI,
														const wstring& wstrLocalName,
														const wstring& wstrQualifiedName,
														WMXMLAttributeMap& mapAttributes,
														NSPrefixMap& mapNSPrefixes,
														WMXMLElement *pElement)
{
	if (IsXSDType(wstrURI))
	{
		if (wstrLocalName == L"attribute")
		{
			WMAttributeHandler *pAttribute = new WMAttributeHandler();
			if (pAttribute == NULL)
			{
				throw new WMWebServicesDescFault(L"Internal Error",
						L"Memory allocation failure.");
			}
			// append to list
			m_listAttributes.push_back(pAttribute);
			pAttribute->SetSchema(m_pSchema);
			pAttribute->ReadAttributes(mapAttributes, mapNSPrefixes);
			return pAttribute;
		}
		else if (wstrLocalName == L"sequence" || wstrLocalName == L"all")
		{
			m_Sequence.SetTNS(m_wstrTNS);
			m_Sequence.SetSchema(m_pSchema);
			m_Sequence.SetElemFormDefault(m_bElemFormDefQualified);
			return &m_Sequence;
		}
	}
	return IGNORE_ELEMENT_HANDLER;
}

void WMRestrictionHandler::ReadAttributes(WMXMLAttributeMap& mapAttributes, NSPrefixMap& mapNSPrefixes)
{
	// unqualified attribute name expected
	wstring wstrElemAttr = L"restrictionbase";
	WMXMLAttributeMap::iterator iter;
	if (GetXSDAttribute(wstrElemAttr, mapAttributes, iter) == true)
	{
		WMXMLAttribute *pAttr = (*iter).second;
		// insert into map
		wstring wstrTemp = pAttr->GetValue();
		wstring::size_type pos = wstrTemp.find(':');
		if (pos != wstring::npos)
		{
			// get NS prefix
			NSPrefixMap::iterator iNS;
			if ((iNS = mapNSPrefixes.find(wstrTemp.substr(0, pos))) != mapNSPrefixes.end())
			{
				m_wstrBaseTypeNS = (*iNS).second;
			}
			else
			{
				// unresolvable namespace prefix
				throw new WMWebServicesDescFault(L"WSDL Schema Error",
					L"Unresolvable namespace for attribute 'base' on element: 'restriction'");
			}
			m_wstrBaseType = wstrTemp.substr(++pos);
		}
		else
		{
			// default namespace
			NSPrefixMap::iterator iNS;
			if ((iNS = mapNSPrefixes.find(wstring(L""))) != mapNSPrefixes.end())
			{
				m_wstrBaseTypeNS = (*iNS).second;
			}
			else
			{
				// unresolvable namespace prefix
				throw new WMWebServicesDescFault(L"WSDL Schema Error",
					L"Unresolvable namespace for attribute 'base' on element: 'restriction'");
			}
			m_wstrBaseType = wstrTemp;
		}
	}
}

void WMExtensionHandler::ReadAttributes(WMXMLAttributeMap& mapAttributes, NSPrefixMap& mapNSPrefixes)
{
	// unqualified attribute name expected
	wstring wstrElemAttr = L"extensionbase";
	WMXMLAttributeMap::iterator iter;
	if (GetXSDAttribute(wstrElemAttr, mapAttributes, iter) == true)
	{
		WMXMLAttribute *pAttr = (*iter).second;
		// insert into map
		wstring wstrTemp = pAttr->GetValue();
		wstring::size_type pos = wstrTemp.find(':');
		if (pos != wstring::npos)
		{
			// get NS prefix
			NSPrefixMap::iterator iNS;
			if ((iNS = mapNSPrefixes.find(wstrTemp.substr(0, pos))) != mapNSPrefixes.end())
			{
				m_wstrBaseTypeNS = (*iNS).second;
			}
			else
			{
				// unresolvable namespace prefix
				throw new WMWebServicesDescFault(L"WSDL Schema Error",
					L"Unresolvable namespace for attribute 'base' on element: 'extension'");
			}
			m_wstrBaseType = wstrTemp.substr(++pos);
		}
		else
		{
			// default namespace
			NSPrefixMap::iterator iNS;
			if ((iNS = mapNSPrefixes.find(wstring(L""))) != mapNSPrefixes.end())
			{
				m_wstrBaseTypeNS = (*iNS).second;
			}
			else
			{
				// unresolvable namespace prefix
				throw new WMWebServicesDescFault(L"WSDL Schema Error",
					L"Unresolvable namespace for attribute 'base' on element: 'extension'");
			}
			m_wstrBaseType = wstrTemp;
		}
	}
}

void WMSimpleContentHandler::GetBaseTypeNames(wstring& wstrType, wstring& wstrTypeNS)
{
	if (m_bIsRestriction == true)
	{
		m_Restriction.GetBaseTypeNames(wstrType, wstrTypeNS);
		return;
	}
	else if (m_bIsExtension == true)
	{
		m_Extension.GetBaseTypeNames(wstrType, wstrTypeNS);
		return;
	}
}

void WMComplexContentHandler::GetBaseTypeNames(wstring& wstrType, wstring& wstrTypeNS)
{
	if (m_bIsRestriction == true)
	{
		m_Restriction.GetBaseTypeNames(wstrType, wstrTypeNS);
		return;
	}
	else if (m_bIsExtension == true)
	{
		m_Extension.GetBaseTypeNames(wstrType, wstrTypeNS);
		return;
	}
}

WMWSDLEventHandler *WMSimpleContentHandler::StartElement(	const wstring& wstrURI,
															const wstring& wstrLocalName,
															const wstring& wstrQualifiedName,
															WMXMLAttributeMap& mapAttributes,
															NSPrefixMap& mapNSPrefixes,
															WMXMLElement *pElement)
{
	if (IsXSDType(wstrURI))
	{
		if (wstrLocalName == L"restriction")
		{
			m_Restriction.SetTNS(m_wstrTNS);
			m_Restriction.SetSchema(m_pSchema);
			m_Restriction.SetElemFormDefault(m_bElemFormDefQualified);
			m_Restriction.ReadAttributes(mapAttributes, mapNSPrefixes);
			m_bIsRestriction = true;
			return &m_Restriction;
		}
		if (wstrLocalName == L"extension")
		{
			m_Extension.SetTNS(m_wstrTNS);
			m_Extension.SetSchema(m_pSchema);
			m_Extension.SetElemFormDefault(m_bElemFormDefQualified);
			m_Extension.ReadAttributes(mapAttributes, mapNSPrefixes);
			m_bIsExtension = true;
			return &m_Extension;
		}
	}
	return IGNORE_ELEMENT_HANDLER;
}

WMWSDLEventHandler *WMComplexContentHandler::StartElement(  const wstring& wstrURI,
															const wstring& wstrLocalName,
															const wstring& wstrQualifiedName,
															WMXMLAttributeMap& mapAttributes,
															NSPrefixMap& mapNSPrefixes,
															WMXMLElement *pElement)
{
	if (IsXSDType(wstrURI))
	{
		if (wstrLocalName == L"restriction")
		{
			m_Restriction.SetTNS(m_wstrTNS);
			m_Restriction.SetSchema(m_pSchema);
			m_Restriction.SetElemFormDefault(m_bElemFormDefQualified);
			m_Restriction.ReadAttributes(mapAttributes, mapNSPrefixes);
			m_bIsRestriction = true;
			return &m_Restriction;
		}
		if (wstrLocalName == L"extension")
		{
			m_Extension.SetTNS(m_wstrTNS);
			m_Extension.SetSchema(m_pSchema);
			m_Extension.SetElemFormDefault(m_bElemFormDefQualified);
			m_Extension.ReadAttributes(mapAttributes, mapNSPrefixes);
			m_bIsExtension = true;
			return &m_Extension;
		}
	}
	return IGNORE_ELEMENT_HANDLER;
}

WMWSDLEventHandler *WMSchemaSimpleTypeHandler::StartElement(const wstring& wstrURI,
															const wstring& wstrLocalName,
															const wstring& wstrQualifiedName,
															WMXMLAttributeMap& mapAttributes,
															NSPrefixMap& mapNSPrefixes,
															WMXMLElement *pElement)
{
	if (IsXSDType(wstrURI))
	{
		if (wstrLocalName == L"restriction")
		{
			m_Restriction.SetTNS(m_wstrTNS);
			m_Restriction.SetSchema(m_pSchema);
			m_Restriction.SetElemFormDefault(m_bElemFormDefQualified);
			m_Restriction.ReadAttributes(mapAttributes, mapNSPrefixes);
			m_bIsRestriction = true;
			return &m_Restriction;
		}
	}
	return IGNORE_ELEMENT_HANDLER;
}

void WMSchemaComplexTypeHandler::GetBaseTypeNames(wstring& wstrType, wstring& wstrTypeNS)
{
	if (m_bIsComplexContent == true)
	{
		// delegate to complexContent handler
		m_ComplexContent.GetBaseTypeNames(wstrType, wstrTypeNS);
		return;
	}
	else if (m_bIsSimpleContent == true)
	{
		// delegate to simpleContent handler
		m_SimpleContent.GetBaseTypeNames(wstrType, wstrTypeNS);
	}
}

list<WMAttributeHandler *>& WMSchemaComplexTypeHandler::GetAttributeList()
{ 
	if (m_bIsComplexContent == true)
	{
		if (m_ComplexContent.IsExtension() == true)
		{
			return m_ComplexContent.GetExtension().GetAttributeList();
		}
		if (m_ComplexContent.IsRestriction() == true)
		{
			return m_ComplexContent.GetRestriction().GetAttributeList();
		}
	}
	else if (m_bIsSimpleContent == true)
	{
		if (m_SimpleContent.IsExtension() == true)
		{
			return m_SimpleContent.GetExtension().GetAttributeList();
		}
		if (m_SimpleContent.IsRestriction() == true)
		{
			return m_SimpleContent.GetRestriction().GetAttributeList();
		}
	}
	return m_listAttributes;
}

bool WMSchemaComplexTypeHandler::GetElementType( const wstring& wstrName,
												 const wstring& wstrNS,
												 wstring& wstrType,
												 wstring& wstrTypeNS,
												 bool& bIsRef)
{
	wstring wstrElemName, wstrElemNS;
	list<WMSchemaElemHandler *>::iterator iter;
	for (iter = m_Sequence.GetSchemaElemList().begin();
			iter != m_Sequence.GetSchemaElemList().end(); iter++)
	{
		WMSchemaElemHandler *pElement = *iter;
		pElement->GetNames(wstrElemName, wstrElemNS);
		if (wstrName == wstrElemName && wstrNS == wstrElemNS)
		{
			if (pElement->IsRef() == false)
			{
				pElement->GetType(wstrType, wstrTypeNS);
				bIsRef = false;
			}
			else
			{
				pElement->GetNames(wstrType, wstrTypeNS);
				bIsRef = true;
			}
			return true;
		}
	}
    // is it within a complexContent element?
    if (IsComplexContent() == true)
	for (iter = m_ComplexContent.GetExtension().GetSequence().GetSchemaElemList().begin();
			iter != m_ComplexContent.GetExtension().GetSequence().GetSchemaElemList().end(); iter++)
	{
		WMSchemaElemHandler *pElement = *iter;
		pElement->GetNames(wstrElemName, wstrElemNS);
		if (wstrName == wstrElemName && wstrNS == wstrElemNS)
		{
			if (pElement->IsRef() == false)
			{
				pElement->GetType(wstrType, wstrTypeNS);
				bIsRef = false;
			}
			else
			{
				pElement->GetNames(wstrType, wstrTypeNS);
				bIsRef = true;
			}
			return true;
		}
	}
	for (iter = m_ComplexContent.GetRestriction().GetSequence().GetSchemaElemList().begin();
			iter != m_ComplexContent.GetRestriction().GetSequence().GetSchemaElemList().end(); iter++)
	{
		WMSchemaElemHandler *pElement = *iter;
		pElement->GetNames(wstrElemName, wstrElemNS);
		if (wstrName == wstrElemName && wstrNS == wstrElemNS)
		{
			if (pElement->IsRef() == false)
			{
				pElement->GetType(wstrType, wstrTypeNS);
				bIsRef = false;
			}
			else
			{
				pElement->GetNames(wstrType, wstrTypeNS);
				bIsRef = true;
			}
			return true;
		}
	}
	return false;
}

bool WMSchemaComplexTypeHandler::GetArrayType(   wstring& wstrType,
												 wstring& wstrTypeNS,
												 bool& bIsRef)
{
    if (m_Sequence.GetSchemaElemList().size() == 1)
    {
	    list<WMSchemaElemHandler *>::iterator iter;
	    iter = m_Sequence.GetSchemaElemList().begin();
		WMSchemaElemHandler *pElement = *iter;
        if (pElement->GetMinOccurs() == L"0" && 
            (pElement->GetMaxOccurs() == L"unbounded" ||
            pElement->GetMaxOccurs() == L"*"))
		{
			if (pElement->IsRef() == false)
			{
				pElement->GetType(wstrType, wstrTypeNS);
				bIsRef = false;
			}
			else
			{
				pElement->GetNames(wstrType, wstrTypeNS);
				bIsRef = true;
			}
			return true;
		}
    }
	// delegate to complexContent handler
	return m_ComplexContent.GetRestriction().GetArrayType(wstrType, wstrTypeNS, bIsRef);
}

bool WMSchemaComplexTypeHandler::GetArrayTypeLit(wstring& wstrType,
												 wstring& wstrTypeNS,
                                                 wstring& wstrElemName,
                                                 wstring& wstrElemNS,
												 bool& bIsRef)
{
    if (m_Sequence.GetSchemaElemList().size() == 1)
    {
	    list<WMSchemaElemHandler *>::iterator iter;
	    iter = m_Sequence.GetSchemaElemList().begin();
		WMSchemaElemHandler *pElement = *iter;
        if (pElement->GetMinOccurs() == L"0" && 
            (pElement->GetMaxOccurs() == L"unbounded" ||
            pElement->GetMaxOccurs() == L"*"))
		{
			if (pElement->IsRef() == false)
			{
				pElement->GetType(wstrType, wstrTypeNS);
				bIsRef = false;
			}
			else
			{
				bIsRef = true;
			}
			pElement->GetNames(wstrElemName, wstrElemNS);
			return true;
		}
    }
	// delegate to complexContent handler
	return m_ComplexContent.GetRestriction().GetArrayTypeLit(   wstrType,
                                                                wstrTypeNS,
                                                                wstrElemName,
                                                                wstrElemNS,
                                                                bIsRef);
}

unsigned int WMSchemaComplexTypeHandler::GetArrayDims()
{
	if (m_bIsDerivation == false)
	{
		// only one dimensional arrays expressible w/o WSDL 1.1 syntax
		return 1;
	}
	// delegate to complexContent handler
	return m_ComplexContent.GetRestriction().GetArrayDims();
}

WMWSDLEventHandler *WMSchemaComplexTypeHandler::StartElement(const wstring& wstrURI,
															const wstring& wstrLocalName,
															const wstring& wstrQualifiedName,
															WMXMLAttributeMap& mapAttributes,
															NSPrefixMap& mapNSPrefixes,
															WMXMLElement *pElement)
{
	// only 'sequence' compositor supported
	// 'all' is treated as 'sequence'
	if (IsXSDType(wstrURI))
	{
		if (wstrLocalName == L"sequence" || wstrLocalName == L"all")
		{
			m_Sequence.SetTNS(m_wstrTNS);
			m_Sequence.SetSchema(m_pSchema);
			m_Sequence.SetElemFormDefault(m_bElemFormDefQualified);
			return &m_Sequence;
		}
		if (wstrLocalName == L"complexContent")
		{
			m_bIsDerivation = true;
			m_ComplexContent.SetTNS(m_wstrTNS);
			m_ComplexContent.SetSchema(m_pSchema);
			m_ComplexContent.SetElemFormDefault(m_bElemFormDefQualified);
			m_bIsComplexContent = true;
			return &m_ComplexContent;
		}
		if (wstrLocalName == L"simpleContent")
		{
			m_bIsDerivation = true;
			m_SimpleContent.SetTNS(m_wstrTNS);
			m_SimpleContent.SetSchema(m_pSchema);
			m_SimpleContent.SetElemFormDefault(m_bElemFormDefQualified);
			m_bIsSimpleContent = true;
			return &m_SimpleContent;
		}
		if (wstrLocalName == L"attribute")
		{
			WMAttributeHandler *pAttribute = new WMAttributeHandler();
			if (pAttribute == NULL)
			{
				throw new WMWebServicesDescFault(L"Internal Error",
						L"Memory allocation failure.");
			}
			// append to list
			m_listAttributes.push_back(pAttribute);
			pAttribute->SetSchema(m_pSchema);
			pAttribute->ReadAttributes(mapAttributes, mapNSPrefixes);
			return pAttribute;
		}
	}
	return IGNORE_ELEMENT_HANDLER;
}

WMWSDLEventHandler *WMSchemaHandler::StartElement(  const wstring& wstrURI,
													const wstring& wstrLocalName,
													const wstring& wstrQualifiedName,
													WMXMLAttributeMap& mapAttributes,
													NSPrefixMap& mapNSPrefixes,
													WMXMLElement *pElement)
{
	if (IsXSDType(wstrURI))
	{
		WMXMLAttributeMap::iterator iter;
		if (wstrLocalName == L"element")
		{
			// unqualified attribute name expected
			wstring wstrKey = wstrURI;
			wstrKey += wstrLocalName;
			wstrKey += L"name";
			if ((iter = mapAttributes.find(wstrKey)) != mapAttributes.end())
			{
				WMSchemaElemHandler *pElement = new WMSchemaElemHandler();
				if (pElement == NULL)
				{
					throw new WMWebServicesDescFault(L"Internal Error",
							L"Memory allocation failure.");
				}
				WMXMLAttribute *pAttr = (*iter).second;
				// insert into map
				m_mapSchemaElems.insert(map<wstring,
					WMSchemaElemHandler *>::value_type(pAttr->GetValue(), pElement));
				// global, name qualified by tns
				pElement->SetNamespace(m_wstrTNS);
				pElement->SetTNS(m_wstrTNS);
				pElement->SetSchema(this);
				pElement->SetElemFormDefault(m_bElemFormDefQualified);
				pElement->ReadAttributes(mapAttributes, mapNSPrefixes);
				return pElement;
			}
			else
			{
				// Required name attribute missing
				throw new WMWebServicesDescFault(L"WSDL Schema Error",
						L"Required attribute 'name' missing on element: 'element'.");
			}
		}
		else if (wstrLocalName == L"complexType")
		{
			// unqualified attribute name expected
			wstring wstrKey = wstrURI;
			wstrKey += wstrLocalName;
			wstrKey += L"name";
			if ((iter = mapAttributes.find(wstrKey)) != mapAttributes.end())
			{
				WMSchemaComplexTypeHandler *pElement = new WMSchemaComplexTypeHandler();
				if (pElement == NULL)
				{
					throw new WMWebServicesDescFault(L"Internal Error",
							L"Memory allocation failure.");
				}
				WMXMLAttribute *pAttr = (*iter).second;
				// insert into map
				m_mapSchemaComplexTypes.insert(map<wstring,
					WMSchemaComplexTypeHandler *>::value_type(pAttr->GetValue(), pElement));
				pElement->SetTNS(m_wstrTNS);
				pElement->SetNamespace(m_wstrTNS);
				pElement->SetSchema(this);
				pElement->SetElemFormDefault(m_bElemFormDefQualified);
				pElement->ReadAttributes(mapAttributes, mapNSPrefixes);
				return pElement;
			}
			else
			{
				// Required name attribute missing
				throw new WMWebServicesDescFault(L"WSDL Schema Error",
						L"Required attribute 'name' missing on element: 'complexType'.");
			}
		}
		else if (wstrLocalName == L"simpleType")
		{
			// unqualified attribute name expected
			wstring wstrKey = wstrURI;
			wstrKey += wstrLocalName;
			wstrKey += L"name";
			if ((iter = mapAttributes.find(wstrKey)) != mapAttributes.end())
			{
				WMSchemaSimpleTypeHandler *pElement = new WMSchemaSimpleTypeHandler();
				if (pElement == NULL)
				{
					throw new WMWebServicesDescFault(L"Internal Error",
							L"Memory allocation failure.");
				}
				WMXMLAttribute *pAttr = (*iter).second;
				// insert into map
				m_mapSchemaSimpleTypes.insert(map<wstring,
					WMSchemaSimpleTypeHandler *>::value_type(pAttr->GetValue(), pElement));
				pElement->SetTNS(m_wstrTNS);
				pElement->SetNamespace(m_wstrTNS);
				pElement->SetSchema(this);
				pElement->SetElemFormDefault(m_bElemFormDefQualified);
				pElement->ReadAttributes(mapAttributes, mapNSPrefixes);
				return pElement;
			}
			else
			{
				// Required name attribute missing
				throw new WMWebServicesDescFault(L"WSDL Schema Error",
						L"Required attribute 'name' missing on element: 'simpleType'.");
			}
		}
	}
	return IGNORE_ELEMENT_HANDLER;
}

WMSchemaElemHandler *WMSchemaHandler::GetSchemaElem(const wstring& wstrElemName,
													const wstring& wstrNamespace)
{
	map<wstring, WMSchemaElemHandler *>::iterator iM;
	if ((iM = m_mapSchemaElems.find(wstrElemName)) == m_mapSchemaElems.end())
	{
		return NULL;
	}
	WMSchemaElemHandler *pElement = (*iM).second;
	if (pElement->GetNamespace() != wstrNamespace)
	{
		return NULL;
	}
	return pElement;
}

WMSchemaSimpleTypeHandler *WMSchemaHandler::GetSimpleType(const wstring& wstrTypeName,
															const wstring& wstrTypeNS)
{
	map<wstring, WMSchemaSimpleTypeHandler *>::iterator iM;
	if ((iM = m_mapSchemaSimpleTypes.find(wstrTypeName)) == m_mapSchemaSimpleTypes.end())
	{
		return NULL;
	}
	WMSchemaSimpleTypeHandler *pElement = (*iM).second;
	if (pElement->GetNamespace() != wstrTypeNS)
	{
		return NULL;
	}
	return pElement;
}

WMSchemaComplexTypeHandler *WMSchemaHandler::GetComplexType(const wstring& wstrTypeName,
															const wstring& wstrTypeNS)
{
	map<wstring, WMSchemaComplexTypeHandler *>::iterator iM;
	if ((iM = m_mapSchemaComplexTypes.find(wstrTypeName)) == m_mapSchemaComplexTypes.end())
	{
		return NULL;
	}
	WMSchemaComplexTypeHandler *pElement = (*iM).second;
	if (pElement->GetNamespace() != wstrTypeNS)
	{
		return NULL;
	}
	return pElement;
}

void WMSchemaHandler::Merge(WMSchemaHandler *pSchema)
{
	// elements
	map<wstring, WMSchemaElemHandler *>::iterator iM1;
	for (	iM1 = pSchema->GetSchemaElemMap().begin();
			iM1 != pSchema->GetSchemaElemMap().end();
	)
	{
		if (m_mapSchemaElems.find((*iM1).first) == m_mapSchemaElems.end())
		{
			// not found here, so take ownership
			m_mapSchemaElems.insert(map<wstring,
			WMSchemaElemHandler *>::value_type((*iM1).first, (*iM1).second));
			// erase from source map
			iM1 = pSchema->GetSchemaElemMap().erase(iM1);
		}
		else
		{
			// already present, skip it
			iM1++;
		}
	}
	// simple types
	map<wstring, WMSchemaSimpleTypeHandler *>::iterator iM2;
	for (	iM2 = pSchema->GetSimpleTypeMap().begin();
			iM2 != pSchema->GetSimpleTypeMap().end();
	)
	{
		if (m_mapSchemaSimpleTypes.find((*iM2).first) == m_mapSchemaSimpleTypes.end())
		{
			// not found here, so take ownership
			m_mapSchemaSimpleTypes.insert(map<wstring,
			WMSchemaSimpleTypeHandler *>::value_type((*iM2).first, (*iM2).second));
			// erase from source map
			iM2 = pSchema->GetSimpleTypeMap().erase(iM2);
		}
		else
		{
			// already present, skip it
			iM2++;
		}
	}
	// complex types
	map<wstring, WMSchemaComplexTypeHandler *>::iterator iM3;
	for (	iM3 = pSchema->GetComplexTypeMap().begin();
			iM3 != pSchema->GetComplexTypeMap().end();
	)
	{
		if (m_mapSchemaComplexTypes.find((*iM3).first) == m_mapSchemaComplexTypes.end())
		{
			// not found here, so take ownership
			m_mapSchemaComplexTypes.insert(map<wstring,
			WMSchemaComplexTypeHandler *>::value_type((*iM3).first, (*iM3).second));
			// erase from source map
			iM3 = pSchema->GetComplexTypeMap().erase(iM3);
		}
		else
		{
			// already present, skip it
			iM3++;
		}
	}
}

void WMSchemaHandler::ReadAttributes(WMXMLAttributeMap& mapAttributes, NSPrefixMap& mapNSPrefixes)
{
	// unqualified attribute name expected
	wstring wstrElemAttr = L"schematargetNamespace";
	WMXMLAttributeMap::iterator iter;
	if (GetXSDAttribute(wstrElemAttr, mapAttributes, iter) == true)
	{
		WMXMLAttribute *pAttr = (*iter).second;
		m_wstrTNS = pAttr->GetValue();
	}
	else
	{
		// Required attribute missing
		throw new WMWebServicesDescFault(L"WSDL Schema Error",
				L"Required attribute 'targetNamespace' missing on element: 'schema'");
	}
	wstrElemAttr = L"schemaelementFormDefault";
	if (GetXSDAttribute(wstrElemAttr, mapAttributes, iter) == true)
	{
		WMXMLAttribute *pAttr = (*iter).second;
		m_bElemFormDefQualified = (pAttr->GetValue() == L"qualified") ? true : false;
	}
}

WMWSDLEventHandler *WMTypesHandler::StartElement(const wstring& wstrURI,
													const wstring& wstrLocalName,
													const wstring& wstrQualifiedName,
													WMXMLAttributeMap& mapAttributes,
													NSPrefixMap& mapNSPrefixes,
													WMXMLElement *pElement)
{
	if (IsXSDType(wstrURI) && wstrLocalName == L"schema")
	{
		// unqualified attribute name expected
		wstring wstrKey = wstrURI;
		wstrKey += wstrLocalName;
		wstrKey += L"targetNamespace";
		WMXMLAttributeMap::iterator iter;
		if ((iter = mapAttributes.find(wstrKey)) != mapAttributes.end())
		{
			WMXMLAttribute *pAttr = (*iter).second;
			// already in map?
			if (m_mapSchemas.find(pAttr->GetValue()) != m_mapSchemas.end())
			{
				// already in map
				return m_mapSchemas[pAttr->GetValue()];
			}
			// insert into map
			WMSchemaHandler *pSchema = new WMSchemaHandler();
			if (pSchema == NULL)
			{
				throw new WMWebServicesDescFault(L"Internal Error",
						L"Memory allocation failure.");
			}
			m_mapSchemas.insert(map<wstring,
				WMSchemaHandler *>::value_type(pAttr->GetValue(), pSchema));
			pSchema->SetNamespace(wstrURI);
			pSchema->ReadAttributes(mapAttributes, mapNSPrefixes);
			return pSchema;
		}
		else
		{
			// Required name attribute missing
			throw new WMWebServicesDescFault(L"WSDL Schema Error",
					L"Required attribute 'targetNamespace' missing on element: 'schema'.");
		}
	}
	return IGNORE_ELEMENT_HANDLER;
}

WMSchemaHandler *WMTypesHandler::GetSchema(const wstring& wstrSchemaTNS)
{
	map<wstring, WMSchemaHandler *>::iterator iM;
	if ((iM = m_mapSchemas.find(wstrSchemaTNS)) == m_mapSchemas.end())
	{
		return NULL;
	}
	return (*iM).second;
}

void WMInputHandler::ReadAttributes(WMXMLAttributeMap& mapAttributes, NSPrefixMap& mapNSPrefixes)
{
	// unqualified attribute name expected
	wstring wstrKey = g_pwszWebServicesDescNS;
	wstrKey += L"inputname";
	WMXMLAttributeMap::iterator iter;
	if ((iter = mapAttributes.find(wstrKey)) != mapAttributes.end())
	{
		WMXMLAttribute *pAttr = (*iter).second;
		m_wstrName = pAttr->GetValue();
	}
	// unqualified attribute name expected
	wstrKey = g_pwszWebServicesDescNS;
	wstrKey += L"inputmessage";
	if ((iter = mapAttributes.find(wstrKey)) != mapAttributes.end())
	{
		WMXMLAttribute *pAttr = (*iter).second;
		wstring wstrTemp = pAttr->GetValue();
		wstring::size_type pos = wstrTemp.find(':');
		if (pos != wstring::npos)
		{
			// get NS prefix
			NSPrefixMap::iterator iNS;
			if ((iNS = mapNSPrefixes.find(wstrTemp.substr(0, pos))) != mapNSPrefixes.end())
			{
				m_wstrMessageNS = (*iNS).second;
			}
			else
			{
				// unresolvable namespace prefix
				throw new WMWebServicesDescFault(L"WSDL Schema Error",
					L"Unresolvable namespace for attribute 'message' on element: 'input'");
			}
			m_wstrMessage = wstrTemp.substr(++pos);
		}
		else
		{
			// default namespace
			NSPrefixMap::iterator iNS;
			if ((iNS = mapNSPrefixes.find(wstring(L""))) != mapNSPrefixes.end())
			{
				m_wstrMessageNS = (*iNS).second;
			}
			else
			{
				// unresolvable namespace prefix
				throw new WMWebServicesDescFault(L"WSDL Schema Error",
					L"Unresolvable namespace for attribute 'message' on element: 'input'");
			}
			m_wstrMessage = wstrTemp;
		}
	}
	else
	{
		// Required attribute missing
		throw new WMWebServicesDescFault(L"WSDL Schema Error",
				L"Required attribute 'message' missing on element: 'input'");
	}
}

void WMOutputHandler::ReadAttributes(WMXMLAttributeMap& mapAttributes, NSPrefixMap& mapNSPrefixes)
{
	// unqualified attribute name expected
	wstring wstrKey = g_pwszWebServicesDescNS;
	wstrKey += L"outputname";
	WMXMLAttributeMap::iterator iter;
	if ((iter = mapAttributes.find(wstrKey)) != mapAttributes.end())
	{
		WMXMLAttribute *pAttr = (*iter).second;
		m_wstrName = pAttr->GetValue();
	}
	// unqualified attribute name expected
	wstrKey = g_pwszWebServicesDescNS;
	wstrKey += L"outputmessage";
	if ((iter = mapAttributes.find(wstrKey)) != mapAttributes.end())
	{
		WMXMLAttribute *pAttr = (*iter).second;
		wstring wstrTemp = pAttr->GetValue();
		wstring::size_type pos = wstrTemp.find(':');
		if (pos != wstring::npos)
		{
			// get NS prefix
			NSPrefixMap::iterator iNS;
			if ((iNS = mapNSPrefixes.find(wstrTemp.substr(0, pos))) != mapNSPrefixes.end())
			{
				m_wstrMessageNS = (*iNS).second;
			}
			else
			{
				// unresolvable namespace prefix
				throw new WMWebServicesDescFault(L"WSDL Schema Error",
					L"Unresolvable namespace for attribute 'message' on element: 'output'");
			}
			m_wstrMessage = wstrTemp.substr(++pos);
		}
		else
		{
			// default namespace
			NSPrefixMap::iterator iNS;
			if ((iNS = mapNSPrefixes.find(wstring(L""))) != mapNSPrefixes.end())
			{
				m_wstrMessageNS = (*iNS).second;
			}
			else
			{
				// unresolvable namespace prefix
				throw new WMWebServicesDescFault(L"WSDL Schema Error",
					L"Unresolvable namespace for attribute 'message' on element: 'output'");
			}
			m_wstrMessage = wstrTemp;
		}
	}
	else
	{
		// Required attribute missing
		throw new WMWebServicesDescFault(L"WSDL Schema Error",
				L"Required attribute 'message' missing on element: 'output'");
	}
}

void WMMessagePartHandler::ReadAttributes(WMXMLAttributeMap& mapAttributes, NSPrefixMap& mapNSPrefixes)
{
	// unqualified attribute name expected
	wstring wstrKey = g_pwszWebServicesDescNS;
	wstrKey += L"parttype";
	WMXMLAttributeMap::iterator iter;
	if ((iter = mapAttributes.find(wstrKey)) != mapAttributes.end())
	{
		WMXMLAttribute *pAttr = (*iter).second;
		// insert into map
		wstring wstrTemp = pAttr->GetValue();
		wstring::size_type pos = wstrTemp.find(':');
		if (pos != wstring::npos)
		{
			// get NS prefix
			NSPrefixMap::iterator iNS;
			if ((iNS = mapNSPrefixes.find(wstrTemp.substr(0, pos))) != mapNSPrefixes.end())
			{
				m_wstrTypeNS = (*iNS).second;
			}
			else
			{
				// unresolvable namespace prefix
				throw new WMWebServicesDescFault(L"WSDL Schema Error",
					L"Unresolvable namespace for attribute 'type' on element: 'message'");
			}
			m_wstrType = wstrTemp.substr(++pos);
		}
		else
		{
			// default namespace
			NSPrefixMap::iterator iNS;
			if ((iNS = mapNSPrefixes.find(wstring(L""))) != mapNSPrefixes.end())
			{
				m_wstrTypeNS = (*iNS).second;
			}
			else
			{
				// unresolvable namespace prefix
				throw new WMWebServicesDescFault(L"WSDL Schema Error",
					L"Unresolvable namespace for attribute 'type' on element: 'message'");
			}
			m_wstrType = wstrTemp;
		}
	}
	// unqualified attribute name expected
	wstrKey = g_pwszWebServicesDescNS;
	wstrKey += L"partelement";
	if ((iter = mapAttributes.find(wstrKey)) != mapAttributes.end())
	{
		WMXMLAttribute *pAttr = (*iter).second;
		// insert into map
		wstring wstrTemp = pAttr->GetValue();
		wstring::size_type pos = wstrTemp.find(':');
		if (pos != wstring::npos)
		{
			// get NS prefix
			NSPrefixMap::iterator iNS;
			if ((iNS = mapNSPrefixes.find(wstrTemp.substr(0, pos))) != mapNSPrefixes.end())
			{
				m_wstrElementNS = (*iNS).second;
			}
			else
			{
				// unresolvable namespace prefix
				throw new WMWebServicesDescFault(L"WSDL Schema Error",
					L"Unresolvable namespace for attribute 'element' on element: 'message'");
			}
			m_wstrElement = wstrTemp.substr(++pos);
		}
		else
		{
			// default namespace
			NSPrefixMap::iterator iNS;
			if ((iNS = mapNSPrefixes.find(wstring(L""))) != mapNSPrefixes.end())
			{
				m_wstrElementNS = (*iNS).second;
			}
			else
			{
				// unresolvable namespace prefix
				throw new WMWebServicesDescFault(L"WSDL Schema Error",
					L"Unresolvable namespace for attribute 'element' on element: 'message'");
			}
			m_wstrElement = wstrTemp;
		}
	}
}

WMFaultHandler *WMOperationHandler::GetFault(const wstring& wstrName)
{
	map<wstring, WMFaultHandler	*>::iterator iM;
	if ((iM = m_mapFaults.find(wstrName)) == m_mapFaults.end())
	{
		return NULL;
	}
	WMFaultHandler *pFault = (*iM).second;
	return pFault;
}

WMWSDLEventHandler *WMOperationHandler::StartElement(const wstring& wstrURI,
													const wstring& wstrLocalName,
													const wstring& wstrQualifiedName,
													WMXMLAttributeMap& mapAttributes,
													NSPrefixMap& mapNSPrefixes,
													WMXMLElement *pElement)
{
	if (IsWSDLType(wstrURI))
	{
		if (wstrLocalName == L"input")
		{
			m_Input.SetNamespace(m_wstrNS);
			m_Input.ReadAttributes(mapAttributes, mapNSPrefixes);
			return &m_Input;
		}
		else if (wstrLocalName == L"output")
		{
			m_Output.SetNamespace(m_wstrNS);
			m_Output.ReadAttributes(mapAttributes, mapNSPrefixes);
			return &m_Output;
		}
		else if (wstrLocalName == L"fault")
		{
			// unqualified attribute name expected
			wstring wstrKey = wstrURI;
			wstrKey += wstrLocalName;
			wstrKey += L"name";
			WMXMLAttributeMap::iterator iter;
			if ((iter = mapAttributes.find(wstrKey)) != mapAttributes.end())
			{
				WMFaultHandler *pFault = new WMFaultHandler();
				if (pFault == NULL)
				{
					throw new WMWebServicesDescFault(L"Internal Error",
							L"Memory allocation failure.");
				}
				WMXMLAttribute *pAttr = (*iter).second;
				// insert into map
				m_mapFaults.insert(map<wstring,
					WMFaultHandler *>::value_type(pAttr->GetValue(), pFault));
				pFault->SetNamespace(m_wstrNS);
				pFault->ReadAttributes(mapAttributes, mapNSPrefixes);
				return pFault;
			}
			else
			{
				// Required name attribute missing
				throw new WMWebServicesDescFault(L"WSDL Schema Error",
						L"Required attribute 'name' missing on element: 'fault'.");
			}
		}
	}
	return IGNORE_ELEMENT_HANDLER;
}

void WMOperationHandler::ReadAttributes(WMXMLAttributeMap& mapAttributes, NSPrefixMap& mapNSPrefixes)
{
	// unqualified attribute name expected
	wstring wstrKey = g_pwszWebServicesDescNS;
	wstrKey += L"operationparameterOrder";
	WMXMLAttributeMap::iterator iter;
	if ((iter = mapAttributes.find(wstrKey)) != mapAttributes.end())
	{
		WMXMLAttribute *pAttr = (*iter).second;
		m_wstrParameterOrder = pAttr->GetValue();
		// parse string and populate map
		wstring wstrParamOrder = pAttr->GetValue();
		wstring::size_type wpos;
		int i = 0;
		for (wpos = wstrParamOrder.find(wchar_t(' '));
				wpos != wstring::npos;
				wpos = wstrParamOrder.find(wchar_t(' ')))
		{
			if (wstrParamOrder.substr(0, wpos).empty() == false)
			{
				m_mapParamOrder.insert(
					map<wstring, int>::value_type(wstrParamOrder.substr(0, wpos), i++));
			}
			wstrParamOrder = wstrParamOrder.substr(++wpos);
		}
		if (wstrParamOrder.empty() == false)
		{
			m_mapParamOrder.insert(map<wstring, int>::value_type(wstrParamOrder.substr(0, wpos), i));
		}
	}
}

bool WMOperationHandler::GetParamOrderIndex(const wstring& wstrParam, int& nIndex)
{
	map<wstring, int>::iterator iter;
	iter = m_mapParamOrder.find(wstrParam);
	if (iter == m_mapParamOrder.end())
	{
		return false;
	}
	nIndex = (*iter).second;
	return true;
}

WMWSDLEventHandler *WMPortTypeHandler::StartElement(const wstring& wstrURI,
													const wstring& wstrLocalName,
													const wstring& wstrQualifiedName,
													WMXMLAttributeMap& mapAttributes,
													NSPrefixMap& mapNSPrefixes,
													WMXMLElement *pElement)
{
	if (IsWSDLType(wstrURI) && wstrLocalName == L"operation")
	{
		// unqualified attribute name expected
		wstring wstrKey = wstrURI;
		wstrKey += wstrLocalName;
		wstrKey += L"name";
		WMXMLAttributeMap::iterator iter;
		if ((iter = mapAttributes.find(wstrKey)) != mapAttributes.end())
		{
			WMOperationHandler *pOperation = new WMOperationHandler();
			if (pOperation == NULL)
			{
				throw new WMWebServicesDescFault(L"Internal Error",
						L"Memory allocation failure.");
			}
			WMXMLAttribute *pAttr = (*iter).second;
			// insert into map
			m_mapOperations.insert(map<wstring,
				WMOperationHandler *>::value_type(pAttr->GetValue(), pOperation));
			pOperation->SetNamespace(m_wstrNS);
			pOperation->ReadAttributes(mapAttributes, mapNSPrefixes);
			return pOperation;
		}
		else
		{
			// Required name attribute missing
			throw new WMWebServicesDescFault(L"WSDL Schema Error",
					L"Required attribute 'name' missing on element: 'operation'.");
		}
	}
	return IGNORE_ELEMENT_HANDLER;
}

WMOperationHandler *WMPortTypeHandler::GetOperation(const wstring& wstrOpName)
{
	map<wstring, WMOperationHandler *>::iterator iM;
	if ((iM = m_mapOperations.find(wstrOpName)) == m_mapOperations.end())
	{
		return NULL;
	}
	WMOperationHandler *pOp = (*iM).second;
	return pOp;
}
	
WMWSDLEventHandler *WMMessageHandler::StartElement(const wstring& wstrURI,
													const wstring& wstrLocalName,
													const wstring& wstrQualifiedName,
													WMXMLAttributeMap& mapAttributes,
													NSPrefixMap& mapNSPrefixes,
													WMXMLElement *pElement)
{
	if (IsWSDLType(wstrURI) && wstrLocalName == L"part")
	{
		// unqualified attribute name expected
		wstring wstrKey = wstrURI;
		wstrKey += wstrLocalName;
		wstrKey += L"name";
		WMXMLAttributeMap::iterator iter;
		if ((iter = mapAttributes.find(wstrKey)) != mapAttributes.end())
		{
			WMMessagePartHandler *pPart = new WMMessagePartHandler();
			if (pPart == NULL)
			{
				throw new WMWebServicesDescFault(L"Internal Error",
						L"Memory allocation failure.");
			}
			WMXMLAttribute *pAttr = (*iter).second;
			// insert into map
			m_mapParts.insert(map<wstring,
				WMMessagePartHandler *>::value_type(pAttr->GetValue(), pPart));
			pPart->SetNamespace(m_wstrNS);
			pPart->ReadAttributes(mapAttributes, mapNSPrefixes);
			// if first then update default part
			if (m_pDefaultPart == NULL)
			{
				m_pDefaultPart = pPart;
			}
			return pPart;
		}
		else
		{
			// Required name attribute missing
			throw new WMWebServicesDescFault(L"WSDL Schema Error",
					L"Required attribute 'name' missing on element: 'part'.");
		}
	}
	return IGNORE_ELEMENT_HANDLER;
}

WMMessagePartHandler *WMMessageHandler::GetMessagePart(const wstring& wstrPartName)
{
	map<wstring, WMMessagePartHandler *>::iterator iM;
	if ((iM = m_mapParts.find(wstrPartName)) == m_mapParts.end())
	{
		return NULL;
	}
	return (*iM).second;
}

bool WMMessageHandler::GetMessagePartType(const wstring& wstrPartName,
											wstring& wstrType,
											wstring& wstrTypeNS)
{
	// first case...part refers to type
	WMMessagePartHandler *pPart;
	if ((pPart = GetMessagePart(wstrPartName)) == NULL)
	{
		return false;
	}
	pPart->GetType(wstrType, wstrTypeNS);
	if (wstrType.empty() == false)
	{
		// check for simpleType declared with this name
		WMSchemaHandler *pSchema;
		if ((pSchema = m_Types.GetSchema(wstrTypeNS)) == NULL)
		{
			// no schema found for this namespace, done
			return true;
		}
		// ok, schema found...check for simpleType declared with this name
		WMSchemaSimpleTypeHandler *pSimpleType;
		if ((pSimpleType = pSchema->GetSimpleType(wstrType, wstrTypeNS)) != NULL)
		{
			// found matching simple type, get base type name
			pSimpleType->GetBaseTypeNames(wstrType, wstrTypeNS);
		}
		return true;
	}
	// second case...part refers to xsi:element element in schema
	wstring wstrElement, wstrElementNS;
	pPart->GetElement(wstrElement, wstrElementNS);
	if (wstrElement.length() == 0)
	{
		return false;
	}
	// look for schema associated with element qname
	WMSchemaHandler *pSchema;
	if ((pSchema = m_Types.GetSchema(wstrElementNS)) == NULL)
	{
		return false;
	}
	// ok, schema found...get element itself
	WMSchemaElemHandler *pElement;
	if ((pElement = pSchema->GetSchemaElem(wstrElement, wstrElementNS)) == NULL)
	{
		return false;
	}
	// found it, get type
	pElement->GetType(wstrType, wstrTypeNS);
	if (wstrType.empty() == false)
	{
		// check for simpleType declared with this name
		WMSchemaHandler *pSchema;
		if ((pSchema = m_Types.GetSchema(wstrTypeNS)) == NULL)
		{
			// no schema found for this namespace, done
			return true;
		}
		// ok, schema found...check for simpleType declared with this name
		WMSchemaSimpleTypeHandler *pSimpleType;
		if ((pSimpleType = pSchema->GetSimpleType(wstrType, wstrTypeNS)) != NULL)
		{
			// found matching simple type, get base type name
			pSimpleType->GetBaseTypeNames(wstrType, wstrTypeNS);
		}
		return true;
	}
	return false;
}

bool WMMessageHandler::GetDefaultPartType(	wstring& wstrType,
											wstring& wstrTypeNS)
{
	if (m_pDefaultPart == NULL)
	{
		return false;
	}
	// first case...part refers to type
	m_pDefaultPart->GetType(wstrType, wstrTypeNS);
	if (wstrType.empty() == false)
	{
		// check for simpleType declared with this name
		WMSchemaHandler *pSchema;
		if ((pSchema = m_Types.GetSchema(wstrTypeNS)) == NULL)
		{
			// no schema found for this namespace, done
			return true;
		}
		// ok, schema found...check for simpleType declared with this name
		WMSchemaSimpleTypeHandler *pSimpleType;
		if ((pSimpleType = pSchema->GetSimpleType(wstrType, wstrTypeNS)) != NULL)
		{
			// found matching simple type, get base type name
			pSimpleType->GetBaseTypeNames(wstrType, wstrTypeNS);
		}
		return true;
	}
	// second case...part refers to xsi:element element in schema
	wstring wstrElement, wstrElementNS;
	m_pDefaultPart->GetElement(wstrElement, wstrElementNS);
	if (wstrElement.length() == 0)
	{
		return false;
	}
	// look for schema associated with element qname
	WMSchemaHandler *pSchema;
	if ((pSchema = m_Types.GetSchema(wstrElementNS)) == NULL)
	{
		return false;
	}
	// ok, schema found...get element itself
	WMSchemaElemHandler *pElement;
	if ((pElement = pSchema->GetSchemaElem(wstrElement, wstrElementNS)) == NULL)
	{
		return false;
	}
	// found it, get type
	pElement->GetType(wstrType, wstrTypeNS);
	if (wstrType.empty() == false)
	{
		// check for simpleType declared with this name
		WMSchemaHandler *pSchema;
		if ((pSchema = m_Types.GetSchema(wstrTypeNS)) == NULL)
		{
			// no schema found for this namespace, done
			return true;
		}
		// ok, schema found...check for simpleType declared with this name
		WMSchemaSimpleTypeHandler *pSimpleType;
		if ((pSimpleType = pSchema->GetSimpleType(wstrType, wstrTypeNS)) != NULL)
		{
			// found matching simple type, get base type name
			pSimpleType->GetBaseTypeNames(wstrType, wstrTypeNS);
		}
		return true;
	}
	return false;
}

WMWSDLEventHandler *WMBindingHandler::StartElement(const wstring& wstrURI,
													const wstring& wstrLocalName,
													const wstring& wstrQualifiedName,
													WMXMLAttributeMap& mapAttributes,
													NSPrefixMap& mapNSPrefixes,
													WMXMLElement *pElement)
{
	if (IsWSDLType(wstrURI) && wstrLocalName == L"operation")
	{
		// unqualified attribute name expected
		wstring wstrKey = wstrURI;
		wstrKey += wstrLocalName;
		wstrKey += L"name";
		WMXMLAttributeMap::iterator iter;
		if ((iter = mapAttributes.find(wstrKey)) != mapAttributes.end())
		{
			WMOperationHandler *pOperation = new WMOperationHandler();
			if (pOperation == NULL)
			{
				throw new WMWebServicesDescFault(L"Internal Error",
						L"Memory allocation failure.");
			}
			WMXMLAttribute *pAttr = (*iter).second;
			// insert into map
			m_mapOperations.insert(map<wstring,
				WMOperationHandler *>::value_type(pAttr->GetValue(), pOperation));
			pOperation->SetNamespace(m_wstrNS);
			return pOperation;
		}
		else
		{
			// Required name attribute missing
			throw new WMWebServicesDescFault(L"WSDL Schema Error",
					L"Required attribute 'name' missing on element: 'operation'.");
		}
	}
	return IGNORE_ELEMENT_HANDLER;
}

void WMBindingHandler::ReadAttributes(WMXMLAttributeMap& mapAttributes, NSPrefixMap& mapNSPrefixes)
{
	// unqualified attribute name expected
	wstring wstrKey = g_pwszWebServicesDescNS;
	wstrKey += L"bindingtype";
	WMXMLAttributeMap::iterator iter;
	if ((iter = mapAttributes.find(wstrKey)) != mapAttributes.end())
	{
		WMXMLAttribute *pAttr = (*iter).second;
		wstring wstrTemp = pAttr->GetValue();
		wstring::size_type pos = wstrTemp.find(':');
		if (pos != wstring::npos)
		{
			// get NS prefix
			NSPrefixMap::iterator iNS;
			if ((iNS = mapNSPrefixes.find(wstrTemp.substr(0, pos))) != mapNSPrefixes.end())
			{
				m_wstrTypeNS = (*iNS).second;
			}
			else
			{
				// unresolvable namespace prefix
				throw new WMWebServicesDescFault(L"WSDL Schema Error",
					L"Unresolvable namespace for attribute 'type' on element: 'binding'");
			}
			m_wstrType = wstrTemp.substr(++pos);
		}
		else
		{
			// default namespace
			NSPrefixMap::iterator iNS;
			if ((iNS = mapNSPrefixes.find(wstring(L""))) != mapNSPrefixes.end())
			{
				m_wstrTypeNS = (*iNS).second;
			}
			else
			{
				// unresolvable namespace prefix
				throw new WMWebServicesDescFault(L"WSDL Schema Error",
					L"Unresolvable namespace for attribute 'type' on element: 'binding'");
			}
			m_wstrType = wstrTemp;
		}
	}
	else
	{
		// Required 'type' attribute missing
		throw new WMWebServicesDescFault(L"WSDL Schema Error",
				L"Required attribute 'type' missing on element: 'binding'");
	}
}

WMOperationHandler *WMBindingHandler::GetOperation(const wstring& wstrOpName)
{
	map<wstring, WMOperationHandler *>::iterator iM;
	if ((iM = m_mapOperations.find(wstrOpName)) == m_mapOperations.end())
	{
		return NULL;
	}
	WMOperationHandler *pOp = (*iM).second;
	return pOp;
}

void WMPortHandler::ReadAttributes(WMXMLAttributeMap& mapAttributes, NSPrefixMap& mapNSPrefixes)
{
	// unqualified attribute name expected
	wstring wstrKey = g_pwszWebServicesDescNS;
	wstrKey += L"portbinding";
	WMXMLAttributeMap::iterator iter;
	if ((iter = mapAttributes.find(wstrKey)) != mapAttributes.end())
	{
		WMXMLAttribute *pAttr = (*iter).second;
		// insert into map
		wstring wstrTemp = pAttr->GetValue();
		wstring::size_type pos = wstrTemp.find(':');
		if (pos != wstring::npos)
		{
			// get NS prefix
			NSPrefixMap::iterator iNS;
			if ((iNS = mapNSPrefixes.find(wstrTemp.substr(0, pos))) != mapNSPrefixes.end())
			{
				m_wstrBindingNS = (*iNS).second;
			}
			else
			{
				// unresolvable namespace prefix
				throw new WMWebServicesDescFault(L"WSDL Schema Error",
					L"Unresolvable namespace for attribute 'binding' on element: 'port'");
			}
			m_wstrBinding = wstrTemp.substr(++pos);
		}
		else
		{
			// default namespace
			NSPrefixMap::iterator iNS;
			if ((iNS = mapNSPrefixes.find(wstring(L""))) != mapNSPrefixes.end())
			{
				m_wstrBindingNS = (*iNS).second;
			}
			else
			{
				// unresolvable namespace prefix
				throw new WMWebServicesDescFault(L"WSDL Schema Error",
					L"Unresolvable namespace for attribute 'binding' on element: 'port'");
			}
			m_wstrBinding = wstrTemp;
		}
	}
	else
	{
		// Required attribute missing
		throw new WMWebServicesDescFault(L"WSDL Schema Error",
				L"Required attribute 'binding' missing on element: 'port'");
	}
}

WMWSDLEventHandler *WMServiceHandler::StartElement(const wstring& wstrURI,
													const wstring& wstrLocalName,
													const wstring& wstrQualifiedName,
													WMXMLAttributeMap& mapAttributes,
													NSPrefixMap& mapNSPrefixes,
													WMXMLElement *pElement)
{
	if (IsWSDLType(wstrURI))
	{
		if (wstrLocalName == L"port")
		{
			// unqualified attribute name expected
			wstring wstrKey = wstrURI;
			wstrKey += wstrLocalName;
			wstrKey += L"name";
			WMXMLAttributeMap::iterator iter;
			if ((iter = mapAttributes.find(wstrKey)) != mapAttributes.end())
			{
				WMPortHandler *pPort = new WMPortHandler();
				if (pPort == NULL)
				{
					throw new WMWebServicesDescFault(L"Internal Error",
							L"Memory allocation failure.");
				}
				WMXMLAttribute *pAttr = (*iter).second;
				// insert into map
				m_mapPorts.insert(map<wstring,
					WMPortHandler *>::value_type(pAttr->GetValue(), pPort));
				pPort->SetNamespace(m_wstrNS);
				pPort->ReadAttributes(mapAttributes, mapNSPrefixes);
				return pPort;
			}
			else
			{
				// Required name attribute missing
				throw new WMWebServicesDescFault(L"WSDL Schema Error",
						L"Required attribute 'name' missing on element: 'port'.");
			}
		}
	}
	return IGNORE_ELEMENT_HANDLER;
}

WMPortHandler *WMServiceHandler::GetPort(const wstring& wstrPortName)
{
	map<wstring, WMPortHandler *>::iterator iM;
	if ((iM = m_mapPorts.find(wstrPortName)) == m_mapPorts.end())
	{
		return NULL;
	}
	return (*iM).second;
}

WMWSDLEventHandler *WMDefinitionsHandler::StartElement(const wstring& wstrURI,
														const wstring& wstrLocalName,
														const wstring& wstrQualifiedName,
														WMXMLAttributeMap& mapAttributes,
														NSPrefixMap& mapNSPrefixes,
														WMXMLElement *pElement)
{
	if (IsWSDLType(wstrURI))
	{
		// 'types' element is unique and un-named
		if (wstrLocalName == L"types")
		{
			m_Types.SetNamespace(m_wstrTNS);
			return &m_Types;
		}
		// unqualified attribute name expected
		wstring wstrKey = wstrURI;
		wstrKey += wstrLocalName;
		wstrKey += L"name";
		WMXMLAttributeMap::iterator iter;
		if (wstrLocalName == L"binding")
		{
			if ((iter = mapAttributes.find(wstrKey)) != mapAttributes.end())
			{
				WMBindingHandler *pBinding = new WMBindingHandler();
				if (pBinding == NULL)
				{
					throw new WMWebServicesDescFault(L"Internal Error",
							L"Memory allocation failure.");
				}
				WMXMLAttribute *pAttr = (*iter).second;
				// insert into map
				m_mapBindings.insert(map<wstring,
					WMBindingHandler *>::value_type(pAttr->GetValue(), pBinding));
				pBinding->SetNamespace(m_wstrTNS);
				pBinding->ReadAttributes(mapAttributes, mapNSPrefixes);
				return pBinding;
			}
			else
			{
				// Required name attribute missing
				throw new WMWebServicesDescFault(L"WSDL Schema Error",
						L"Required attribute 'name' missing on element: 'binding'.");
			}
		}
		else if (wstrLocalName == L"service")
		{
			if ((iter = mapAttributes.find(wstrKey)) != mapAttributes.end())
			{
				WMServiceHandler *pService = new WMServiceHandler();
				if (pService == NULL)
				{
					throw new WMWebServicesDescFault(L"Internal Error",
							L"Memory allocation failure.");
				}
				WMXMLAttribute *pAttr = (*iter).second;
				// insert into map
				m_mapServices.insert(map<wstring,
					WMServiceHandler *>::value_type(pAttr->GetValue(), pService));
				pService->SetNamespace(m_wstrTNS);
				return pService;
			}
			else
			{
				// Required name attribute missing
				throw new WMWebServicesDescFault(L"WSDL Schema Error",
						L"Required attribute 'name' missing on element: 'service'.");
			}
		}
		else if (wstrLocalName == L"message")
		{
			if ((iter = mapAttributes.find(wstrKey)) != mapAttributes.end())
			{
				WMMessageHandler *pMessage = new WMMessageHandler(m_Types);
				if (pMessage == NULL)
				{
					throw new WMWebServicesDescFault(L"Internal Error",
							L"Memory allocation failure.");
				}
				WMXMLAttribute *pAttr = (*iter).second;
				// insert into map
				m_mapMessages.insert(map<wstring,
					WMMessageHandler *>::value_type(pAttr->GetValue(), pMessage));
				pMessage->SetNamespace(m_wstrTNS);
				return pMessage;
			}
			else
			{
				// Required name attribute missing
				throw new WMWebServicesDescFault(L"WSDL Schema Error",
						L"Required attribute 'name' missing on element: 'message'.");
			}
		}
		else if (wstrLocalName == L"portType")
		{
			if ((iter = mapAttributes.find(wstrKey)) != mapAttributes.end())
			{
				WMPortTypeHandler *pPortType = new WMPortTypeHandler();
				if (pPortType == NULL)
				{
					throw new WMWebServicesDescFault(L"Internal Error",
							L"Memory allocation failure.");
				}
				WMXMLAttribute *pAttr = (*iter).second;
				// insert into map
				m_mapPortTypes.insert(map<wstring,
					WMPortTypeHandler *>::value_type(pAttr->GetValue(), pPortType));
				pPortType->SetNamespace(m_wstrTNS);
				return pPortType;
			}
			else
			{
				// Required name attribute missing
				throw new WMWebServicesDescFault(L"WSDL Schema Error",
						L"Required attribute 'name' missing on element: 'portType'.");
			}
		}
	}
	return IGNORE_ELEMENT_HANDLER;
}

void WMDefinitionsHandler::ReadAttributes(WMXMLAttributeMap& mapAttributes, NSPrefixMap& mapNSPrefixes)
{
	// unqualified attribute name expected
	wstring wstrKey = g_pwszWebServicesDescNS;
	wstrKey += L"definitionsname";
	WMXMLAttributeMap::iterator iter;
	if ((iter = mapAttributes.find(wstrKey)) != mapAttributes.end())
	{
		WMXMLAttribute *pAttr = (*iter).second;
		m_wstrName = pAttr->GetValue();
	}
	// unqualified attribute name expected
	wstrKey = g_pwszWebServicesDescNS;
	wstrKey += L"definitionstargetNamespace";
	if ((iter = mapAttributes.find(wstrKey)) != mapAttributes.end())
	{
		WMXMLAttribute *pAttr = (*iter).second;
		m_wstrTNS = pAttr->GetValue();
	}
}

WMServiceHandler *WMDefinitionsHandler::GetService(const wstring& wstrServiceName,
												   const wstring& wstrNamespace)
{
	map<wstring, WMServiceHandler *>::iterator iM;
	if ((iM = m_mapServices.find(wstrServiceName)) == m_mapServices.end())
	{
		return NULL;
	}
	WMServiceHandler *pService = (*iM).second;
	if (pService->GetNamespace() != wstrNamespace)
	{
		return NULL;
	}
	return pService;
}

WMPortTypeHandler *WMDefinitionsHandler::GetPortType(const wstring& wstrPortTypeName,
													 const wstring& wstrNamespace)
{
	map<wstring, WMPortTypeHandler *>::iterator iM;
	if ((iM = m_mapPortTypes.find(wstrPortTypeName)) == m_mapPortTypes.end())
	{
		return NULL;
	}
	WMPortTypeHandler *pPortType = (*iM).second;
	if (pPortType->GetNamespace() != wstrNamespace)
	{
		return NULL;
	}
	return pPortType;
}

WMBindingHandler *WMDefinitionsHandler::GetBinding(const wstring& wstrServiceName,
												   const wstring& wstrPortName,
												   const wstring& wstrNamespace)
{
	WMServiceHandler *pService = GetService(wstrServiceName, wstrNamespace);
	if (pService == NULL)
	{
		return NULL;
	}
	WMPortHandler *pPort;
	if ((pPort = pService->GetPort(wstrPortName)) == NULL)
	{
		return NULL;
	}
	map<wstring, WMBindingHandler *>::iterator iM;
	if ((iM = m_mapBindings.find(pPort->GetBindingName())) == m_mapBindings.end())
	{
		return NULL;
	}
	return (*iM).second;
}

WMMessageHandler *WMDefinitionsHandler::GetMessage(	const wstring& wstrMessageName,
													const wstring& wstrNamespace)
{
	map<wstring, WMMessageHandler *>::iterator iM;
	if ((iM = m_mapMessages.find(wstrMessageName)) == m_mapMessages.end())
	{
		return NULL;
	}
	WMMessageHandler *pMsg = (*iM).second;
	if (pMsg->GetNamespace() != wstrNamespace)
	{
		return NULL;
	}
	return pMsg;
}

bool WMDefinitionsHandler::GetSchemaElemType(const wstring& wstrElemName,
											const wstring& wstrElemNS,
											wstring& wstrType,
											wstring& wstrTypeNS)
{
	// look for schema associated with qname
	WMSchemaHandler *pSchema = GetTypes().GetSchema(wstrElemNS);
	if (pSchema == NULL)
	{
		return false;
	}
	// look for element declaration in schema
	WMSchemaElemHandler *pElement = pSchema->GetSchemaElem(wstrElemName, wstrElemNS);
	if (pElement == NULL)
	{
		return false;
	}
	// get element's type
	pElement->GetType(wstrType, wstrTypeNS);
	return true;
}

bool WMDefinitionsHandler::GetArrayType(const wstring& wstrArrayName,
										const wstring& wstrArrayNS,
										wstring& wstrType,
										wstring& wstrTypeNS)
{
	// look for schema associated with qname
	WMSchemaHandler *pSchema;
	if ((pSchema = m_Types.GetSchema(wstrArrayNS)) == NULL)
	{
		return false;
	}
	// ok, schema found...get array type itself
	WMSchemaComplexTypeHandler *pComplexType;
	if ((pComplexType = pSchema->GetComplexType(wstrArrayName, wstrArrayNS)) == NULL)
	{
		return false;
	}
	// found it, get array element type
	bool bIsRef = false;
	if (pComplexType->GetArrayType(wstrType, wstrTypeNS, bIsRef) == false)
	{
		return false;
	}
	// is it a reference?
	if (bIsRef == true)
	{
		// a reference, try to look it up
		wstring wstrElemName = wstrType;
		wstring wstrElemNS = wstrTypeNS;
		if (GetSchemaElemType(wstrElemName, wstrElemNS, wstrType, wstrTypeNS) == false)
		{
			// bad reference
			return false;
		}
	}
	// check for simpleType declared with this name
	if ((pSchema = m_Types.GetSchema(wstrTypeNS)) == NULL)
	{
		// no schema found for this namespace, done
		return true;
	}
	// ok, schema found...check for simpleType declared with this name
	WMSchemaSimpleTypeHandler *pSimpleType;
	if ((pSimpleType = pSchema->GetSimpleType(wstrType, wstrTypeNS)) != NULL)
	{
		// found matching simple type, get base type name
		pSimpleType->GetBaseTypeNames(wstrType, wstrTypeNS);
	}
	return true;
}

bool WMDefinitionsHandler::GetArrayTypeLit( const wstring& wstrArrayName,
										    const wstring& wstrArrayNS,
										    wstring& wstrItemType,
										    wstring& wstrItemTypeNS,
                                            wstring& wstrItemName,
                                            wstring& wstrItemNS)
{
	// look for schema associated with qname
	WMSchemaHandler *pSchema;
	if ((pSchema = m_Types.GetSchema(wstrArrayNS)) == NULL)
	{
		return false;
	}
	// ok, schema found...get array type itself
	WMSchemaComplexTypeHandler *pComplexType;
	if ((pComplexType = pSchema->GetComplexType(wstrArrayName, wstrArrayNS)) == NULL)
	{
		return false;
	}
	// found it, get array element type
	bool bIsRef = false;
	if (pComplexType->GetArrayTypeLit(  wstrItemType,
                                        wstrItemTypeNS,
                                        wstrItemName,
                                        wstrItemNS,
                                        bIsRef) == false)
	{
		return false;
	}
	// is it a reference?
	if (bIsRef == true)
	{
		// a reference, try to look it up, names will have been populated
        // during call to GetLitArrayType() above
		if (GetSchemaElemType(wstrItemName, wstrItemNS, wstrItemType, wstrItemTypeNS) == false)
		{
			// bad reference
			return false;
		}
	}
	// check for simpleType declared with this name
	if ((pSchema = m_Types.GetSchema(wstrItemTypeNS)) == NULL)
	{
		// no schema found for this namespace, done
		return true;
	}
	// ok, schema found...check for simpleType declared with this name
	WMSchemaSimpleTypeHandler *pSimpleType;
	if ((pSimpleType = pSchema->GetSimpleType(wstrItemType, wstrItemTypeNS)) != NULL)
	{
		// found matching simple type, get base type name
		pSimpleType->GetBaseTypeNames(wstrItemType, wstrItemTypeNS);
	}
	return true;
}

bool WMDefinitionsHandler::GetArrayDims(const wstring& wstrArrayName,
										const wstring& wstrArrayNS,
										unsigned int& nDims)
{
	// look for schema associated with qname
	WMSchemaHandler *pSchema;
	if ((pSchema = m_Types.GetSchema(wstrArrayNS)) == NULL)
	{
		return false;
	}
	// ok, schema found...get array type itself
	WMSchemaComplexTypeHandler *pComplexType;
	if ((pComplexType = pSchema->GetComplexType(wstrArrayName, wstrArrayNS)) == NULL)
	{
		return false;
	}
	// found it, get array dimensionality
	nDims = pComplexType->GetArrayDims();
	return true;
}

WMSchemaSimpleTypeHandler * WMDefinitionsHandler::GetSimpleType(  const wstring& wstrName,
																	const wstring& wstrNS)
{
	// look for schema associated with element qname
	WMSchemaHandler *pSchema;
	if ((pSchema = m_Types.GetSchema(wstrNS)) == NULL)
	{
		return NULL;
	}
	// ok, schema found...get type itself
	return pSchema->GetSimpleType(wstrName, wstrNS);
}

WMSchemaComplexTypeHandler * WMDefinitionsHandler::GetComplexType(  const wstring& wstrName,
																	const wstring& wstrNS)
{
	// look for schema associated with element qname
	WMSchemaHandler *pSchema;
	if ((pSchema = m_Types.GetSchema(wstrNS)) == NULL)
	{
		return NULL;
	}
	// ok, schema found...get type itself
	return pSchema->GetComplexType(wstrName, wstrNS);
}

bool WMDefinitionsHandler::GetSimpleBaseType(	const wstring& wstrName,
												const wstring& wstrNS,
												wstring& wstrBaseType,
												wstring& wstrBaseTypeNS)
{
	// look for schema associated with element qname
	WMSchemaHandler *pSchema;
	if ((pSchema = m_Types.GetSchema(wstrNS)) == NULL)
	{
		return false;
	}
	// ok, schema found...get type itself
	WMSchemaSimpleTypeHandler *pSimpleType;
	if ((pSimpleType = pSchema->GetSimpleType(wstrName, wstrNS)) == NULL)
	{
		return false;
	}
	// found it, get base type
	pSimpleType->GetBaseTypeNames(wstrBaseType, wstrBaseTypeNS);
	return true;
}

bool WMDefinitionsHandler::GetComplexBaseType(  const wstring& wstrName,
												const wstring& wstrNS,
												wstring& wstrBaseType,
												wstring& wstrBaseTypeNS)
{
	// look for schema associated with element qname
	WMSchemaHandler *pSchema;
	if ((pSchema = m_Types.GetSchema(wstrNS)) == NULL)
	{
		return false;
	}
	// ok, schema found...get type itself
	WMSchemaComplexTypeHandler *pComplexType;
	if ((pComplexType = pSchema->GetComplexType(wstrName, wstrNS)) == NULL)
	{
		return false;
	}
	// found it, get base type
	pComplexType->GetBaseTypeNames(wstrBaseType, wstrBaseTypeNS);
	return true;
}

bool WMDefinitionsHandler::GetFirstStructMember(const wstring& wstrStructName,
												const wstring& wstrStructNS,
												wstring& wstrMemberName,
												wstring& wstrMemberNS,
												wstring& wstrType,
												wstring& wstrTypeNS,
												long& lPosition)
{
	// look for schema associated with struct qname
	WMSchemaHandler *pSchema = GetTypes().GetSchema(wstrStructNS);
	if (pSchema == NULL)
	{
		return false;
	}
	// look for complex type
	WMSchemaComplexTypeHandler *pComplexType;
	if ((pComplexType = pSchema->GetComplexType(wstrStructName, wstrStructNS)) == NULL)
	{
		// no matching complex type found
		return false;
	}
	// look for first member
	list<WMSchemaElemHandler *>::iterator iL;
	iL = pComplexType->GetSchemaSequence().GetSchemaElemList().begin();
	if (iL == pComplexType->GetSchemaSequence().GetSchemaElemList().end())
	{
		// empty list
		return false;
	}
	lPosition = 0;
	// is it a reference?
	WMSchemaElemHandler *pElem = *iL;
	pElem->GetNames(wstrMemberName, wstrMemberNS);
	if (pElem->IsRef() == true)
	{
		// a reference, try to look it up
		GetSchemaElemType(wstrMemberName, wstrMemberNS, wstrType, wstrTypeNS);
		return true;
	}
	pElem->GetType(wstrType, wstrTypeNS);
	return true;
}

bool WMDefinitionsHandler::GetNextStructMember( const wstring& wstrStructName,
												const wstring& wstrStructNS,
												wstring& wstrMemberName,
												wstring& wstrMemberNS,
												wstring& wstrType,
												wstring& wstrTypeNS,
												long& lPosition)
{
	// look for schema associated with struct qname
	WMSchemaHandler *pSchema = GetTypes().GetSchema(wstrStructNS);
	if (pSchema == NULL)
	{
		return false;
	}
	// look for complex type
	WMSchemaComplexTypeHandler *pComplexType;
	if ((pComplexType = pSchema->GetComplexType(wstrStructName, wstrStructNS)) == NULL)
	{
		// no matching complex type found
		return false;
	}
	// look for member
	list<WMSchemaElemHandler *>::iterator iL;
	iL = pComplexType->GetSchemaSequence().GetSchemaElemList().begin();
	long lNext = lPosition + 1;
	for (long i = 0; i < lNext; i++)
	{
		iL++;
	}
	if (iL != pComplexType->GetSchemaSequence().GetSchemaElemList().end())
	{
		lPosition = lNext;
		// is it a reference?
		WMSchemaElemHandler *pElem = *iL;
		pElem->GetNames(wstrMemberName, wstrMemberNS);
		if (pElem->IsRef() == true)
		{
			// a reference, try to look it up
			GetSchemaElemType(wstrMemberName, wstrMemberNS, wstrType, wstrTypeNS);
			return true;
		}
		pElem->GetType(wstrType, wstrTypeNS);
		return true;
	}
	return false;
}

bool WMDefinitionsHandler::GetStructMemberType( const wstring& wstrStructName,
												const wstring& wstrStructNS,
												const wstring& wstrMemberName,
												const wstring& wstrMemberNS,
												wstring& wstrType,
												wstring& wstrTypeNS)
{
	// look for schema associated with struct qname
	WMSchemaHandler *pSchema = GetTypes().GetSchema(wstrStructNS);
	if (pSchema == NULL)
	{
		return false;
	}
	// look for complex type
	WMSchemaComplexTypeHandler *pComplexType;
	if ((pComplexType = pSchema->GetComplexType(wstrStructName, wstrStructNS)) == NULL)
	{
		// no matching complex type found
		return false;
	}
	// look for member type
	bool bIsRef = false;
	if (pComplexType->GetElementType(wstrMemberName, wstrMemberNS, wstrType, wstrTypeNS, bIsRef) == false)
	{
        // is it an extended type?
        if (pComplexType->IsExtension() == true)
        {
            wstring wstrName, wstrNS;
            pComplexType->GetBaseTypeNames(wstrName, wstrNS);
            return GetStructMemberType( wstrName,
									    wstrNS,
									    wstrMemberName,
									    wstrMemberNS,
									    wstrType,
									    wstrTypeNS);
        }
		// member not found
		return false;
	}
	if (bIsRef == true)
	{
		// a reference, try to look it up
		wstring wstrElemName = wstrType;
		wstring wstrElemNS = wstrTypeNS;
		if (GetSchemaElemType(wstrElemName, wstrElemNS, wstrType, wstrTypeNS) == false)
		{
			// bad reference
			return false;
		}
	}
	// check for simpleType declared with this name
	if ((pSchema = m_Types.GetSchema(wstrTypeNS)) == NULL)
	{
		// no schema found for this namespace, done
		return true;
	}
	// ok, schema found...check for simpleType declared with this name
	WMSchemaSimpleTypeHandler *pSimpleType;
	if ((pSimpleType = pSchema->GetSimpleType(wstrType, wstrTypeNS)) != NULL)
	{
		// found matching simple type, get base type name
		pSimpleType->GetBaseTypeNames(wstrType, wstrTypeNS);
	}
	return true;
}

WMWSDLEventHandler *WMWSDLDesc::StartElement(   const wstring& wstrURI,
												const wstring& wstrLocalName,
												const wstring& wstrQualifiedName,
												WMXMLAttributeMap& mapAttributes,
												NSPrefixMap& mapNSPrefixes,
												WMXMLElement *pElement)
{
	if (IsWSDLType(wstrURI) && wstrLocalName == L"definitions")
	{
		m_Definitions.ReadAttributes(mapAttributes, mapNSPrefixes);
		return &m_Definitions;
	}
	return IGNORE_ELEMENT_HANDLER;
}
