MUI Refinement panel   

Tags: SharePoint 2010, Taxonomy, Search
Technorati Tags: , ,

First of all in this blog post I am going to explain how I resolved this little issue, but if this is the best solution I don’t know feel free to comment and share your idea’s with me.

 

OOB SharePoint 2010 offers a refinement panel that works great with the if you don’t use multiple languages. Unfortunately the project where I’m currently working on is a SharePoint environment with multiple languages. After some testing with search and the refinement panel I noticed that the Managed Metadata wasn’t changing when I was switching languages. This also was confirmed at the BIWUG 30/11 by Joris Poelmans.

 

After some thinking and testing I came to the conclusion that if I can edit the xml that most of my issues would be solved.

 

Here is a piece of the XML file. For getting the right term we can get the Id from the Url property.

<FilterCategory Id="Metadata_Groentenx0020_x0020Lx" ConfigId="Microsoft_Office_Server_Search_WebControls_TaxonomyFilterGenerator__-52273983" Type="Microsoft.Office.Server.Search.WebControls.TaxonomyFilterGenerator" DisplayName="Groenten - Légumes" ManagedProperty="ows_MetadataFacetInfo" ShowMoreLink="True" MoreLinkText="show more" LessLinkText="show fewer" ShowCounts="" ShowTaggingControl="false">
      <Filters>
        <Filter>
          <Value>Any Groenten - Légu…</Value>
          <Tooltip>Any Groenten - Légumes</Tooltip>
          <Url>/Search/Pages/XMLResults.aspx?k=ui&amp;r=</Url>
          <Selection>Implied</Selection>
          <Count></Count>
        </Filter>
        <Filter>
          <Value>Ui</Value>
          <Url>/Search/Pages/XMLResults.aspx?k=ui&amp;r=%22owstaxIdGroentenx0020%2Dx0020Lx%22%3D%23560159a2%2D4d98%2D4722%2Da0b1%2D1b06893769e6%3A%22Ui%22</Url>
          <Selection>Deselected</Selection>
          <Count>3</Count>
        </Filter>
        <Filter>
          <Value>Paprika</Value>
          <Url>/Search/Pages/XMLResults.aspx?k=ui&amp;r=%22owstaxIdGroentenx0020%2Dx0020Lx%22%3D%23e216effa%2D7bac%2D4f99%2Da762%2Dcf18ee2810bb%3A%22Paprika%22</Url>
          <Selection>Deselected</Selection>
          <Count>2</Count>
        </Filter>
        <Filter>
          <Value>Tomaat</Value>
          <Url>/Search/Pages/XMLResults.aspx?k=ui&amp;r=%22owstaxIdGroentenx0020%2Dx0020Lx%22%3D%23b4238ff9%2D6e9c%2D43d1%2Db9ad%2Dbad7317221b4%3A%22Tomaat%22</Url>
          <Selection>Deselected</Selection>
          <Count>2</Count>
        </Filter>
      </Filters>
      <MoreFilters>
        <Filter>
          <Value>Aardappelen</Value>
          <Url>/Search/Pages/XMLResults.aspx?k=ui&amp;r=%22owstaxIdGroentenx0020%2Dx0020Lx%22%3D%23efad4c07%2Df37c%2D4bf5%2Da602%2Dd1ed5ff479a7%3A%22Aardappelen%22</Url>
          <Selection>Deselected</Selection>
          <Count>1</Count>
        </Filter>
      </MoreFilters>
      <CustomData>
        <AssociateTermSets>e1092ea9-35df-41fd-b790-d29c469a95a5|320d82f1-6649-43c6-96a5-8bfedeb6c9f0</AssociateTermSets>
        <EscapedDisplayName>Groenten\ -\ Légumes</EscapedDisplayName>
      </CustomData>
    </FilterCategory>

 

The following points are important to know.

  • <FilterCategory Id="Metadata_ …..    When a category starts with “Metadata_” it is metadata :)
  • The difference between “Filters” and “MoreFilters”
  • The id can be retrieved from the “Url”

 

My Fix

 

Step 1:
Create a new SharePoint Empty project and name it MUIRefinement  and choose farm solution.

image

 

Step 2:
Add the following reference Microsoft.Office.Server.Search can be found at “C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\ISAPI\Microsoft.Office.Server.Search.dll”

image

 

Step 3:
Add a new webpart NOT A VISUAL WEBPART and name it ExtendedMUIRefinementPanel

image

 

Step 4:
Add a the following usings

using Microsoft.Office.Server.Search.WebControls;
using System.Xml;
using System.Xml.Linq;
using System.Linq;

 

Step 5:
Extend the webpart to RefinementWebpart

public class ExtendedMUIRefinementPanel : RefinementWebPart

 

Step6:
Create the following extension methods. These methods converts XmlDocument To XDocument and XDocument to XmlDocument.

 public static class DocumentExtensions
    {
        public static XmlDocument ToXmlDocument(this XDocument xDocument)
        {
            var xmlDocument = new XmlDocument();
            using (var xmlReader = xDocument.CreateReader())
            {
                xmlDocument.Load(xmlReader);
            }
            return xmlDocument;
        }
 
        public static XDocument ToXDocument(this XmlDocument xmlDocument)
        {
            using (var nodeReader = new XmlNodeReader(xmlDocument))
            {
                nodeReader.MoveToContent();
                return XDocument.Load(nodeReader);
            }
        }
    }

 

Step 7:
Create a private method TranslateMetadata

private XmlDocument TranslateMetadata(XmlDocument xmlDocument)
{
    XElement element = xmlDocument.ToXDocument().Element("FilterPanel");
  
 
    var query = from p in element.Elements()
                where p.Attribute("Id").Value.StartsWith("Metadata_")
                select p;
 
    foreach (XElement item in query)
    {
        TaxonomySession sess = new TaxonomySession(SPContext.Current.Site, false);
 
        foreach (XNode node in item.Element("Filters").Nodes())
        {
            XElement cnode = (XElement)node;
 
            SetXmlValue(sess, cnode);
        }
        if (item.Element("MoreFilters") != null)
        {
            foreach (XNode node in item.Element("MoreFilters").Nodes())
            {
                XElement cnode = (XElement)node;
 
                SetXmlValue(sess, cnode);
            }
        }
    }
 
 
    return element.Document.ToXmlDocument();
}

 

First thing we do is convert XmlDocument to a XElement. The reason for this is, I think it is easier to use linq to xml for filtering certain data.

XElement element = xmlDocument.ToXDocument().Element("FilterPanel");
  

Get all the elements that starts with an id: “Metadata_”

var query = from p in element.Elements()
            where p.Attribute("Id").Value.StartsWith("Metadata_")
            select p;

 

Loop the following elements “Filters” and “MoreFilters”

foreach (XElement item in query)
{
    TaxonomySession sess = new TaxonomySession(SPContext.Current.Site, false);
 
    foreach (XNode node in item.Element("Filters").Nodes())
    {
        XElement cnode = (XElement)node;
 
        SetXmlValue(sess, cnode);
    }
    if (item.Element("MoreFilters") != null)
    {
        foreach (XNode node in item.Element("MoreFilters").Nodes())
        {
            XElement cnode = (XElement)node;
 
            SetXmlValue(sess, cnode);
        }
    }
}

 

Step 8:
Create the method SetXmlValue.

private static void SetXmlValue(TaxonomySession sess, XElement cnode)
{
    var url = Uri.UnescapeDataString(cnode.Element("Url").Value);
 
    if (url.Contains("#"))
    {
        var id = url.Substring(url.LastIndexOf("#") + 1).Split(':')[0];
 
        if (id.Length == 37)
        {
            id = id.Substring(1);
        }
 
        Term term = sess.GetTerm(new Guid(id));
 
        string result = string.Empty;
 
        result = term.GetDefaultLabel(CultureInfo.CurrentUICulture.LCID);
 
 
        if (result.Length > 14)
            cnode.Element("Value").SetValue(result.Substring(0, 13) + "...");
        else
            cnode.Element("Value").SetValue(string.IsNullOrEmpty(result) ? term.Name : result);
 
        if (cnode.Element("Tooltip") != null)
        {
            cnode.Element("Tooltip").SetValue(result);
        }
    }
}

 

First thing we need to do is get the url and unescape it so it is readable.

var url = Uri.UnescapeDataString(cnode.Element("Url").Value);

 

We will convert  /Search/Pages/XMLResults.aspx?k=ui&amp;r=%22owstaxIdGroentenx0020%2Dx0020Lx%22%3D%23560159a2%2D4d98%2D4722%2Da0b1%2D1b06893769e6%3A%22Ui%22 to /Search/Pages/XMLResults.aspx?k=ui&amp;r="owstaxIdGroentenx0020-x0020Lx"=#560159a2-4d98-4722-a0b1-1b06893769e6:"Ui"

 

Then we check if the url we got contains an Guid. If we look at the url we see owstaxIdGroentenx0020-x0020Lx"=#560159a2-4d98-4722-a0b1-1b06893769e6:"Ui". owstaxIdGroentenx0020-x0020Lx is the metadata property that is used to filter that certain field. #560159a2-4d98-4722-a0b1-1b06893769e6:"Ui" is the termguid with the term label(the label depends on how it is saved more about that in my previous post ).

 

Thus if the url contains “#” the url contains a termguid.

if (url.Contains("#"))
 
To get the id we have to know that the last id we find is the id we are going to filter.
 
var id = url.Substring(url.LastIndexOf("#") + 1).Split(':')[0];
 
if (id.Length == 37)
{
    id = id.Substring(1);
}

 

We have to check the length of the id. sometimes the XML return the property Metadata_Tags. In the Metadata_Tags there will be an extra 0 in the id. e.g. “0560159a2-4d98-4722-a0b1-1b06893769e6”

 

When we have the id, we can get the term label in the current language.

Term term = sess.GetTerm(new Guid(id));
 
string result = string.Empty;
 
result = term.GetDefaultLabel(CultureInfo.CurrentUICulture.LCID);
 
For branding reasons if have chosen to limit the length of the of the term to display. After we get the result we can now change the value of the Value property with the term label.
if (result.Length > 14)
    cnode.Element("Value").SetValue(result.Substring(0, 13) + "...");
else
    cnode.Element("Value").SetValue(string.IsNullOrEmpty(result) ? term.Name : result);
 
if (cnode.Element("Tooltip") != null)
    cnode.Element("Tooltip").SetValue(result);

 

Step 9:
Create a global property.

private RefinementManager _manager;

 

Step 10:
Override the onit method to set the refinementmanager

protected override void OnInit(EventArgs e)
{
    base.OnInit(e);
 
    //get the refinementManager
    _manager = RefinementManager.GetInstance(this.Page, this.QueryNumber);
}

 

Step 11:
Override the GetXPathNavigator to send the altered XML to the refinementpanel.

 
protected override XPathNavigator GetXPathNavigator(string viewPath)
{
    XmlDocument xmlDocument = _manager.GetRefinementXml();
 
    if (xmlDocument == null)
            return base.GetXPathNavigator(viewPath);
            
    xmlDocument = TransLateMetadata(xmlDocument);
 
    return xmlDocument.CreateNavigator();
}

 

Step 12:
Build and deploy your solution.

 

Result

Refinementpanel in Dutch

image

Refinementpanel in French

image

 
Posted by  Gilissen Timmy  on  12/13/2011
1  Comment  |  Trackback Url  | 0  Links to this post | Bookmark this post with:        
 

Links to this post

Comments


Timmy  commented on  Tuesday, December 13, 2011  11:20 AM 
You can download the wsp at our codeplex site.

http://ventigrate.codeplex.com/releases/view/78674

Name *:
URL:
Email:
Comments:


CAPTCHA Image Validation