Sample 2: Parsing a CDF File for Specific Tags

//*******************************
// XML OM test code
//
// *******************************

#include <windows.h>
#include <windowsx.h>
#include <stdlib.h>
#include <stdio.h>
#include <io.h>
#include <urlmon.h>
#include <hlink.h>
#include <dispex.h>
#include "mshtml.h"
#include "msxml.h"

#define ASSERT(x)  if(!(x)) DebugBreak()
#define CHECK_ERROR(cond, err) if (!(cond)) {pszErr=(err); goto done;}
#define SAFERELEASE(p) if (p) {(p)->Release(); p = NULL;} else ;


#define WALK_ELEMENT_COLLECTION(pCollection, pDispItem) \
    {\
        long length;\
        \
        if (SUCCEEDED(pCollection->get_length(&length)) && length > 0)\
        {\
            VARIANT vIndex, vEmpty;\
            vIndex.vt = VT_I4;\
            vEmpty.vt = VT_EMPTY;\
                                 \
            for (long i=0; i<length; i++)\
            {\
                vIndex.lVal = i;\
                IDispatch *pDispItem = NULL;\
                if (SUCCEEDED(pCollection->item(vIndex, vEmpty, &pDispItem)))\
                {

#define END_WALK_ELEMENT_COLLECTION(pDispItem) \
                    pDispItem->Release();\
                }\
            }\
        }\
    }


void Indent(int indent)
{
    while (indent-->0)
    {
        printf("   ");
    }
}

void Output(int indent, const char *format, ...)
{
    va_list argptr;

    va_start(argptr, format);

    Indent(indent);

     (void)vprintf(format, argptr);
}

void OutputLn(int indent, const char *format, ...)
{
    va_list argptr;

    va_start(argptr, format);

    printf("\n");

    Indent(indent);

    (void)vprintf(format, argptr);
}

//
// Dump an element attribute member if present.
//
void DumpAttrib(IXMLElement *pElem, BSTR bstrAttribName)
{
    VARIANT vProp;
    
    VariantInit(&vProp);

    if (SUCCEEDED(pElem->getAttribute(bstrAttribName, &vProp)))
    {
        if (vProp.vt == VT_BSTR)
        {
            printf(" %S=\"%S\"", bstrAttribName, vProp.bstrVal);
        }
        VariantClear(&vProp);
    }
}

//
// Helper routine to quickly find out if this is a named element
// currently only used to improve the format of the output.
//
BOOL IsNamedElement(IXMLElement *pElem)
{
    BSTR bstrName;

    if (SUCCEEDED(pElem->get_tagName(&bstrName)))
    {
        if (bstrName)
        {
            SysFreeString(bstrName);
            return TRUE;
        }
    }
    return FALSE;
}

//
// Returns TRUE if this element had children.
//
void DumpElement
(
    IXMLElement *pElem, // the XML element to dump
    int indent          // indentation level
)
{
    BSTR bstrTagName = NULL;
    BSTR bstrContent = NULL;
    IXMLElementCollection * pChildren;
    //
    // Note this nonsense with children and grandchildren is just so we get
    // nicely formatted output!
    //
    BOOL fHadNamedChild = FALSE;

    //
    // Dump the name of the NODE.
    //
    pElem->get_tagName(&bstrTagName);
    if (bstrTagName) 
    {       
        //
        // Special case the output of the special tags.
        //
        if (wcscmp(bstrTagName, L"XML") == 0)
        {
            Output(indent, "<\?XML version=\"1.0\"\?>\n");
            SysFreeString(bstrTagName);
            return;
        }
        else if (wcscmp(bstrTagName, L"DOCTYPE") == 0)
        {
            Output(indent,
              "<!DOCTYPE CHANNEL SYSTEM \"http://www.w3.org/Channel.dtd\">\n");
            SysFreeString(bstrTagName);
            return;
        }
        else
        {
            OutputLn(indent, "<%S", bstrTagName);
        }
    }

    //
    // Dump the attributes if present.
    //
    DumpAttrib(pElem, L"VALUE");
    DumpAttrib(pElem, L"HREF");
    DumpAttrib(pElem, L"HOUR");
    DumpAttrib(pElem, L"DAY");
    DumpAttrib(pElem, L"IsClonable");
    DumpAttrib(pElem, L"Type");

    //
    // Dump the text contents if present.
    //
    XMLELEM_TYPE xmlElemType;
    if (SUCCEEDED(pElem->get_type((long *)&xmlElemType)))
    {
        if (xmlElemType == XMLELEMTYPE_TEXT)
        {
            if (SUCCEEDED(pElem->get_text(&bstrContent)))
            {
                if (bstrContent)
                {
                    printf("%S", bstrContent);
                    SysFreeString(bstrContent);
                }
            }
        }
    }

    //
    // Find the children if they exist.
    //
    if (SUCCEEDED(pElem->get_children(&pChildren)) && pChildren)
    {
        //
        // Close the tag if present but with "children present" closure 
        // that is use > instead of />.
        //
        if (bstrTagName) printf(">");

        WALK_ELEMENT_COLLECTION(pChildren, pDisp)
        {
            //
            // pDisp will iterate over an IDispatch for each item in the collection.
            //
            IXMLElement * pChild;
            if (SUCCEEDED(pDisp->QueryInterface(
                                     IID_IXMLElement, (void **)&pChild)))
            {
                if (IsNamedElement(pChild))
                    fHadNamedChild = TRUE;

                //
                // Recursively dump children.
                //
                DumpElement(pChild, indent+1);

                pChild->Release();
            }
        }
        END_WALK_ELEMENT_COLLECTION(pDisp);
        pChildren->Release();

        //
        // Display closing tag.
        //
        if (bstrTagName)
        {
            if (fHadNamedChild)
            {
                OutputLn(indent, "</%S>", bstrTagName);
            }
            else
            {
                printf("</%S>", bstrTagName);
            }
        }
    }
    else
    {
        //
        // No children so terminate tag on same line.
        //
        if (bstrTagName) printf("/>");
    }

    if (bstrTagName)
        SysFreeString(bstrTagName);
}

int MyStrToOleStrN(LPOLESTR pwsz, int cchWideChar, LPCTSTR psz)
{
    int i;
    i=MultiByteToWideChar(CP_ACP, 0, psz, -1, pwsz, cchWideChar);
    if (!i)
    {
        //DBG_WARN("MyStrToOleStrN string too long; truncated");
        pwsz[cchWideChar-1]=0;
    }
    else
        ZeroMemory(pwsz+i, sizeof(OLECHAR)*(cchWideChar-i));

    return i;
}

int _cdecl main (int argc, char **argv)
{
    PSTR pszErr = NULL;
    IXMLDocument           *pDoc = NULL;
    IStream                *pStm = NULL;
    IPersistStreamInit     *pPSI = NULL;
    IXMLElement            *pElem = NULL;
    TCHAR                  buf[MAX_PATH];
    TCHAR                  *pszURL;
    WCHAR                  *pwszURL=NULL;
    BSTR                   pBURL=NULL;

    HRESULT hr;

    //
    // Check usage.
    //
    if (argc != 2)
    {
        fprintf (stderr, "Usage:   omtest2 URL\n");
        fprintf (stderr, "Eg omtest2 c:\\nt\\private\\inet\\xml\\test\\channel.uni\n");
        fprintf (stderr, "or omtest2 http://ohserv/users/julianj/channel.xml\n");
        exit (1);
    }

    //
    // HACK if passed in a file name, expand if it doesn't look like a URL.
    //
    if (CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, argv[1], 7, "http://", 7) == CSTR_EQUAL)
    {
        pszURL = argv[1];
    }
    else
    {
        pszURL = buf;
        GetFullPathName(argv[1], MAX_PATH, pszURL, NULL);
    }

    hr = CoInitialize(NULL);
    ASSERT(SUCCEEDED(hr));

    //
    // Create an empty XML document.
    //
    hr = CoCreateInstance(CLSID_XMLDocument, NULL, CLSCTX_INPROC_SERVER,
                                IID_IXMLDocument, (void**)&pDoc);

    CHECK_ERROR (pDoc, "CoCreateInstance Failed");

    //
    // Synchronously create a stream on a URL.
    //
    //hr = URLOpenBlockingStream(0, pszURL, &pStm, 0,0);    
    //CHECK_ERROR(SUCCEEDED(hr) && pStm, "Couldn't open stream on URL")
    
    //
    // Get the IPersistStreamInit interface to the XML doc.
    //
    //hr = pDoc->QueryInterface(IID_IPersistStreamInit, (void **)&pPSI);
    //CHECK_ERROR(SUCCEEDED(hr), "QI for IPersistStreamInit failed");

    //
    // Init the XML doc from the stream.
    //
    //hr = pPSI->Load(pStm);
    
    pwszURL = (WCHAR *)LocalAlloc(LMEM_FIXED, ((sizeof(WCHAR))*(strlen(pszURL) + 2)));
    CHECK_ERROR(pwszURL, "Mem Alloc Failure");

    hr = MyStrToOleStrN(pwszURL, (strlen(pszURL) + 1), pszURL);
    CHECK_ERROR(SUCCEEDED(hr), "Failed to convert to UNICODE");
    pBURL = SysAllocString(pwszURL);
    CHECK_ERROR(pBURL, "Mem Alloc Failure");
    LocalFree(pwszURL);

    hr = pDoc->put_URL(pBURL);
    
    if (SUCCEEDED(hr))
    {
        //
        // Now walk the OM and look at interesting things.
        //
        hr = pDoc->get_root(&pElem);
        CHECK_ERROR(SUCCEEDED(hr), "Failed to get_root of XML object");

        //
        // Dump the top level meta nodes of the document.
        //
        BSTR bstrVal;
        hr = pDoc->get_version(&bstrVal);
        if(FAILED(hr) || !bstrVal)
        {
            bstrVal = SysAllocString(L"1.0");
        }
        // 
        Output(0, "<\?XML version=\"%S\" ",bstrVal);
        SysFreeString(bstrVal);
        bstrVal = NULL;
        
        hr = pDoc->get_encoding(&bstrVal);
        if(SUCCEEDED(hr) && bstrVal)
        {
            Output(0, "encoding=\"%S\" ",bstrVal);
            SysFreeString(bstrVal);
        }
        Output(0, "\?>\n");

        //
        // Look for doctype information.
        //

        // Disabled till DavidSch makes a fix
        /*
        bstrVal = NULL;
        hr = pDoc->get_doctype(&bstrVal);
        if(SUCCEEDED(hr) && bstrVal)
        {   
            Output(0, "<!DOCTYPE %S>",bstrVal); 
            SysFreeString(bstrVal);

        }
        */
        //
        // Dump the root element and all children of the XML object.
        //
        
        DumpElement(pElem, 0); // -1 to counteract nameless outer container
    }
    else
    {
        //
        // Failed to parse stream, output error information.
        //
        IXMLError *pXMLError = NULL ;
        XML_ERROR xmle;
    
        hr = pDoc->QueryInterface(IID_IXMLError, (void **)&pXMLError);
        CHECK_ERROR(SUCCEEDED(hr), "Couldn't get IXMLError");
    
        ASSERT(pXMLError);
    
        hr = pXMLError->GetErrorInfo(&xmle);
        SAFERELEASE(pXMLError);
        CHECK_ERROR(SUCCEEDED(hr), "GetErrorInfo Failed");
    
        printf("%s: Error on line %d. Found %S while expecting %S\r\n",
                argv[0],
                xmle._nLine,
                xmle._pszFound,
                xmle._pszExpected);
    
        SysFreeString(xmle._pszFound);
        SysFreeString(xmle._pszExpected);
        SysFreeString(xmle._pchBuf);
    }

done: // Clean up.
    //
    // Release any used interfaces.
    //
    SAFERELEASE(pPSI);
    SAFERELEASE(pStm);
    SAFERELEASE(pElem);
    SAFERELEASE(pDoc);
    SysFreeString(pBURL);
    if (pszErr)
        fprintf (stderr, "%s, last error %d\n", pszErr, GetLastError());
    return 0;
}



© 1999 Microsoft Corporation. All rights reserved. Terms of use.