Click here to Skip to main content
Click here to Skip to main content

XML Transform Shell Extension

By , 11 Oct 2003
 

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

About the Author

Doug Mitchell
Web Developer
United States United States
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralXML with Crystal ReportsussAnonymous6 Apr '05 - 5:42 
QUES: when create the Crystal report using the XML file, i am unable to to set the table hint and row hint pl clear my doubts
Table hint:???
Row hint: ???

<?xml version="1.0" encoding="utf-8" ?>
<Cube StrategyDesc="Sed" StrategyName="asd" DataEntry="E" EntityName="ALDI Entity"
     EntityDesc="ALDI Entity Descrpiton">
   <Desc/>
 
- <LevelNode Name="Expectations" LvlID="1" Edit="False">
   <Desc>customer.</Desc>
 
- <LevelNode Name="Features" LvlID="1.1" Edit="False">
   <Desc>services.</Desc>
 
- <LevelNode Name="Mix" LvlID="1.1.1" Edit="True">
   <Desc>customers.</Desc>
 
- <LevelNode Name="High Quality" LvlID="1.1.1.1" Edit="False" Projection="1" Key="Advantage" Relation="Collaborative">
<Desc>The firm </Desc>
   </LevelNode>
   </LevelNode>
   </LevelNode>
   </LevelNode>
   </Cube>
GeneralCan't build under VS.NET 2003memberDoug Schmidt14 Oct '03 - 4:54 
I can't build xmlTransformer under VS.NET 2003. I've tried building both solutions in the ZIP archive, and I get the same results, shown below.
 
By the way, why *are* there two nearly-identical-but-not-quite solutions in the source code, one rooted at .\*, and the other rooted at src\*. I don't get it.
 
Here are my build results from VS.NET 2003:
Compiling...
stdafx.cpp
Compiling...
xmlTransformerShlExt.cpp
d:\DougTools\xmlTransformer\xmlTransformerShlExt.h(49) : error C2787: 'IContextMenu' : no GUID has been associated with this object
d:\DougTools\xmlTransformer\xmlTransformerShlExt.h(49) : error C2440: 'initializing' : cannot convert from 'DWORD_PTR' to 'const IID *'
Conversion from integral type to pointer type requires reinterpret_cast, C-style cast or function-style cast
d:\DougTools\xmlTransformer\xmlTransformerShlExt.h(49) : error C2440: 'initializing' : cannot convert from 'ATL::_ATL_CREATORARGFUNC (__stdcall *)' to 'DWORD_PTR'
This conversion requires a reinterpret_cast, a C-style cast or function-style cast
 
I can't seem to find any definition of IContextMenu anywhere in the platform SDK. What am I missing?
 
Doug Schmidt
GeneralRe: Can't build under VS.NET 2003memberDoug Mitchell14 Oct '03 - 15:41 
Doug Schmidt wrote:
d:\DougTools\xmlTransformer\xmlTransformerShlExt.h(49) : error C2787: 'IContextMenu' : no GUID has been associated with this object
 
IContextMenu is defined in shlobj.h. This file is different in the VS.Net distribution than that in the Platform SDK. I had this same problem some time ago and could only get past it by downloading the SDK. After installing the SDK, point the VC++ directories to the include and lib directories.
 

Sorry for duped source code. That is my mistake zipping up the files. I'll clean up the source and update the zip.

GeneralSuggestionsmemberPatje13 Oct '03 - 3:56 
Although I don't use much XML myself [yet], I have some suggestions.
 
First of all, I couldn't install it. I copied the file to my disk but registering it (that's with regsvr32, isn't it?) failed: "The specified module could not be found".
 
Second, right-clicking a file is cool, but then having to select the XSL file manually looks cumbersome compared with a simple right-click (I suppose you use the standard file selection dialog, but I couldn't verify that, see first point).
Why not let the user select two files: one XML, one XSL file and then right-clicking on them.
 
Even better, why not allow the user to select multiple XML files and multiple XSL files and showing the results of all combinations (all XML x all XSL files) in e.g. a tabbed window.
 
Dragging an XML or XSL file to the window where the result of the transformation is shown can be cool too.
 
Nevertheless, I think the idea is good. A 4 from me.
 
Enjoy life, this is not a rehearsal !!!
 
My Articles:
- Implementing a Subject/Observer pattern with templates
- Different ways of writing class factories
- AutoRunner: a template class to automatically run start- and cleanup-code in code blocks
GeneralRe: SuggestionsmemberDoug Mitchell13 Oct '03 - 5:20 
Thanks for the input.
 
I'm not sure why you couldn't register the dll on your machine. What OS are you using? I have tested this on win2K pro and XP home edition and didn't have any issues.
 
While your suggestions are valid, I needed a way to quickly perform a transformation when writing stylesheets. This simple solution allows me to concentrate on the stylesheet.
 
Patje wrote:
Why not let the user select two files: one XML, one XSL file and then right-clicking on them.
 
The problem with this is that we can use a stylesheet to transform a stylesheet. It would be difficult to distinguish which is the file to be transformed since the order of selection is not known.
 


GeneralRe: SuggestionsmemberPatje13 Oct '03 - 5:23 
I ran the Dependency Walker on it and it told me the DLL referred to ATL70.DLL, which I haven't found on my machine (I'm using Visual Studio .Net which has ATL71.DLL). Maybe that's the problem.
 
Don't worry about it, I don't really need the shell extension at this moment.
Maybe later.
 
Enjoy life, this is not a rehearsal !!!
 
My Articles:
- Implementing a Subject/Observer pattern with templates
- Different ways of writing class factories
- AutoRunner: a template class to automatically run start- and cleanup-code in code blocks
GeneralRe: Suggestionsmembermemswiler7 Apr '04 - 0:46 
An enhancement to your extension would be a drag-n-drop solution where the dragged file is transformed with the file it is dropped onto ... all automagically Smile | :)

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130516.1 | Last Updated 12 Oct 2003
Article Copyright 2003 by Doug Mitchell
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid