XML Spy Plugins

xml spy
XML Spy plug-ins

XMLSPY 5 allows you to create your own plug-ins and integrate them into XMLSPY 5.

Use plug-ins to:
· Configure your version of XMLSPY 5, add commands through menus, icons, buttons etc.
· Run your specific code within XMLSPY 5 with access to the XMLSPY 5 API

Top Next

© 2002 Altova


Registration of IDE PlugIns

Registration of IDE plug-ins

XMLSPY 5 scans a specific key in the Registry of the user each time the application starts:

HKEY_CURRENT_USER\Software\Altova\XML Spy\PlugIns

All values of this key are treated as plug-ins and should conform to a specific format. The name of the entry is the ProgID and the data is equal to the CLSID of the component. The type of the value must be REG_SZ.

For each PlugIn the user adds to XMLSPY 5 using the "Customize" dialog, a new value is created for this key. You can also add these values from outside of XMLSPY 5 using any other method of writing to the registry. No additional information is necessary to register a plug-in. The new plug-in will be activated the next time XMLSPY 5 is launched.

Previous Top Next


Configuration XML

Configuration XML

The IDE plug-in allows you to change the user interface (UI) of XMLSPY 5. This is done by describing each separate modification using an XML data stream. The XML configuration is passed to XMLSPY 5 using the GetUIModifications method of the IXMLSpyPlugIn interface.

The XML file containing the UI modifications for the IDE PlugIn, must have the following structure:

<ConfigurationData>
<ImageFile>path to image file</ImageFile>
<Modifications>
<Modification>
...
</Modification>
...
</Modifications>
</ConfigurationData>

You can define icons or toolbar buttons for the new menu items which are added to the UI of XMLSPY 5 by the plug-in. The path to the file containing the images is set using the ImageFile element. Each image must be 16 x 16 pixels using max. 256 colors. The image references must be arranged from left to right in a single (<ImageFile>...) line. The rightmost image index value, is zero.

The Modifications element can have any number of Modification child elements. Each Modification element defines a specific change to the standard UI of XMLSPY 5. Starting with version 4.3, it is also possible to remove UI elements from XMLSPY 5.

Structure of Modification elements
All Modification elements consist of the following two child elements:

<Modification>
<Action>type of action</Action>
<UIElement type="type of UI element">
</UIElement>
</Modification>

Valid values for the Action element are:

Add - to add the following UI element to XMLSPY 5
Hide - to hide the following UI element in XMLSPY 5
Remove - to remove the UI element from the "Commands" list box, in the customize dialog

You can combine values of the Action element e.g. "Hide Remove"

The UIElement element describes any new, or existing UI element for XMLSPY 5. Possible elements are currently: new toolbars, buttons, menus or menu items. The type attribute, defines which UI element is described by the XML element.

Common UIElement children
The ID and Name elements are valid for all different types of XML UIElement fragments. It is however possible, to ignore one of the values for a specific type of UIElement e.g. Name is ignored for a separator.

<ID></ID>
<Name></Name>

If UIElement describes an existing element of the UI, the value of the ID element is predefined by XMLSPY 5. Normally these ID values are not known to the public. If the XML fragment describes a new part of the UI, then the ID is arbitrary and the value should be less than 1000.
The Name element sets the textual value. Existing UI elements can be identified just by name, for e.g. menus and menu items with associated sub menus. For new UI elements, the Name element sets the caption e.g. the title of a toolbar, or text for a menu item.

Toolbars and Menus
To define a toolbar its necessary to specify the ID and/or the name of the toolbar. An existing toolbar can be specified using only the name, or by the ID if it is known. To create a new toolbar both values must be set. The type attribute must be equal to "ToolBar".

<UIElement type="ToolBar">
<ID>1</ID>
<Name>TestPlugIn</Name>
</UIElement>

To specify an XMLSPY 5 menu you need two parameters:
· The ID of the menu bar which contains the menu. If no XML documents are open in the main window, the menu bar ID is 128. If one or more XML documents are open, the menu bar ID is 129.
· The menu name. Menus do not have an associated ID value. The following example defines the "Edit" menu of the menu bar which is active, when at least one XML document is open:

<UIElement type="Menu">
<ID>129</ID>
<Name>Edit</Name>
</UIElement>

An additional element is used if you want to create a new menu. The Place element defines the position of the new menu in the menu bar:

<UIElement type="Menu">
<ID>129</ID>
<Name>PlugIn Menu</Name>
<Place>12</Place>
</UIElement>

A value of -1 for the Place element sets the new button or menu item at the end of the menu or toolbar.

Commands
If you add a new command, through a toolbar button or a menu item, the UIElement fragment can contain any of these sub elements:

<MacroName></MacroName>
<Info></Info>
<ImageID></ImageID>

If MacroName is specified, XMLSPY 5 searches for a macro with the same name in the scripting environment and executes it each time this command is processed. The Info element contains a short description string which is displayed in the status bar, when the mouse pointer is over the associated command (button or menu item). ImageID defines the index of the icon the external image file. Please note that all icons are stored in one image file.

To define a toolbar button create an UIElement with this structure:

<UIElement type="ToolBarItem">
<!--don't reuse local IDs even the commands do the same-->
<ID>5</ID>
<Name>Open file from repository...</Name>
<!--set Place to -1 if this is the first button to be inserted-->
<Place>-1</Place>
<ImageID>0</ImageID>
<ToolBarID>1</ToolBarID>
<!--instead of the toolbar ID the toolbar name could be used-->
<ToolBarName>TestPlugIn</ToolBarName>
</UIElement>

Additional elements to declare a toolbar button are Place, ToolBarID and ToolBarName. ToolBarID and ToolBarName are used to identify the toolbar which contains the new or existing button. The textual value of ToolBarName is case sensitive. The (UIElement) type attribute must equal "ToolBarItem".

To define a menu item, the elements MenuID, Place and Parent are available in addition to the standard elements used to declare a command. MenuID can be either 128 or 129. Please see "Toolbars and Menus" for more information on these values.

The Parent element is used to identify the menu where the new menu entry should be inserted. As sub menu items have no unique Windows ID, we need some other way to identify the parent of the menu item.

The value of the Parent element is a path to the menu item.
The text value of the Parent element, must equal the parent menu name of the submenu, where the submenu name is separated by a colon. If the menu has no parent, because its not a submenu, add a colon to the beginning of the name. The type attribute must be set to "MenuItem". Example for an UIElement defining a menu item:

<UIElement type="MenuItem">
<!--the following element is a local command ID-->
<ID>3</ID>
<Name>Open file from repository...</Name>
<Place>-1</Place>
<MenuID>129</MenuID>
<Parent>:PlugIn Menu</Parent>
<ImageID>0</ImageID>
</UIElement>

XMLSPY 5 version 4.4 makes it possible to add toolbar separators and menus if the value of the ID element is set to 0.


ATL sample files

ATL sample files

The following pages show how to create a simple XMLSPY 5 IDE plug-in DLL using ATL. To completely build the DLL its necessary to know about ATL and the wizards that generate new ATL objects as well as VisualStudio.

To access the API the implementation imports the Type Library of XMLSPY 5. The code reads various properties and calls methods using the smart pointers provided by the #import statement.

In addition, the sample code uses the MFC class CString and the ATL conversion macros such as W2T.

At a glance the steps to create an ATL DLL are as follows:

1. Open VisualStudio and select "New..." from the "File" menu.
2. Select "ATL COM AppWizard" and type in a project name.
3. Select "Support for MFC" if you want to use MFC classes, or if you want to create a project for the sample code.

Having created the project files you can add an ATL object to implement the IXMLSpyPlugIn interface:

1. Select "New ATL Object..." from the "Insert" menu.
2. Select "Simple Object" from the wizard and hit "Next".
3. Type in a name for the object.
4. On the "Attributes" tab, select "Custom" for the type of the interface, and disable Aggregation.

These steps produce the skeleton code for the implementation of the IDE plug-in interface. Please see the following pages on how to modify the code and achieve some basic functionality.


Interface description (IDL)

Interface description (IDL)

Having created the ATL object, you then need to implement the IDE plug-in interface of XMLSPY 5. The IDL file of the project contains a new entry for a coclass. Instead of using the predefined custom interface, you can insert the definition of the IXMLSpyPlugIn interface.

The IDL must also contain the definition of the SPYUpdateAction enumeration. Also, replace the generated interface name, (created by the wizard) with "IXMLSpyPlugIn" in the coclass declaration. The IDL should then look something like this:

import "oaidl.idl";
import "ocidl.idl";

   typedef enum {
      spyEnable = 1,
      spyDisable = 2,
      spyCheck = 4,
      spyUncheck = 8
   } SPYUpdateAction;

   [
      odl,
      uuid(88F2A622-4B7E-42CD-8D04-3C0E5389DD85),
      helpstring("IXMLSpyPlugIn Interface")
   ]
   interface IXMLSpyPlugIn : IUnknown
      {
         HRESULT _stdcall OnCommand([in] long nID, [in] IDispatch* pXMLSpy);

         HRESULT _stdcall OnUpdateCommand([in] long nID, [in] IDispatch* pXMLSpy, [out, retval] SPYUpdateAction* pAction);

         HRESULT _stdcall OnEvent([in] long nEventID, [in] SAFEARRAY(VARIANT)* arrayParameters, [in] IDispatch* pXMLSpy, [out, retval] VARIANT* pReturnValue);

         HRESULT _stdcall GetUIModifications([out, retval] BSTR* pModificationsXML);

         HRESULT _stdcall GetDescription([out, retval] BSTR* pDescription);
      };

 [
   uuid(24FE0D1B-3FC0-494E-B36E-1D4CE412B014),
   version(1.0),
   helpstring("XMLSpyIDEPlugInDLL 1.0 Type Library")
 ]
 library XMLSPYIDEPLUGINDLLLib
 {
   importlib("stdole32.tlb");
   importlib("stdole2.tlb");

   [
      uuid(3800E791-7F6B-4ACD-9E32-2AC184444501),
      helpstring("XMLSpyIDEPlugIn Class")
   ]
   coclass XMLSpyIDEPlugIn
   {
      [default] interface IXMLSpyPlugIn;
   };
};


Class definition

Class definition

In the class definition of the ATL object, several changes must be made. The class has to derive from IXMLSpyPlugIn, the "Interface Map" needs an entry for IXMLSpyPlugIn, and the methods of the IDE plug-in interface must be declared:

#ifndef __XMLSPYIDEPLUGIN_H_
#define __XMLSPYIDEPLUGIN_H_

#include "resource.h"       // main symbols

/////////////////////////////////////////////////////////////////////////////
// CXMLSpyIDEPlugIn
class ATL_NO_VTABLE CXMLSpyIDEPlugIn :
   public CComObjectRootEx<CComSingleThreadModel>,
   public CComCoClass<CXMLSpyIDEPlugIn, &CLSID_XMLSpyIDEPlugIn>,
   public IXMLSpyPlugIn
{
public:
   CXMLSpyIDEPlugIn()
   {
   }

DECLARE_REGISTRY_RESOURCEID(IDR_XMLSPYIDEPLUGIN)
DECLARE_NOT_AGGREGATABLE(CXMLSpyIDEPlugIn)

DECLARE_PROTECT_FINAL_CONSTRUCT()

BEGIN_COM_MAP(CXMLSpyIDEPlugIn)
   COM_INTERFACE_ENTRY(IXMLSpyPlugIn)
END_COM_MAP()

// IXMLSpyIDEPlugIn
public:
   virtual HRESULT _stdcall OnCommand(long nID, IDispatch* pXMLSpy);

   virtual HRESULT _stdcall OnUpdateCommand(long nID, IDispatch* pXMLSpy, SPYUpdateAction* pAction);

   virtual HRESULT _stdcall OnEvent(long nEventID, SAFEARRAY **arrayParameters, IDispatch* pXMLSpy, VARIANT* pReturnValue);

   virtual HRESULT _stdcall GetUIModifications(BSTR* pModificationsXML);

   virtual HRESULT _stdcall GetDescription(BSTR* pDescription);
};

#endif //__XMLSPYIDEPLUGIN_H_


Implementation

Implementation

The code below shows a simple implementation of an XMLSPY 5 IDE plug-in which adds a menu item and a separator (available with XMLSPY 5 4.4) to the Tools menu. Inside the OnUpdateCommand() method, the new command is only enabled when the active document is displayed using the Grid View. The command searches for the XML element which has the current focus, and opens any URL starting with "http://", from the textual value of the element.

#import "XMLSpy.tlb"
using namespace XMLSpyLib;

/////////////////////////////////////////////////////////////////////////////
// CXMLSpyIDEPlugIn

HRESULT CXMLSpyIDEPlugIn::OnCommand(long nID, IDispatch* pXMLSpy)
{
   USES_CONVERSION;

   if(nID == 1)   {
      IApplicationPtr   ipSpyApp;

      if(pXMLSpy)   {
         if(SUCCEEDED(pXMLSpy->QueryInterface(__uuidof(IApplication),(void **)&ipSpyApp)))   {
            IDocumentPtr   ipDocPtr = ipSpyApp->ActiveDocument;

            // we assume that grid view is active
            if(ipDocPtr)   {
               IGridViewPtr   ipGridPtr = ipDocPtr->GridView;

               if(ipGridPtr)   {
                  IXMLDataPtr      ipXMLData = ipGridPtr->CurrentFocus;

                  CString   strValue = W2T(ipXMLData->TextValue);

                  if(!strValue.IsEmpty() && (strValue.Left(7) == _T("http://")))
                     ::ShellExecute(NULL,"open",T2A((LPTSTR)(LPCTSTR)strValue),NULL,NULL,SW_SHOWNORMAL);
               }
            }
         }
      }
   }

   return S_OK;
}

HRESULT CXMLSpyIDEPlugIn::OnUpdateCommand(long nID, IDispatch* pXMLSpy, SPYUpdateAction* pAction)
{
   *pAction = spyDisable;

   if(nID == 1)   {
      IApplicationPtr   ipSpyApp;

      if(pXMLSpy)   {
         if(SUCCEEDED(pXMLSpy->QueryInterface(__uuidof(IApplication),(void **)&ipSpyApp)))   {
            IDocumentPtr   ipDocPtr = ipSpyApp->ActiveDocument;

            // only enable if grid view is active
            if((ipDocPtr != NULL) && (ipDocPtr->CurrentViewMode == spyViewGrid))
               *pAction = spyEnable;
         }
      }
   }

   return S_OK;
}

HRESULT CXMLSpyIDEPlugIn::OnEvent(long nEventID, SAFEARRAY **arrayParameters, IDispatch* pXMLSpy, VARIANT* pReturnValue)
{
   return S_OK;
}

HRESULT CXMLSpyIDEPlugIn::GetUIModifications(BSTR* pModificationsXML)
{
   CComBSTR   bstrMods = _T("
            <ConfigurationData>                     \
               <Modifications>                     \
                  <Modification>                  \
                     <Action>Add</Action>            \
                     <UIElement type=\"MenuItem\">         \
                        <ID>1</ID>               \
                        <Name>Open URL...</Name>      \
                        <Place>0</Place>            \
                        <MenuID>129</MenuID>         \
                        <Parent>:Tools</Parent>         \
                     </UIElement>               \
                  </Modification>                  \
                  <Modification>                  \
                     <Action>Add</Action>            \
                     <UIElement type=\"MenuItem\">         \
                        <ID>0</ID>               \
                        <Place>1</Place>            \
                        <MenuID>129</MenuID>         \
                        <Parent>:Tools</Parent>         \
                     </UIElement>               \
                  </Modification>                  \
               </Modifications>                     \
            </ConfigurationData>");

   return bstrMods.CopyTo(pModificationsXML);
}

HRESULT CXMLSpyIDEPlugIn::GetDescription(BSTR* pDescription)
{
   CComBSTR   bstrDescr = _T("ATL C++ XMLSpy IDE PlugIn;This PlugIn demonstrates the implementation of a simple ATL DLL as a IDE PlugIn for XMLSpy.");
   return bstrDescr.CopyTo(pDescription);
}


IXMLSpyPlugIn

See also

Methods

OnCommand
OnUpdateCommand
OnEvent
GetUIModifications
GetDescription

Description
If a DLL is added to XMLSPY 5 as an IDE plug-in, it is necessary that the component implements the IXMLSpyPlugIn interface, for it to be recognized as a plug-in.


OnCommand

IXMLSpyPlugIn.OnCommand

See also

Declaration: OnCommand(nID as long, pXMLSpy as IDispatch)

Description
The OnCommand() method of the interface implementation, is called each time a command added by the the IDE plug-in (menu item or toolbar button) is processed. nID stores the command ID defined by the ID element of the respective UIElement.

pXMLSpy holds a reference to the dispatch interface of the Application object of XMLSPY 5.
Example:

Public Sub IXMLSpyPlugIn_OnCommand(ByVal nID As Long, ByVal pXMLSpy As Object)
    If (Not (pXMLSpy Is Nothing)) Then
        Dim objDlg
        Dim objDoc As XMLSpyLib.Document
        Dim objSpy As XMLSpyLib.Application
        Set objSpy = pXMLSpy

        If nID = 3 Or nID = 5 Then
            Set objDlg = CreateObject("MSComDlg.CommonDialog")
            objDlg.Filter = "XML Files (*.xml)|*.xml|All Files (*.*)|*.*||"
            objDlg.FilterIndex = 1
            objDlg.ShowOpen

            If Len(objDlg.FileName) > 0 Then
                Set objDoc = objSpy.Documents.OpenFile(objDlg.FileName, False)
                Set objDoc = Nothing
            End If
        End If

        If nID = 4 Or nID = 6 Then
            Set objDlg = CreateObject("MSComDlg.CommonDialog")
            objDlg.Filter = "All Files (*.*)|*.*||"
            objDlg.Flags = cdlOFNPathMustExist
            objDlg.ShowSave

            If Len(objDlg.FileName) > 0 Then
                Set objDoc = objSpy.ActiveDocument

                If Not (objDoc Is Nothing) Then
                    objDoc.SetPathName objDlg.FileName
                    objDoc.Save
                    Set objDoc = Nothing
                End If
            End If
        End If

        Set objSpy = Nothing
    End If
End Sub


OnUpdateCommand

IXMLSpyPlugIn.OnUpdateCommand

See also

Declaration: OnUpdateCommand(nID as long, pXMLSpy as IDispatch) as SPYUpdateAction

Description
The OnUpdateCommand() method is called each time the visible state of a button or menu item needs to be set. nID stores the command ID defined by the ID element of the respective UIElement.

pXMLSpy holds a reference to the dispatch interface of the Application object.

Possible return values to set the update state are:

spyEnable = 1
spyDisable = 2
spyCheck = 4
spyUncheck = 8

Example:

Public Function IXMLSpyPlugIn_OnUpdateCommand(ByVal nID As Long, ByVal pXMLSpy As Object) As SPYUpdateAction
    IXMLSpyPlugIn_OnUpdateCommand = spyDisable

    If (Not (pXMLSpy Is Nothing)) Then
        Dim objSpy As XMLSpyLib.Application
        Set objSpy = pXMLSpy

        If nID = 3 Or nID = 5 Then
            IXMLSpyPlugIn_OnUpdateCommand = spyEnable
        End If
        If nID = 4 Or nID = 6 Then
            If objSpy.Documents.Count > 0 Then
                IXMLSpyPlugIn_OnUpdateCommand = spyEnable
            Else
                IXMLSpyPlugIn_OnUpdateCommand = spyDisable
            End If
        End If
    End If
End Function


OnEvent

IXMLSpyPlugIn.OnEvent

See also

Declaration: OnEvent(nEventID as long, arrayParameters as SAFEARRAY(VARIANT), pXMLSpy as IDispatch) as VARIANT

Description

OnEvent() is called each time an event is raised from XMLSPY 5.

Possible values for nEventID are:

On_BeforeStartEditing = 1
On_EditingFinished = 2
On_FocusChanged = 3
On_Beforedrag = 4
On_BeforeDrop = 5
On_OpenProject = 6
On_OpenDocument = 7
On_CloseDocument = 8
On_SaveDocument = 9

Events available with XMLSPY 5 4.4:

On_DocEditDragOver = 10
On_DocEditDrop = 11
On_DocEditKeyDown = 12
On_DocEditKeyUp = 13
On_DocEditKeyPressed = 14
On_DocEditMouseMove = 15
On_DocEditButtonUp = 16
On_DocEditButtonDown = 17
On_DocEditContextMenu = 18
On_DocEditPaste = 19
On_DocEditCut = 20
On_DocEditCopy = 21
On_DocEditClear = 22
On_DocEditSelectionChanged = 23

The names of the events are the same as they appear in the Scripting Environment of XMLSPY 5. For IDE plug-ins the names used are immaterial. The events are identified using the ID value.

arrayParameters is an array which is filled with the parameters of the currently raised event. Order, type and meaning of the single parameters are available through the scripting environment of XMLSPY 5. The events module of a scripting project, contains predefined functions for all events prior to version 4.4. The parameters passed to the predefined functions are identical to the array elements of the arrayParameters parameter.

Events raised from the Document Editor view of XMLSPY 5 do not pass any parameters directly. An "event" object is used instead. The event object can be accessed through the Document object of the active document.

pXMLSpy holds a reference to the dispatch interface of the Application object of XMLSPY 5.

If the return value of OnEvent() is set, then neither the IDE plug-in, nor an event handler inside of the scripting environment will get this event afterwards. Please note that all IDE plug-ins get/process the event before the Scripting Environment does.


GetUIModifications

IXMLSpyPlugIn.GetUIModifications

See also

Declaration: GetUIModifications() as String

Description
The GetUIModifications() method is called during initialization of the plug-in, to get the configuration XML data that defines the changes to the UI of XMLSPY 5. The method is called when the plug-in is loaded for the first time, and at every start of XMLSPY 5.

See also Configuration XML for a detailed description how to change the UI.

Example:

Public Function IXMLSpyPlugIn_GetUIModifications() As String
    ' GetUIModifications() gets the XML file with the specified modifications of
    ' the UI from the config.xml file in the plug-in folder
    Dim strPath As String
    strPath = App.Path

    If Len(strPath) > 0 Then
        Dim fso As New FileSystemObject
        Dim file As file

        Set file = fso.GetFile(strPath & "\config.xml")

        If (Not (file Is Nothing)) Then
            Dim stream As TextStream
            Set stream = file.OpenAsTextStream(ForReading)

            ' this replaces the token "**path**" from the XML file with
            ' the actual installation path of the plug-in to get the image file
            Dim strMods As String
            strMods = stream.ReadAll
            strMods = Replace(strMods, "**path**", strPath)

            IXMLSpyPlugIn_GetUIModifications = strMods
        Else
            IXMLSpyPlugIn_GetUIModifications = ""
        End If
    End If
End Function


GetDescription

IXMLSpyPlugIn.GetDescription

See also

Declaration: GetDescription() as String

Description

GetDescription() is used to define the description string for the plug-in entries visible in the Customize dialog box.

Example:

Public Function IXMLSpyPlugIn_GetDescription() As String
    IXMLSpyPlugIn_GetDescription = "Sample Plug-in for XMLSpy;This Plug-in demonstrates the implementation of a simple VisualBasic DLL as a Plug-in for XMLSpy."
End Function

Previous Top