Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

XML Transform Shell Extension

0.00/5 (No votes)
11 Oct 2003 1  
A shell extension to transform xml files against a stylesheet

Sample Image - xmlTransformer.jpg

Introduction

When working with XML and XSLT, it becomes tedious testing changes since there is no built-in support for executing the transformation. The MSXML SDK includes an XSLT command-line utility but unless the source and transforming stylesheet are in the same directory you must enter the paths for the inputs. You could write a script, as I have done many times, but this will need to be updated each time you change inputs or outputs.

This utility takes some of the pain out of writing and testing stylesheets. The output of the transformation is saved to disk and opened in its own process using notepad. This output is overwritten each time a transformation is done so you will need to 'Save As' to keep the document before closing notepad. I decided to use notepad because a transformation does not always result in valid XML.

There are a number of great articles that cover shell extensions quite well so I won't re-hash that information. I will cover simple transformations and parse errors using the DOMDocument in MSXML4.

Using the code

To use this utility, copy and register the dll. In Explorer, right click on an XML, XSL, or XSLT file to get the 'Transform with...' option. You will be prompted for an XSL/XSLT file to do the transformation. Notepad will display the results, being valid output or parser error information.

Any valid xml text can be loaded into a DOMDocument: XML, stylesheets and schemas. I have chosen to make this functionality available only to XML and stylesheets. To make this available to other file types, update the registrar script and rebuild. The following will include this option for XML schemas.

NoRemove xsdfile{
   NoRemove Shellex{
      NoRemove ContextMenuHandlers{
         RegSvrEx = s '{737E08D6-7EEA-4AD6-B15F-373B2BCDF5B7}'
}  }  }    

The Transformation

Both input files need to be loaded into a DOMDocument before we can perform a transformation. The steps to do this are simple: create a DOMDocument object, turn off asynchronous loading, load the file and check for parse errors.

    // load the stylesheet into a DOM

    MSXML2::IXMLDOMDocument2Ptr spStyleSheet;
    spStyleSheet.CreateInstance(__uuidof(MSXML2::DOMDocument));
    spStyleSheet->put_async(VARIANT_FALSE);

    if( spStyleSheet->load(_variant_t(szStyleSheet)) == VARIANT_FALSE)
    {
        ReportParseError(spStyleSheet->parseError, szStyleSheet);
        return S_FALSE;
    }

If everything goes well, the XML is transformed using the transformNode method of the DOMDocument and the results are displayed. If there are parse errors, it is helpful to have as much information as we can.

Sample screenshot of parse error output

This is accomplished in ReportParseError. The DOMDocument exposes an interface to the parseError object. With this, we can get all error information, including the unparsed source text. I use the line and linepos properties to get a snippet of text surrounding the point where the parser stopped.

    CString src = pParseError->srcText.GetBSTR();

    int badChar = 0;
    int maxLen = 0;

    if(src.GetLength() < 120)
        maxLen = src.GetLength();
    else
    {
        // move to the correct line

        for(int x=0; x < pParseError->line - 1; x++)
            badChar = src.Find(_T("\n"), badChar);

        // get 120 characters starting at 60 before error

        badChar -= (60 - pParseError->linepos);  
        maxLen = 120;
    }
    .
    .
    .
    src.Mid(badChar, maxLen)    

The parser will report an error on the first character found to be invalid. In most cases, this is a symptom of the real issue so we want to display text prior to that point. Something interesting to note is that srcTxt doesn't always contain all of the source. The SDK states that "this property returns an empty string if the error is caused by XML that is not well-formed and cannot be assigned to a specific line", but I had cases where it returns a partial string that doesn't contian enough text to see the actual error.

Points of Interest

This Shell Extension dll is an ATL project written using Visual Studio .NET and compiled for Unicode. To rebuild for ASCII, you will need to make changes using the conversion macros in order to interact with _bstr_t.

MSXML4 is a required dependency and can be downloaded, along with the SDK from MSDN.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here