Posted on Oct 31, 2011

The CMDUI.xml file, located in the SharePoint hive (\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\Template\Global\Xml), contains IDs of all built-in ribbon buttons, groups, and tabs. Sometimes it is useful to have these IDs in a text file or in an SQL Server database. In this article, I'm going to show how to transform CMDUI.xml to a comma-separated text file and then how to import it to an SQL Server table.

First, let's have a look at the structure of the CMDUI.xml file. The following XML snippet shows a simplified fragment of the Document tab:

<Tab Id="Ribbon.Library" Sequence="200" Command="LibraryTab">
  <Scaling  Id="Ribbon.Library.Scaling">
    <MaxSize Id="Ribbon.Library.Scaling.ViewFormat.MaxSize" Size="LargeLarge" />
    <MaxSize Id="Ribbon.Library.Scaling.Datasheet.MaxSize" Size="LargeMedium" />
    <MaxSize Id="Ribbon.Library.Scaling.CustomViews.MaxSize" Size="LargeMedium" />
    <Scale Id="Ribbon.Library.Scaling.Datasheet.LargeSmall" Size="LargeSmall" />
    <Scale Id="Ribbon.Library.Scaling.Settings.LargeMedium" Size="LargeMedium" />
  </Scaling>
  <Groups Id="Ribbon.Library.Groups">
    <Group Id="Ribbon.Library.ViewFormat"
    Sequence="10" Command="ViewFormatGroup"
    Template="Ribbon.Templates.Flexible2">
    <Controls Id="Ribbon.Library.ViewFormat.Controls">
        <ToggleButton Id="Ribbon.Library.ViewFormat.Standard"
        Sequence="10" Command="DisplayStandardView"
        LabelText="$Resources:core,cui_ButStandardView;"
        ToolTipTitle="$Resources:core,cui_ButStandardView;"
        ToolTipDescription="$Resources:core,cui_STT_ButStandardView;"
        QueryCommand="QueryDisplayStandardView"
        TemplateAlias="o1" />
        <ToggleButton Id="Ribbon.Library.ViewFormat.Datasheet"
        Sequence="20" Command="DisplayDatasheetView"
        LabelText="$Resources:core,cui_ButDataSheetView;"
        ToolTipTitle="$Resources:core,cui_ButDataSheetView;"
        ToolTipDescription="$Resources:core,cui_STT_ButDatasheetView;"
        QueryCommand="QueryDisplayDatasheetView"
        TemplateAlias="o1" />
    </Controls>
    </Group>
    <Group Id="Ribbon.Library.Datasheet"
    Sequence="20" Command="DatasheetGroup"
    Template="Ribbon.Templates.Flexible2">
    <Controls Id="Ribbon.Library.Datasheet.Controls">
        <Button Id="Ribbon.Library.Datasheet.NewRow"
        Sequence="10" Command="DatasheetNewRow"
        LabelText="$Resources:core,cui_ButNewRow;"
        ToolTipTitle="$Resources:core,cui_ButNewRow;"
        ToolTipDescription="$Resources:core,cui_STT_ButNewRow;"
        TemplateAlias="o1" />
        <Button Id="Ribbon.Library.Datasheet.ShowTaskPane"
        Sequence="20" Command="DatasheetShowTaskPane"
        LabelText="$Resources:core,cui_ButShowTaskPane"
        ToolTipTitle="$Resources:core,cui_ButShowTaskPane;"
        ToolTipDescription="$Resources:core,cui_STT_ButShowTaskPane;"
        TemplateAlias="o2" />
        <Button Id="Ribbon.Library.Datasheet.ShowTotals"
        Sequence="30" Command="DatasheetShowTotals"
        LabelText="$Resources:core,cui_ButShowTotals;"
        ToolTipTitle="$Resources:core,cui_ButShowTotals;"
        ToolTipDescription="$Resources:core,cui_STT_ButShowTotals;"
        TemplateAlias="o2" />
        <Button Id="Ribbon.Library.Datasheet.RefreshData"
        Sequence="40" Command="DatasheetRefreshData"
        LabelText="$Resources:core,cui_ButRefreshData;"
        ToolTipTitle="$Resources:core,cui_ButRefreshData;"
        ToolTipDescription="$Resources:core,cui_STT_ButRefreshData;"
        TemplateAlias="o2" />
    </Controls>
    </Group>
etc.

The above definition contains much more information than I need as I'm interested only in the IDs of the ribbon controls. In order to extract the IDs (highlighted in the above XML snippet) I use the following XSLT transformation:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
ElementId,ElementType,ButtonType
<xsl:for-each select="//Tab">
<xsl:value-of select="@Id" />,Tab,<br />
<xsl:for-each select="Groups/Group">
<xsl:value-of select="@Id" />,Group,<br />
<xsl:for-each select="Controls/*">
<xsl:value-of select="@Id" />,Control,<xsl:value-of select="name(.)" /><br />
</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
</xsl:template>

The easiest method to apply the above transformation is to insert a reference to XSLT into the CMDUI.xml header (the highlighted line below). I assume the transformation is located in the cmdui.xsl file:

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="/cmdui.xsl"?>
<CommandUI>
<Ribbon 
  Id="Ribbon"

Opening the modified CMDUI.xml yields the following output:

ElementId,ElementType,ButtonType
Ribbon.Library,Tab,
Ribbon.Library.ViewFormat,Group,
Ribbon.Library.ViewFormat.Standard,Control,ToggleButton
Ribbon.Library.ViewFormat.Datasheet,Control,ToggleButton
Ribbon.Library.Datasheet,Group,
Ribbon.Library.Datasheet.NewRow,Control,Button
Ribbon.Library.Datasheet.ShowTaskPane,Control,Button
Ribbon.Library.Datasheet.ShowTotals,Control,Button
Ribbon.Library.Datasheet.RefreshData,Control,Button
...

Where:

  • ElementId - ID of a ribbon element: a button, a group, or a tab
  • ElementType - an element type: "Control", "Group", or "Tab"
  • ButtonType - a button's type; this field has a meaning only for ribbon controls, examples: Button, ComboBox, SplitButton, FlyoutAnchor, etc.

It's easy to copy the output from the browser window to a text file: buttons.txt

Another option is to use a processing tool such as nxslt2 to export XSLT output to a text file. The following script uses this approach:

REM -o filename Write output to named file
REM -xw Strip non-significant whitespace from source and stylesheet
nxslt2 cmdui.xml cmdui.xsl -xw -o buttons.txt

Sometimes I'd like to transform the CMDUI.xml file to an HTML table instead of comma-separated text. This kind of transformation could look like that:

<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
  <table cellpadding="2" cellspacing="1" border="1">
    <tr style="background-color:grey;color:white">
      <td width="80">ElementType</td>
      <td width="100">ButtonType</td>
      <td width="250">ElementId</td>
    </tr>
    <xsl:for-each select="//Tab">
      <tr>
        <td>Tab</td>
        <td> </td>
        <td>
          <xsl:value-of select="@Id" />
        </td>
      </tr>
      <xsl:for-each select="Groups/Group">
      <tr>
        <td>Group</td>
        <td> </td>
        <td>
          <xsl:value-of select="@Id" />
        </td>
      </tr>
        <xsl:for-each select="Controls/*">
        <tr>
          <td>Control</td>
          <td>
            <xsl:value-of select="name(.)" />
          </td>
          <td>
            <xsl:value-of select="@Id" />
          </td>
        </tr>
        </xsl:for-each>
      </xsl:for-each>
    </xsl:for-each>
</table>
</xsl:template>
</xsl:stylesheet>

It generates the following output:

ElementType ButtonType ElementId
Tab   Ribbon.Library
Group   Ribbon.Library.ViewFormat
Control ToggleButton Ribbon.Library.ViewFormat.Standard
Control ToggleButton Ribbon.Library.ViewFormat.Datasheet
Group   Ribbon.Library.Datasheet
Control Button Ribbon.Library.Datasheet.NewRow
Control Button Ribbon.Library.Datasheet.ShowTaskPane
Control Button Ribbon.Library.Datasheet.ShowTotals
Control Button Ribbon.Library.Datasheet.RefreshData

 

This is just a small fragment of the entire ribbon. A file containing all elements is available here: buttons.htm

I also found it useful to have the IDs of the ribbon's elements in an SQL Server table. A table to keep the IDs could be created using a script similar to this one:

CREATE TABLE RibbonButtons (
    ElementId VARCHAR(200) NOT NULL DEFAULT '' PRIMARY KEY,
    ElementType VARCHAR(50) NOT NULL DEFAULT '',
    ButtonType VARCHAR(50) NOT NULL DEFAULT '',
    Notes VARCHAR(150) NOT NULL DEFAULT ''
) ON [PRIMARY]
GO

... and then bulk loaded from a text file buttons.txt:

TRUNCATE TABLE RibbonButtons
GO
BULK
INSERT RibbonButtons
FROM 'c:\buttons.txt'
WITH
(
    FIRSTROW = 2,
    MAXERRORS = 0,
    FIELDTERMINATOR = ',',
    ROWTERMINATOR = '\n'
)
GO

Having the IDs of ribbon elements in an SQL Server table allows me to write queries like that:

-- show all ribbon groups
SELECT * FROM RibbonButtons
WHERE ElementType='Group'
GO

The entire code is available here.