Unravel the SharePoint Threaded Discussion
The SharePoint Threaded Discussion is a forum type of post. Underneath, like all things SharePoint, it is a list. By default that list is made up of two content types, Discussion and Message. The content types have IDs of 0x012002 and 0x0107 respectively. Following the content type inheritance chain this means that the Discussion content type inherits from folder and the Message content type from Item. This gives us some clue about the structure of the list.
If you enter a top level item in a threaded discussion list it will be created as a folder. In order to navigate each top level thread using the object model we use code similar to that shown below.
using ( SPSite siteCollection = new SPSite( "https://moss.litwareinc.com/" ) ) {
using ( SPWeb web = siteCollection.OpenWeb( "/SiteDirectory/mktg" ) ) {
SPList list = web.Lists["Team Discussion"];
foreach ( SPListItem folder in list.Folders ) {
Console.WriteLine( "-- Folder --" );
Console.WriteLine( folder.Title );
Console.WriteLine( folder.UniqueId.ToString() );
Console.WriteLine( folder.ID.ToString() );
Console.WriteLine( folder.Xml );
Console.WriteLine( "-- End Folder --" );
}
}
}
You can also iterate over the list items themselves using the typical foreach convention. When you do this take a look at the Xml property for the List Item and you will see various items that we can use to find the context of our item within the threaded discussion.
<?xml version="1.0" encoding="utf-8" ?>
<z:row xmlns:z='#RowsetSchema'
ows_ContentTypeId='0x010700135BC7419F95B04C8EA15325163C1444'
ows_Body='<div class=ExternalClassAAF51B42E3834F8D90CA3A8DA7739064><div>second sample item<br><br><hr><b>From: </b>System Account<br><b>Posted: </b>Wednesday, June 04, 2008 5:14 PM<br><b>Subject: </b>sample item one<br><br><div class=ExternalClassF19C451E2C284124AB09D103E8A70A18><div>first sample item</div></div></div></div>'
ows_TrimmedBody='<div class=ExternalClass4D66DF23C3C649C4985CFE81A1E2E0E2><div>second sample item<br></div></div>'
ows_ParentFolderId='1'
ows_ID='2'
ows_ContentType='Message'
ows_Modified='2008-06-04 17:14:33'
ows_Created='2008-06-04 17:14:33'
ows_Author='1073741823;#System Account'
ows_Editor='1073741823;#System Account'
ows_owshiddenversion='1'
ows_WorkflowVersion='1'
ows__UIVersion='512'
ows__UIVersionString='1.0'
ows_Attachments='0'
ows__ModerationStatus='0'
ows_SelectTitle='2'
ows_Order='200.000000000000'
ows_GUID='{8FAC9A20-6343-48A3-8BE3-CD7E17E45894}'
ows_FileRef='2;#SiteDirectory/mktg/Lists/TeamDiscussion/sample item one/2_.000'
ows_FileDirRef='2;#SiteDirectory/mktg/Lists/Team Discussion/sample item one'
ows_Last_x0020_Modified='2;#2008-06-04 17:14:33'
ows_Created_x0020_Date='2;#2008-06-04 17:14:33'
ows_FSObjType='2;#0'
ows_PermMask='0x7fffffffffffffff'
ows_FileLeafRef='2;#2_.000'
ows_UniqueId='2;#{87C5CD04-7D68-4B26-B00C-DD76AE7B96D8}'
ows_ProgId='2;#'
ows_ScopeId='2;#{6ED2F3B8-3D0A-4B4F-B092-C9A6D1942AE2}'
ows__EditMenuTableStart='2_.000'
ows__EditMenuTableEnd='2'
ows_LinkFilenameNoMenu='2_.000'
ows_LinkFilename='2_.000'
ows_ServerUrl='/SiteDirectory/mktg/Lists/Team Discussion/sample item one/2_.000'
ows_EncodedAbsUrl='https://moss.litwareinc.com/SiteDirectory/mktg/Lists/Team%20Discussion/sample%20item%20one/2_.000'
ows_BaseName='2_'
ows_MetaInfo='2;#'
ows__Level='1'
ows__IsCurrentVersion='1'
ows_ThreadIndex='0x01CA94B8313E972C16929A454ACFA141B2588F7291DB000004B927'
ows_ShortestThreadIndexIdLookup='1;#'
ows_DiscussionTitleLookup='1;#sample item one'
ows_DiscussionTitle='sample item one'
ows_ReplyNoGif='SiteDirectory/mktg/Lists/Team Discussion/sample item one'
ows_ThreadingControls='0x01CA94B8313E972C16929A454ACFA141B2588F7291DB000004B927'
ows_IndentLevel='0x01CA94B8313E972C16929A454ACFA141B2588F7291DB000004B927'
ows_Indentation='0x01CA94B8313E972C16929A454ACFA141B2588F7291DB000004B927'
ows_StatusBar='2008-06-05T00:14:33Z'
ows_BodyAndMore='<div class=ExternalClassAAF51B42E3834F8D90CA3A8DA7739064><div>second sample item<br><br><hr><b>From: </b>System Account<br><b>Posted: </b>Wednesday, June 04, 2008 5:14 PM<br><b>Subject: </b>sample item one<br><br><div class=ExternalClassF19C451E2C284124AB09D103E8A70A18><div>first sample item</div></div></div></div>'
ows_MessageBody='<div class=ExternalClassAAF51B42E3834F8D90CA3A8DA7739064><div>second sample item<br><br><hr><b>From: </b>System Account<br><b>Posted: </b>Wednesday, June 04, 2008 5:14 PM<br><b>Subject: </b>sample item one<br><br><div class=ExternalClassF19C451E2C284124AB09D103E8A70A18><div>first sample item</div></div></div></div>'
ows_BodyWasExpanded='{8FAC9A20-6343-48A3-8BE3-CD7E17E45894}'
ows_QuotedTextWasExpanded='{8FAC9A20-6343-48A3-8BE3-CD7E17E45894}'
ows_CorrectBodyToShow='<div class=ExternalClass4D66DF23C3C649C4985CFE81A1E2E0E2><div>second sample item<br></div></div>' ows_FullBody='<div class=ExternalClassAAF51B42E3834F8D90CA3A8DA7739064><div>second sample item<br><br><hr><b>From: </b>System Account<br><b>Posted: </b>Wednesday, June 04, 2008 5:14 PM<br><b>Subject: </b>sample item one<br><br><div class=ExternalClassF19C451E2C284124AB09D103E8A70A18><div>first sample item</div></div></div></div>'
ows_LimitedBody='<div class=ExternalClassAAF51B42E3834F8D90CA3A8DA7739064><div>second sample item<br><br><hr><b>From: </b>System Account<br><b>Posted: </b>Wednesday, June 04, 2008 5:14 PM<br><b>Subject: </b>sample item one<br><br><div class=ExternalClassF19C451E2C284124AB09D103E8A70A18><div>first sample item</div></div></div></div>'
ows_MoreLink='2'
ows_LessLink='2'
ows_ToggleQuotedText='2'
ows_Threading='0x01CA94B8313E972C16929A454ACFA141B2588F7291DB000004B927'
ows_PersonImage='System Account'
ows_PersonViewMinimal='System Account'
ows_IsRootPost='0'
ows_ItemChildCount='2;#0'
ows_ServerRedirected='0'/>
One of the more important properties is the ows_ParentFolderId. By leveraging this property we can establish the parent thread or discussion, in this case the folder, that is the host for the item. This will always be the top level folder item, not the item that was responded to originally. While this does allow you to figure out which items go with which folder, it does not provide order or hierarchy.
If you examine the default 'Threaded' view that comes with an instance of the Team Discussion you will notice that it contains one column, 'Threading (threaded)'. This column is used for display and also used to sort the items. There is a group of properties that provide a structure that enabling you to figure out he thread hierarchy. Notice the ows_ThreadIndex, ows_Threading, ows_ThreadingControls, ows_IndentLevel, etc. These properties all have the same value for an item, but as you navigate from item to item notice that a hierarchy of sorts is formed. The base item has a thread value and then the children have this same thread value, but with some additional random text after the base item. This begins to form a hierarchy.
ows_ThreadingIndex='0x01CA94B8313E972C16929A454ACFA141B2588F7291DB’
|_ows_ThreadingIndex='0x01CA94B8313E972C16929A454ACFA141B2588F7291DB000004B927'
|_ows_ThreadingIndex='0x01CA94B8313E972C16929A454ACFA141B2588F7291DB000004B9270000026E29'
When reviewing the Xml attributes another item looks promising, ows_Order. It has a format of xxx.xxxxxx. This leads one to believe that this would control the order of the items in the thread. I was hoping to find a pattern that was parent.childorder or something to that affect, but that is not the case. Upon further examination this is simply the item id. It is probably reserved for some future use.
Comments
- Anonymous
July 16, 2008
PingBack from http://wordnew.acne-reveiw.info/?p=9331 - Anonymous
August 13, 2008
Does this discussion in which we are currently participating use the WSS discussion feature, or is some other enabling technology providing the discussion thread engine? - Anonymous
August 13, 2008
...nevermind. I see in teh source code that it is usng CommunityServer 2.1 SP1.thanks, R - Anonymous
January 12, 2010
How to iterate item (message) level?. Now I am working on finding all posts for particular user in the web. CAML query returning only Top level post only (Discussion), not replies (Messages). Give me some clue to get them too. - Anonymous
January 13, 2010
You could do a CAML query that is limited to the Content Type of folder. the content type id is mentioned in the first paragraph. - Anonymous
February 16, 2010
Cliff can you demonstrate how to post a reply against a reply programitacly using "AddDiscussionBoardItem" method of list web service. Able to create discussion and post replies. But unable to find any solution to post a reply against a reply. - Anonymous
February 18, 2010
The comment has been removed - Anonymous
March 09, 2010
Franz, did you find an answer to your question about AddDiscussionBoardItem? I am having the same problem! - Anonymous
March 11, 2010
Fraz and John, I'll look into this, but here is an example of the 64encoding and how to post an item. I will look at posting a reply if I can, and it may be that it requires the ChangeListitem method with some knowledge of the internals.http://social.technet.microsoft.com/Forums/en-US/sharepointdevelopment/thread/25d55767-71f1-4e1a-a62e-8a22f9de58a8 - Anonymous
March 12, 2010
Looks like I have all but one of my issues solved...how can I pass my encoded value to WSS via JavaScript?Since the 2nd param of AddDiscussionBoardItem wants a Base64Binary how should I handle that? - Anonymous
March 14, 2010
Excellent. There are third party and open source libraries for doing base64 encoding, so you can look into those. - Anonymous
March 15, 2010
see the following post on using web services ...http://blogs.msdn.com/cliffgreen/archive/2010/03/15/threaded-discussion-using-sharepoint-2007-web-services.aspx - Anonymous
March 17, 2010
Hey Cliff,Just looking at the new post now, but heck I think it's going to be a HUGE help!Thanks VERY much!John