Content Type XML Document

Over the past few months, I’ve been surprised by the number of people I’ve spoken with who were not aware that it’s possible to store custom XML documents against content type objects through the API. These are people who have either been developing of providing consultation for the platform since, at least, the release of MOSS 2007.

So, for that reason, I’ve decided to write a short post about the functionality.

The SPContentType class contains a property called XmlDocuments.

This property exposes a collection of XML documents that are stored against the content type. Although there can be a number of XML documents in this collection, it is also possible to add your own XML documents to the collection.

Adding your own XML document to this property allows you, as a developer, to store custom configurations against individual content types, whether that be against the site content type, or a child version defined within a list or library.

Say, for instance, you created an XML document to define a unique name for any item created against it. By creating an application page to allow administrators to specify a naming convention for new items, you are able to control how new documents are named and be able to change the logic by simply updating it via the custom application page. When you implement the logic to generate a new document’s (or item’s) name, you would simply read the XML document from the XmlDocuments property of the content type that the item belongs to and apply your custom logic.

Lets have a look at an example of what the custom XML document class could look like.

[DataContract(Namespace = "http://www.sharepointstu.com/ContentTypes/ItemNaming")]
public class CustomContentType
{
    [DataMember]
    protected string namingLogic;
 
    public string NamingLogic
    {
        get { return namingLogic; }
        set { namingLogic = value; }
    }
}

The important things to note about this class is the two class attributes, DataContract and DataMember.

By adding these attributes to the class we will be able to serialize and deserialize the class against the XmlDocuments property.

The next part is adding code to create\update the XML document within the content type. The following is some code that will do this for you. To keep it simple, I’ve not added any error handling or object checks to the code.

public void UpdateXmlProperties(SPContentType contentType, CustomContentType properties, bool updateChildren)
{
    DataContractSerializer serializer = new DataContractSerializer(properties.GetType());
 
    using (MemoryStream memStream = new MemoryStream())
    {
        using (XmlDictionaryWriter xmlWriter = XmlDictionaryWriter.CreateTextWriter(memStream))
        {
            serializer.WriteObject(xmlWriter, properties);
            xmlWriter.Flush();
 
            memStream.Position = 0;
            XmlDocument doc = new XmlDocument();
            doc.Load(memStream);
 
            SPXmlDocumentCollection docCollection = contentType.XmlDocuments;
 
            docCollection.Delete(doc.FirstChild.NamespaceURI); // delete XML document by given namespace
            docCollection.Add(doc); // add the serialized XML
        }
    }
 
    contentType.Update(updateChildren, false);
}

This method should ideally be moved into a base class for your content type and not require the content type object to be passed in but it keeps things simple to show the logic this way.

I’ve set the properties parameter as a CustomContentType type but I’m sure I don’t need to tell you that this should be set as a base interface\abstract class.

The logic is petty straightforward and uses the DataContractSerializer class to serialize the passed properties object to and XmlDocument object before adding it to the XmlDocument property.

Lastly, the reverse of the above method is shown below. This time we’re reading the serialized XmlDocument from the content type and returning the saved properties object.

public object LoadCustomProperties(SPContentType contentType, Type objectType, string objectNamespace)
{
    SPXmlDocumentCollection docCollection = contentType.XmlDocuments;
    string xmlDocString = docCollection[objectNamespace];
 
    DataContractSerializer serializer = new DataContractSerializer(objectType);
    using (MemoryStream memStream = new MemoryStream(Encoding.UTF8.GetBytes(xmlDocString)))
    {
        return serializer.ReadObject(memStream);
    }
}

First, we retrieve the serialized XmlDocument from the content type’s collection before using the DataContractSerializer object to deserialize the string back into it’s object.

Leave a Reply

Your email address will not be published. Required fields are marked *

Solve the maths problem shown below before posting: *

Follow

Get every new post delivered to your Inbox

Join other followers: