Wednesday, 20 July 2011

Sharepoint 2010 managed meta-data taxonomy field data using web services

Sharepoint 2010 includes a very useful new concept: managed meta-data. This allows you to build taxonomic hierarchies, and provide document routing based on the meta-data.

Unfortunately, it seems that using this field type using a web service call is extremely complicated, and hardly seems to be documented at all (this is so typical of Sharepoint stuff...).  Microsoft have given us a new web service class ("taxonomyclientservice") but there hardly any documentation on it all (

Here is an example that I have managed to get working (after MUCH trial and error) that will hopefully help you to do the following:
  1. opens a list using the Lists web service, 
  2. iterates through the fields in the default content type for the list (you can remove this bit and just iterate through the fields in the list if you like),
  3. if it finds a "TaxonomyFieldType" field, it then gets the "Shared Service ID" (GUID of managed meta-data service) and Term Set ID (GUID of term set defined on this field) required to run the Taxonomy web service call
  4. sets up the CAML to run the Taxonomy web service call,
  5. retrieves the taxonomy data for that field in XML.  
 I do not try to analyse what the taxonomy XML means - that is for another day!

Note that all my web service proxies are called "ListService" and "Taxonomys".

//get list data from webservice
ListService.Lists listService = new ListService.Lists();
// Use your own list name
XmlNode list = listService.GetList("My List Name");

// Let's have a look at it

// Get the content types for this list
//Get our defined content type (see previous post on how to do this - you need your own values here!)
string contentTypeGuid = GetListContentTypeGuid("My List Name", "{GUID}", "My Content Type");

// Now get content type definition 
XmlNode contentType = m_listService.GetListContentType(mylistinfo.m_listName, contentTypeGuid);

//Get the fields from the content type
XmlNodeList nodes = RunXPathQuery(contentType, "//sp:Field");

// Loop through the fields in the content type
foreach (XmlNode node in nodes)
 // This stuff just sets up some variables based on the content type and skips over hidden fields
 string Name = node.Attributes["Name"].Value;
 if (Name == "ContentType") continue;
 string ID = node.Attributes["ID"].Value;

 if (string.IsNullOrEmpty(ID) || string.IsNullOrEmpty(Name))

 bool hidden = false;
 bool ReadOnly = false;
 try { hidden = Convert.ToBoolean(node.Attributes["Hidden"].Value); }
 catch { }
 try { ReadOnly = Convert.ToBoolean(node.Attributes["ReadOnly"].Value); }
 catch { }

 if (hidden || ReadOnly)

 string ShowInFileDlg = "";
 try { ShowInFileDlg = node.Attributes["ShowInFileDlg"].Value; }
 catch { }
 if (ShowInFileDlg == "FALSE") continue;

 string StaticName = node.Attributes["StaticName"].Value;
 string DisplayName = node.Attributes["DisplayName"].Value;

 // Now we can check the "Type" attribute
 string FieldType = node.Attributes["Type"].Value;

 if (FieldType == "TaxonomyFieldType")

     // Lets get the shared service ID and the termset ID from teh List schema
     string sharedServiceIds = "";
     string termSetId = ""; 
     // jump a few nodes to get the correct bit of the schema (included for clarity)
     XmlNode childNode =  node.ChildNodes[1];
     XmlNode termNodes = childNode.ChildNodes[0];

     //Loop through these nodes until we find the information we need
     foreach (XmlNode term in termNodes.ChildNodes)
         System.Diagnostics.Debug.Print("term = " + term.ChildNodes[0].InnerText.ToString());
         if (term.ChildNodes.Count > 1)
             System.Diagnostics.Debug.Print("value = " + term.ChildNodes[1].InnerText.ToString());
             if (term.ChildNodes[0].InnerText.ToString() == "SspId")
                 // Get shared services ID from list
                 sharedServiceIds = term.ChildNodes[1].InnerText.ToString();
             if (term.ChildNodes[0].InnerText.ToString() == "TermSetId")
                 // Get Term Set ID from list
                 termSetId = term.ChildNodes[1].InnerText.ToString();
     int lcid = System.Globalization.CultureInfo.CurrentUICulture.LCID;
     string serverTermSetTimeStampXml = "";

     string termStoreIds = "<termStoreIds><termStoreId>" + sharedServiceIds + "</termStoreId></termStoreIds>";
     string termSetIds = "<termSetIds><termSetId>" + termSetId + "</termSetId></termSetIds>";
     //Always set timestamp to this
     string oldtimestamp = "<timeStamps><timeStamp>633992461437070000</timeStamp></timeStamps>";
     //Always set version to 1
     string clientVersion = "<versions><version>1</version></versions>";
     string timeStamp = "";

     // Taxonomy web service!!
     Taxonomys.Taxonomywebservice taxonomy = new Taxonomys.Taxonomywebservice();
     taxonomy.Credentials = System.Net.CredentialCache.DefaultCredentials;
     string resultXML = taxonomy.GetTermSets(termStoreIds, termSetIds, lcid, oldtimestamp, clientVersion, out timeStamp);

     //Loop through the XML
     string termValue = "MHA";
     string termGUID = "";
     string parentID = "";
     XmlDocument termSetXML = new XmlDocument();
     XmlNodeList terms = termSetXML.GetElementsByTagName("T");
     foreach (XmlNode term in terms)
         string termName = term.FirstChild.FirstChild.Attributes["a32"].Value;
         termGUID = term.Attributes["a9"].Value;
             parentID = term.Attributes["a25"].Value;
         catch (Exception)
             parentID = "";
         System.Diagnostics.Debug.Print("termName = " + termName + ", termGUID = " + termGUID + ", parentID = " + parentID);   

If you would like to know how to analyse the attribute codes returned in the XML, then take a look at this blog entry: