Welcome to EMC Consulting Blogs Sign in | Join | Help

Paul Galvin's Blog

Walk-through: Use People Search for Department Contacts

Overview

This article describes how to use Microsoft Office SharePoint Server (MOSS) People Search to display department-level contacts in a simple-to-read grid format.

This solution arose from a consulting engagement.  The client’s portal taxonomy included many corporate departments.  Most departments wanted to display member’s contact information on their site’s main page.  The client’s first impulse was to use a Contacts web part.  That is not usually the best approach, however.  Instead, leverage the People Search Core Results web part.

The solution

Here is the desired result:

clip_image002

To achieve that result, we use the following SharePoint features and technology:

1.       People Search Core Results web part

2.       XSL

3.       Visual Studio (optional but recommended)

This solution does not require any programming (at least in a C#/VB.NET sense).  It does not require SharePoint Designer.

Overall, we follow these steps:

1.       Locate the page where we want to add the department contacts.

2.       Edit the page and add a People Search Core Results web part where appropriate.

3.       Modify the web part for look and feel and query parameters.

4.       Modify the web part’s XSL to display the data in a grid format (best done in visual studio, but any text editor will do).

Add a People Search Core Results Web Part

Locate the page where you want to show the department contacts and edit the page.

Click “add a web part” and select “People Search Core Results” from the gallery:

clip_image004

Modify Fixed Keyword Query

After it has been added, modify the web part and expand the “Fixed Keyword Query” section as shown:

clip_image006

This tells the web part to “feed itself” so to speak.  Instead of looking for the user to enter search terms, it instead uses whatever we enter into the “Fixed Keyword Query”.  In the example above, we tell the web part to run a query that returns any person whose department equals “IT” (for information technology).

See here (http://msdn2.microsoft.com/en-us/library/ms467796.aspx) for the MSDN documentation on keyword queries to learn more options that might be useful here.

Modify Results Query Options

Even though we’ve just specified a fixed keyword query on the web part, we need to tell it to use the results of fixed keyword query we just defined as opposed to the results of some other query.  Do this as shown:

clip_image008

Enjoy the Intermediate Results

At this point, we have a fully functioning embedded people search that only shows contact information for those users whose department equals the literal value “IT”.  MOSS presents the contacts using the same layout you get when you do a people search from anywhere (i.e. picture of the user, specially formatted contact details, etc).  For a department level contacts list, we want a much more minimalist result.

You can cross-check your work.  Use advanced search to search for People whose department = “IT”.  The results should be identical.

Modify the XSL to Generate a Grid Layout

Luckily for us, the People Search Core Results (and its partner, the simple Search Core Results), unlike the Content Query Web Part, uses just one XSL “file” for transforming query results to HTML.  As a result, we can make straight forward changes to generate the output we want.

I’ve included XSL that generates the minimalist layout at the end of the article.  There are two key facets to it.

First, at its root, it generates an html table, as in: <table><tr><td> … </td></tr></table>

Second, It uses the <xsl:sort> directive.

This is the key bit of XSL:

    <table cellpadding="1" cellspacing="5" width="100%">

      <xsl:for-each select="All_Results/Result">

        <xsl:sort select="preferredname"/>

        <!-- Emit <tr> and <td> tags for the columns you want to show -->

      </xsl:for-each>

    </table>


We are manually iterating through the search result set  (“ALL_Results/Result”) and telling the parser to sort via “preferredname” (<xsl:sort select=”preferredname”/>).

It should be obvious how to sort by another field, such as email address.

Use Visual Studio

I always find it easiest to use visual studio to craft my XML.  When properly configured (as described here, http://paulgalvin.spaces.live.com/blog/cns!1CC1EDB3DAA9B8AA!132.entry), visual studio provides Intellisense support for the XSL itself.

Benefits to This Approach

Organizations derive at least two benefits from this approach.

First, department members are often managed in active directory.  Active directory drives People search via the full and incremental user profile import process (a shared service in MOSS).  Therefore, the information is already centrally managed from a data input perspective.  If we can trust active directory to provide good information (which is admittedly a stretch for some organizations), there is no reason to add a new redundant source of contact details via a Contacts web part.

Second, this approach provides a high visibility feedback mechanism to active directory managers.   End users will see their name and title and other profile data on their department main page (or wherever their contact data is displayed) and in a manner more public than the user’s My Site.  If that information is incorrect, they have a good incentive to notify AD managers who can clean up those users’ AD data.  In some cases, it may be easier to manage incorrect AD data this way rather than attempting a brute force, top-down project to clean up AD.

As AD data is cleaned, it becomes more valuable and can be used in other areas of SharePoint (e.g. via Colleagues), My Sites and even other applications in your enterprise that leverage active directory.

Other Resources

If you found this article to be interesting, the following related resources may also be of interest:

·         XSL Primer (http://www.whitefrost.com/documents/html/technical/xsl/xslPrimer.html): I find myself referring to this site on a fairly regular basis.

·         This MSDN forum posting (http://forums.microsoft.com/forums/ShowPost.aspx?PostID=2683595&SiteID=1) includes some questions and answers on this technique.

·         Display Content Query Web Part results in a grid (http://paulgalvin.spaces.live.com/blog/cns!1CC1EDB3DAA9B8AA!491.entry)

·         Embed hyperlinks into the XSL (http://paulgalvin.spaces.live.com/blog/cns!1CC1EDB3DAA9B8AA!301.entry).

XSL

The following XSL replaces the default provided by the web part and displays a minimalist grid format.  It could be trimmed further.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
  <xsl:param name="ResultsBy" />
  <xsl:param name="ViewByUrl" />

  <xsl:param name="ViewByValue" />

  <xsl:param name="IsNoKeyword" />

  <xsl:param name="IsFixedQuery" />

  <xsl:param name="MoreResultsText" />

  <xsl:param name="MoreResultsLink" />

  <xsl:param name="CollapsingStatusLink" />

  <xsl:param name="CollapseDuplicatesText" />

  <xsl:param name="MeHeaderValue" />

  <xsl:param name="CollHeaderValue" />

  <xsl:param name="CollOfCollHeaderValue" />

  <xsl:param name="EveryoneHeaderValue" />

  <xsl:param name="AddToMyColleaguesText" />

  <xsl:param name="SrchRSSText" />

  <xsl:param name="SrchRSSLink" />

  <xsl:param name="ShowMessage" />

  <xsl:param name="ShowActionLinks" />

 

  <!-- When there is keyword to issue the search -->

  <xsl:template name="dvt_1.noKeyword">

    <span class="ms-sbplain">

      <xsl:choose>

        <xsl:when test="$IsFixedQuery">

          Please set the 'Fixed Query' property for the webpart.

        </xsl:when>

        <xsl:otherwise>

          Enter one or more words to search for in the search box.

        </xsl:otherwise>

      </xsl:choose>

    </span>

  </xsl:template>

 

 

  <!-- When empty result set is returned from search -->

  <xsl:template name="dvt_1.empty">

    <xsl:if test="$ShowActionLinks">

      <div class="srch-sort">

        <xsl:if test="string-length($SrchRSSLink) &gt; 0">

          <a type="application/rss+xml" href ="{$SrchRSSLink}" title="{$SrchRSSText}" id="SRCHRSSL">

            <img border="0" src="/_layouts/images/rss.gif" alt=""/>

            <xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text>

            <xsl:value-of select="$SrchRSSText"/>

          </a>

        </xsl:if>

      </div>

    </xsl:if>

    <br/>

    <br/>

 

    <span class="ms-sbplain" id="CSR_NO_RESULTS">

      No contacts were found for this department.  Ensure that the fixed keyword query component to this

      People Search Core Results is properly defined and that the Cross Web Part Query is correct.

    </span>

  </xsl:template>

 

 

  <!-- Main body template. Sets the Results view (Relevance or date) options -->

  <xsl:template name="dvt_1.body">

    <xsl:if test="$ShowActionLinks">

      <div class="srch-sort">

        <xsl:value-of select="$ResultsBy" />

        <xsl:if test="$ViewByUrl">

          |

          <a href ="{$ViewByUrl}" id="CSR_RV" title="{$ViewByValue}">

            <xsl:value-of select="$ViewByValue" />

          </a>

        </xsl:if>

        <xsl:if test="string-length($SrchRSSLink) &gt; 0">

          |

          <a type="application/rss+xml" href ="{$SrchRSSLink}" title="{$SrchRSSText}" id="SRCHRSSL">

            <img border="0" src="/_layouts/images/rss.gif" alt=""/>

            <xsl:text disable-output-escaping="yes">&amp;nbsp;</xsl:text>

            <xsl:value-of select="$SrchRSSText"/>

          </a>

        </xsl:if>

      </div>

      <div style="margin-top: 15px;"></div>

      <br />

      <br />

    </xsl:if>

 

    <table cellpadding="1" cellspacing="5" width="100%">

 

      <xsl:for-each select="All_Results/Result">

        <!-- Wrap all of our grid output logic inside an <xsl:sort> directive.  -->

        <xsl:sort select="preferredname"/>

 

        <!--

          Put column headers here if you want.  I took a more minimalist

          approach since the column information is self-evident.

        -->

        <tr>

       

          <td>

            <xsl:value-of select="preferredname"/> <!-- This is usually Last Name, First Name -->

          </td>

 

          <td>

            <xsl:variable name="email" select="workemail"/>

            <a href="mailto:{$email}">

                <xsl:value-of select="workemail"/>

            </a>

          </td>

 

          <td>

            <xsl:value-of select="jobtitle" />

          </td>

 

          <td>

            <xsl:value-of select="workphone" />

          </td>

 

          <td>

            <xsl:value-of select="officenumber" />

          </td>

 

        </tr>

      </xsl:for-each>

    </table>

  </xsl:template>

 

 

  <xsl:template name="HitHighlighting">

    <xsl:param name="hh" />

    <xsl:apply-templates select="$hh"/>

  </xsl:template>

 

  <xsl:template match="ddd">

    &#8230;

  </xsl:template>

  <xsl:template match="c0">

    <b>

      <xsl:value-of select="."/>

    </b>

  </xsl:template>

  <xsl:template match="c1">

    <b>

      <xsl:value-of select="."/>

    </b>

  </xsl:template>

  <xsl:template match="c2">

    <b>

      <xsl:value-of select="."/>

    </b>

  </xsl:template>

  <xsl:template match="c3">

    <b>

      <xsl:value-of select="."/>

    </b>

  </xsl:template>

  <xsl:template match="c4">

    <b>

      <xsl:value-of select="."/>

    </b>

  </xsl:template>

  <xsl:template match="c5">

    <b>

      <xsl:value-of select="."/>

    </b>

  </xsl:template>

  <xsl:template match="c6">

    <b>

      <xsl:value-of select="."/>

    </b>

  </xsl:template>

  <xsl:template match="c7">

    <b>

      <xsl:value-of select="."/>

    </b>

  </xsl:template>

  <xsl:template match="c8">

    <b>

      <xsl:value-of select="."/>

    </b>

  </xsl:template>

  <xsl:template match="c9">

    <b>

      <xsl:value-of select="."/>

    </b>

  </xsl:template>

 

  <xsl:template match="All_Results/DummyResult/Me">

    <span class="srch-SocDistTitle">

      <xsl:value-of select="$MeHeaderValue" />

    </span>

 

  </xsl:template>

 

  <xsl:template match="All_Results/DummyResult/Colleague">

    <span class="srch-SocDistTitle">

      <xsl:value-of select="$CollHeaderValue" />

    </span>

 

  </xsl:template>

  <xsl:template match="All_Results/DummyResult/ColleagueOfColleague">

    <span class="srch-SocDistTitle">

      <xsl:value-of select="$CollOfCollHeaderValue" />

    </span>

  </xsl:template>

 

  <xsl:template match="All_Results/DummyResult/Everyone">

    <span class="srch-SocDistTitle">

      <!-- (everyoneheadervalue) <xsl:value-of select="$EveryoneHeaderValue" /> -->

      Transportation Department Team Members and Contacts

    </span>

  </xsl:template>

 

  <!-- document collapsing link setup -->

  <xsl:template name="DisplayCollapsingStatusLink">

    <xsl:param name="status"/>

    <xsl:param name="url"/>

    <xsl:if test="$CollapsingStatusLink">

      <xsl:choose>

        <xsl:when test="$status=1">

          <br/>

          <xsl:variable name="CollapsingStatusHref" select="concat(substring-before($CollapsingStatusLink, '$$COLLAPSE_PARAM$$'), 'duplicates:&quot;', $url, '&quot;', substring-after($CollapsingStatusLink, '$$COLLAPSE_PARAM$$'))"/>

          [<a href="{$CollapsingStatusHref}" title="{$CollapseDuplicatesText}">

            <xsl:value-of select="$CollapseDuplicatesText"/>

          </a>]

        </xsl:when>

      </xsl:choose>

    </xsl:if>

  </xsl:template>

 

  <!-- XSL transformation starts here -->

  <xsl:template match="/">

    <xsl:choose>

      <xsl:when test="$IsNoKeyword = 'True'" >

        <xsl:call-template name="dvt_1.noKeyword" />

      </xsl:when>

      <xsl:when test="$ShowMessage = 'True'">

        <xsl:call-template name="dvt_1.empty" />

      </xsl:when>

      <xsl:otherwise>

        <xsl:call-template name="dvt_1.body"/>

      </xsl:otherwise>

    </xsl:choose>

  </xsl:template>

  <!-- End of Stylesheet -->

</xsl:stylesheet>

Subscribe to my blog.

 

Technorati Tags:
Published Monday, March 10, 2008 8:04 PM by Anonymous
Filed under:

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

 

SharePoint, SharePoint and stuff said:

Entwicklung SharePoint Cross List Queries in a custom UserControl Adding Video to a SharePoint Site How

March 13, 2008 3:06 PM
 

Mirrored Blogs said:

Entwicklung SharePoint Cross List Queries in a custom UserControl Adding Video to a SharePoint Site How

March 13, 2008 4:11 PM
 

Darrell Phillips said:

How do you list everyone and then group by Department?

May 1, 2008 1:16 AM
 

Heero Yuy said:

What other fields besides "Department" can you filter through? Is there a list you can point me to? Does this list have to do with the variables located in the "User Profiles and Properties" section in the Shared Service Provider Admin?

May 6, 2008 10:31 PM
 

Anonymous said:

Darrell, sorry for the late response.  People have said that they can only get this approach to show 50 items at a time.  I've wanted for a long time to reproduce that problem and try to solve it, but I have had not had time.

That said, to group it, you would probably have to do your own manual break groups in the XSL.  I learned about "break groups" in computer science class back around 1990 and not even sure they bother teaching that stuff any more.  If you don't know what I mean by that, send me an email to paul.galvin@conchango.com and I'll try to relate it to XSL.

May 7, 2008 2:52 PM
 

Anonymous said:

Heero Yuy,

I believe you can filter on any managed property.  You can see those via the SSP and user profiles.  Email me if that's too vague for you.

May 7, 2008 2:53 PM
 

Ulrich Bernskov said:

If you have time to update your post with the needed breakdown it would be excelent.

Thanks for your post. It has pointed me in the right direction.

July 6, 2008 8:48 AM
 

Victor said:

How about this XSL WITH Pictures?

Please?

Thanks

August 16, 2008 11:49 PM
 

Jeff said:

Wow, this is EXACTLY what I was looking for; a straightforward post on how to dynamically generate a departmental list of people from Active Directory.

Twittered, Stumbled, and bookmarked.

Cheers.

August 29, 2008 6:14 AM
 

CC said:

thank you for this post!

September 12, 2008 9:27 PM
 

Marcin said:

Great post! Thanks a lot.

Is it possible to make the column with names clickable? I mean hyperlinks to peoples profile view, there also photos and other information would be accessible?

Cheers.

September 19, 2008 9:35 PM
 

Victor said:

I am running into a problem where some of the email addresses are displaying in ALL CAPS and others are all lowercase. Anyone know why, has a solution?

I checked the profiles of these people and their emails are all lower case everywhere I look, including AD itself.

September 25, 2008 9:02 PM
 

Jeff said:

One moment, it works, the next, it dies.

For months it was working; ran some server updates the other day and boom!, core results die.

No contacts were found for this department. Ensure that the fixed keyword query component to this People Search Core Results is properly defined and that the Cross Web Part Query is correct.

Any idea why this might be? Thanks in advance...

January 22, 2009 8:24 PM
 

Ricky Singh said:

how do i display "Manager" field in the search results. i have added some custom fileds like Phone extension and it works but still not able to figure out how to display "manager" field?

August 12, 2009 5:47 PM
 

Josh Moore said:

The Peolpe Search Core results web part is limited to 50 rows per page, before you have to check the 'view more results' which creates a link that does not point at our search web application located at a different URL. Any ideas how to fix this?

August 27, 2011 12:48 AM
 

Andrew said:

Can you get the query to filter by AD Group membership? Some people are not members of Department, but part of a team which is within AD.

January 16, 2012 12:29 PM
 

Noel said:

Is there a way to use the fixed keyword search to filter by SharePoint Group? I've added users into a SharePoint group but as yet have not been able to find the correct Crawled Property that holds this value.

April 30, 2012 7:26 AM
 

Bill Schwein said:

Worked great.  Thanks!

March 29, 2013 3:06 PM
 

Norma said:

Thanks Paul - that really helped!

May 19, 2013 12:15 PM
 

Khushi said:

Thanks for your post. Quick question - Department field contains multiple department Accounting, Marketing. On marketing page I put the Department:"Marketing" in fixed query but it is not appearing in result. Is there any query that can work for "CONTAINS" ?

Regards,

Khushi

June 5, 2014 7:06 PM
 

Khushi said:

Thanks for your post. Quick question - Department field contains multiple department Accounting, Marketing. On marketing page I put the Department:"Marketing" in fixed query but it is not appearing in result. Is there any query that can work for "CONTAINS" ?

Regards,

Khushi

June 5, 2014 7:06 PM
 

Khushi said:

Thanks for your post. Quick question - Department field contains multiple department Accounting, Marketing. On marketing page I put the Department:"Marketing" in fixed query but it is not appearing in result. Is there any query that can work for "CONTAINS" ?

Regards,

Khushi

June 5, 2014 7:06 PM
 

Aniket said:

Hello Mate,

Thanks for wonderful post. I was trying to filter using Department:"Operations" query. My output is filtering but it also showing users of "Engineering Operations" department so do you know how to fix output to exact match??

Thanks in Advance

September 1, 2014 7:35 AM

Leave a Comment

(required) 
(optional)
(required) 
Submit
Powered by Community Server (Personal Edition), by Telligent Systems