FIX: DTDs and Schemas Not Resolved When Using loadXML Method

ID: Q235344


The information in this article applies to:
  • Microsoft Internet Explorer (Programming) version 5.0


SYMPTOMS

When using the IXMLDOMDocument::loadXML method to load XML data into the MSXML parser via a string parameter, the MSXML parser does not correctly resolve any external files such as DTDs or Schemas.

Script in a Web page will not suffer from this bug because MSHTML, Internet Explorer's HTML engine, provides a valid security site object to the MSXML parser.


CAUSE

Due to a security constraint, resolveExternals is turned off while parsing the XML data loaded with loadXML.


RESOLUTION

The easiest workaround might be to call IXMLDOMDocument::load with a URL referencing an XML file. If loading from memory is preferred, there are three alternatives that will load XML Documents from memory sources and correctly resolve all external files:

  • Attach a fake site object to the MSXML engine using the IObjectWithSite::SetSite method. See the C++ or Visual Basic examples in MORE INFORMATION below.


  • Create a custom IStream wrapper over an in-memory buffer and pass it to MSXML's IPersistStream::Load or IXMLDOMDocument::load(VARIANT(IStream*)) methods. This is the most efficient mechanism for loading MSXML.


  • Create an IStream over an HGLOBAL buffer using the CreateStreamOnHGlobal API and pass it to IPersistStream::Load or IXMLDOMDocument::load(VARIANT(IStream*)). This is less efficient than loadXML or the above technique, but is easier to code.



STATUS

Microsoft has confirmed this to be a bug in the Microsoft products listed at the beginning of this article.

This problem was corrected in Internet Explorer 5.01.


MORE INFORMATION

Following are two sections of example code that create a fake site object and attach it to an XML Document.

C++ Example

Code using this alternative should call the XMLDummySecurity method and pass the IXMLDOMDocument pointer before using it to load the XML document with loadXML.

class DummySite : public IUnknown
{
public:
    DummySite() : _ulRefCount(1) {}

public:
    virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void ** ppvObject)
    {
        if (!ppvObject)
            return E_POINTER;

        if (riid == IID_IUnknown)
        {
            this->AddRef();
            *ppvObject = (IUnknown*)this;
        }
        else
        {
            *ppvObject = NULL;
            return E_NOINTERFACE;
        }

        return S_OK;
    }

    virtual ULONG STDMETHODCALLTYPE AddRef( void)
    {
        return ++_ulRefCount;
    }

    virtual ULONG STDMETHODCALLTYPE Release( void)
    {
        ULONG ul = --_ulRefCount;
        if (!ul)
            delete this;
        return ul;
    }

protected:
    ULONG _ulRefCount;
};

HRESULT XMLDummySecurity(IXMLDOMDocument * pXMLDocument)
   {
       HRESULT hr;
       IObjectWithSite * pObjWithSite = NULL;
       if (SUCCEEDED(hr = pXMLDocument->QueryInterface(IID_IObjectWithSite, (void **)&pObjWithSite)))
       {
           DummySite * pObj = new DummySite();
           pObjWithSite->SetSite(pObj);
           pObjWithSite->Release();
           pObj->Release();
       }
       return hr;
   }
 

Visual Basic Example

Follow these steps to create a dummy security class in your project and attach it as a site to the XML Document object:
  1. Create a new text file called Objwithsite.idl and add the following code into it:
    
    [
       uuid(FC4801A3-2BA9-11CF-A229-00AA003D7353),
       version(1.0),
       helpstring("IObjectWithSite TLB")
    ]
    library IOBJWITHSITELib
    {
       [
          object,
          uuid(FC4801A3-2BA9-11CF-A229-00AA003D7352),
          pointer_default(unique)
       ]
       interface IObjectWithSite : IUnknown
       {
          typedef IObjectWithSite * LPOBJECTWITHSITE;
       
          HRESULT SetSite(
          [in] IUnknown * pUnkSite
          );
       
          HRESULT GetSite(
             [in] REFIID riid,
             [out, iid_is(riid)] void ** ppvSite);
       }
    }; 


  2. Use the MIDL utility included with the Platform SDK or Visual Studio to create a Type Library (.tlb) from this IDL file.


  3. Add a reference to the resultant type library to the XML project.


  4. Create a new empty class in the project called CDummySecurity and set its Instancing property to "PublicNotCreatable."


  5. Make sure the XML project is an ActiveX project (ActiveX EXE, ActiveX DLL, and so forth). If your existing project is a standard EXE that uses a default startup form, you'll need to add a Main procedure to your project and load the form from there.


  6. Use the following code to set the fake security object before calling loadXML on the XML Document:
    
    Dim objDummySecurity As New CDummySecurity
    Dim site As IObjectWithSite
    Set site = objXMLDoc
    site.SetSite objDummySecurity
       
    'Now you can load the document and external references will be resolved. 
    objXMLDoc.loadXML(strXMLWithDTD) 



© Microsoft Corporation 1999, All Rights Reserved.
Contributions by Jason Strayer, Microsoft Corporation

Additional query words:

Keywords : kbGrpInet kbIE500bug kbXML kbDSupport
Version : WINDOWS:5.0
Platform : WINDOWS
Issue type : kbbug


Last Reviewed: January 28, 2000
© 2000 Microsoft Corporation. All rights reserved. Terms of Use.