In a nutshell, this is how I managed to get it working:
Using PowerShell, I extracted the IDs of the Metadata service name, and the IDs of the term set name.
$col = Get-SPSite http://sharepoint
#Get TermStore ID
$taxonomySession = Get-SPTaxonomySession -site $col
$termStore = $taxonomySession.TermStores["Managed Metadata Service"]
$termStore.Id
#Get TermSet ID
$termStoreGroup = $termStore.Groups["Departments"]
$termSet.Id
Following that, I created a (repeating) group called tblDept in InfoPath. You can do so by going to the Fields toolbar, right click the top level element and choose Add.
Next, create a new data connection called GetDepartments to receive data from the site's TaxonomyService.asmx web services. You can get it from
In the next window, populate the term store id and term set ids like below:
By triggering this data connection to retrieve data each time the form loads, the resulting term set will be stored in an XML for later use.
Now add code-behind to your InfoPath form by clicking on the Developer tab - Loading Event button. Sample of code:
public void FormEvents_Loading(object sender, LoadingEventArgs e)
{
XPathNavigator mainNav = this.MainDataSource.CreateNavigator();
// Retrieve list of Departments from Content Type Hub
populateDropdown(
mainNav, "/my:myFields/my:tblDept/my:Dept", "GetDepartments",
"Dept", "DeptValue", "DeptGuid", "/my:myFields/my:tblDept"
);
}
The populateDropdown function will parse the XML to get the Term Set labels, and add them as a new element called Dept into tblDept.
private void populateDropdown(
XPathNavigator nav, string fieldXPath, string dataSourceName,
string fieldName, string valueLabel, string guidLabel, string groupXPath
)
{
cleanupDropdown(nav, fieldXPath);
XPathNavigator termSetNav = this.DataSources[dataSourceName].CreateNavigator();
// as we're calling the same web service function for each term set,
// the xpath stays the same
string xPath = "/dfs:myFields/dfs:dataFields/ns1:GetTermSetsResponse/ns1:GetTermSetsResult";
XPathNavigator nodeNav = termSetNav.SelectSingleNode(xPath, this.NamespaceManager);
string resultXML = nodeNav.Value.ToString();
XmlDocument termSetXML = new XmlDocument();
termSetXML.LoadXml(resultXML);
XmlNodeList terms = termSetXML.GetElementsByTagName("T");
foreach (XmlNode term in terms)
{
XmlNode v = term.SelectSingleNode("LS/TL");
string termValue = v.Attributes["a32"].Value;
string termGuid = term.Attributes["a9"].Value;
if (!string.IsNullOrEmpty(termValue))
addDropdown(fieldName, termValue, valueLabel, termGuid, guidLabel, groupXPath, nav);
}
}
Prior to adding the dropdown, I make a cleanUPDropdown call to clear tblDept of any existing value.
private void cleanupDropdown(XPathNavigator nav, string xPath)
{
XPathNodeIterator rows = nav.Select(xPath, NamespaceManager);
// remove selected row(s) from table
for (int i = rows.Count; i > 0; i--)
{
XPathNavigator delRow = nav.SelectSingleNode(xPath + "[" + i + "]", NamespaceManager);
if (delRow != null)
delRow.DeleteSelf();
}
Next, I loop through each term label and call addDropdown.
private void addDropdown(string groupName, string value, string valueLabel,
string guid, string guidLabel, string xPath, XPathNavigator nav)
{
XmlDocument doc = new XmlDocument();
XmlNode group = doc.CreateElement(groupName, NamespaceManager.LookupNamespace("my"));
XmlNode field = doc.CreateElement(valueLabel, NamespaceManager.LookupNamespace("my"));
XmlNode node = group.AppendChild(field);
node.InnerText = value;
XmlNode fieldGuid = doc.CreateElement(guidLabel, NamespaceManager.LookupNamespace("my"));
XmlNode guidNode = group.AppendChild(fieldGuid);
guidNode.InnerText = guid;
doc.AppendChild(group);
nav.SelectSingleNode(
xPath,
NamespaceManager).AppendChild(doc.DocumentElement.CreateNavigator());
} }
Finally, add a Drop-Down List Box to the InfoPath form and map the entries to tblDept
It might seem complicated but that's part of the fun!