Updating the docicon.xml File with a Feature

File types are associated to an icon in SharePoint by mapping a particular file extension to a specific icon. This makes the file easily recognizable to end users as they navigate a site and skim a document library. For licensing reasons, only a select list of file types has an icon associated with them by default. This also helps prevent bloating the document icon list with an exhaustive list of file types.

You can map a file extension to a particular icon in SharePoint by editing the docicon.xml file and adding a mapping element with the file extension and icon path. This file is located in the TEMPLATES\XML folder within the SharePoint 12 hive. You will need to edit this file on each web front-end server, making it a good candidate to accidently have a server go out of sync with the other servers. No different from challenges faced with any manual configuration or customization. By instead making the changes via a SharePoint feature, the solution is repeatable, testable, and ensures all servers reflect any changes.

To illustrate an example I will use a file type I often like to add an icon for, PDF files. I created a new feature with a farm scope and a receiver class to override the FeatureActivated and FeatureDeactivating methods. Below is my code for the FeatureActivated method where it loads the docicon.xml document, check if a mapping element exists for the PDF extension, and add one if not.

Being fussy about my code and maintaining consistency, I first attempt to add the new PDF Mapping element in alphabetical order by checking for a file extension in the list that would fall after "PDF" and insert the node before that. Otherwise, I append the PDF Mapping element as the last element. Finally, I save the file overwriting the original with the changes.

public override void FeatureActivated(SPFeatureReceiverProperties properties)

{

    XmlDocument xmlDocument = new XmlDocument();

    xmlDocument.Load(DocIconFilePath);

    XmlNode documentElement = xmlDocument.DocumentElement;

    XmlNode pdfNode = documentElement.SelectSingleNode("ByExtension/Mapping[@Key='pdf']");

    if (pdfNode == null)

    {

        pdfNode = xmlDocument.CreateElement("Mapping");

        pdfNode.Attributes.Append(

        xmlDocument.CreateAttribute("Key")).Value = "pdf";

        pdfNode.Attributes.Append(

        xmlDocument.CreateAttribute("Value")).Value = "pdf.gif";

        bool wasAdded = false;

        XmlNode byExtensionNode = documentElement.SelectSingleNode("ByExtension");

        foreach (XmlNode node in byExtensionNode.ChildNodes)

        {

            if (node.Attributes["Key"].Value.CompareTo("pdf") > 0)

            {

                byExtensionNode.InsertBefore(pdfNode, node);

                wasAdded = true;

                break;

            }

        }

        if (!wasAdded)

            byExtensionNode.AppendChild(pdfNode);

        xmlDocument.Save(DocIconFilePath);

    }

}

The FeatureDeactivating method reverses the configuration changes when administrators deactivate the feature. However, changes may require recycling an application pool before the changes take effect and the icon reverts to the common plain white one. Below is my code for the FeatureDeactivating method where it loads the same docicon.xml file and checks if a Mapping element exists for the PDF extension. If a PDF Mapping element exists, it removes the element and then saves the file back with the changes.

public override void FeatureDeactivating(SPFeatureReceiverProperties properties)

{

    XmlDocument xmlDocument = new XmlDocument();

    xmlDocument.Load(DocIconFilePath);

    XmlNode documentElement = xmlDocument.DocumentElement;

    XmlNode pdfNode = documentElement.SelectSingleNode("ByExtension/Mapping[@Key='pdf']");

    if (pdfNode != null)

    {

        XmlNode byExtensionNode = documentElement.SelectSingleNode("ByExtension");

        byExtensionNode.RemoveChild(pdfNode);

        xmlDocument.Save(DocIconFilePath);

    }

}

Loading and saving the docicon.xml file in the FeatureActivated and FeatureDeactivating methods use the DocIconFilePath property. This property looks up and builds the path on first access. Below is my code for the property where I combine the TEMPLATE\XML directory with the docicon.xml file to build the full path.

Instead of hard coding the directory to the most common path of the 12 hive, I used a static utility method in the SharePoint API to encapsulate the path and make it less fragile to changes. Calling SPUtility.GetGenericSetupPath with an empty string will return the full path to the 12 hive as a string (most typically this path is "C:\Program Files\Common Files\Microsoft Shared\web server extensions\12"). The utility takes string parameters and combines them as a subdirectory of the 12 hive, and then returns the full path with the subdirectory.

private string _docIconFilePath;

private string DocIconFilePath

{

    get

    {

        if (_docIconFilePath == null)

            _docIconFilePath = Path.Combine(

                SPUtility.GetGenericSetupPath("TEMPLATE\\XML"),

                "DOCICON.XML");

        return _docIconFilePath;

    }

}

I deploy the PDF icon file in the WSP solution package with the feature by adding a command to the DDF file that copies it to an Images directory in the WSP. The solution manifest file includes the following TemplateFile element that copies the PDF icon file to the TEMPLATE\IMAGES directory of the 12 hive for each server in the farm during solution deployment.

<TemplateFiles>

    <TemplateFile Location="IMAGES\pdf.gif" />

Once the solution is packaged and deployed on the server, activate the feature in the farm features management area of SharePoint Central Administration. Upload a PDF file to a document library and verify the icon next to it matches the icon set in this feature.