Parmi les blogueurs SharePoint les plus insolites, il en est un en particulier qui sort du lôt notamment par son écriture pleine d'humour : Sahil Malik. Son dernier billet notamment m'a tellement fait rire que je me suis décidé de le relayer. Voilà l'explication :
Pour ceux qui ont suivi les derniers billets de Gribouillon et moi-même sur la Content Query Webpart, vous avez vu que c'est une webpart qui peut s'avérer très utile et qui permet de récupérer et formatter simple enormément de données.
Néanmoins il existe certaines limitations, notamment concernant les audiences comme en parle Gribouillon mais aussi concernant la génération de Rss, toutes les problématiques liées aux normes W3C et à la portée de la requête (limitée à une collection de site).
C'est justement pour pallier à ces derniers points que Sahil Malik a décidé de créer le projet CARBURETUR, pour Content Aggregation, Rendering, Binding, Unlimited Reuse, External conTent inclusive, Using RSS...
L'idée principale derrière ce nom "particulier" est de pouvoir générer un flux rss à partir de n'importe quelle liste SharePoint voire même n'importe quelle View (vue). Le tout avec un flux Rss "propre".
La deuxième idée est de pouvoir agréger et transformer ce flux avec du XSLT pour faire "grosso modo" ce que vous désirez en terme d'affichage.
Ce code est composé d'une page pour générer le flux Rss et d'un Webpart pour gérer le contenu :
<%@ Page Language="C#" %>
<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Import Namespace="System.Text" %>
<script runat="server">
public void Page_Load()
{
Response.Clear();
Response.ContentType = "text/xml";
string blah = Request.QueryString["View"];
try
{
Response.Write(
GetRSSFromListView(
Request.QueryString["List"],
Request.QueryString["View"])
);
}
catch (Exception ex)
{
Response.Write("<pre>");
Response.Write(ex.ToString());
Response.Write("</pre>");
}
}
private static string GetRSSFromListView(string strListGUID, string strViewGUID)
{
StringBuilder sb = new StringBuilder();
sb.Append("<?xml version=\"1.0\"?>") ;
sb.Append("<rss version=\"2.0\">");
Guid listGuid = new Guid(
HttpContext.Current.Server.UrlDecode(strListGUID)) ;
SPSite site = SPContext.Current.Site;
SPWeb web = site.OpenWeb();
SPList list = web.Lists[listGuid];
SPView view = null;
if (strViewGUID != null)
{
Guid viewGuid = new Guid(
HttpContext.Current.Server.UrlDecode(strViewGUID));
view = list.Views[viewGuid];
}
else
{
view = list.DefaultView;
}
sb.Append("<channel>");
AddTag("title", list.Title, sb);
AddTag("description", list.Description, sb);
//// I have the view, now lets start spewing out the RSS
SPListItemCollection items = list.GetItems(view);
foreach (SPListItem item in items)
{
sb.Append("<item>");
AddTag("title", item["LinkTitle"].ToString(), sb);
AddTag("link", list.RootFolder.Url + "/DispForm.aspx?ID=" + item.ID, sb);
sb.Append("<description>");
foreach (string viewField in view.ViewFields)
{
if (viewField != "LinkTitle")
{
AddTag(
viewField.Replace("_x0020_", " "),
HttpContext.Current.Server.HtmlEncode(item.GetFormattedValue(viewField)),
sb);
}
}
sb.Append("</description>");
sb.Append("</item>");
}
sb.Append("</channel>");
sb.Append("</rss>");
return sb.ToString();
}
private static void AddTag(string tagText, string tagValue, StringBuilder sb)
{
sb.Append("<");
sb.Append(tagText.Replace(" ", "_"));
sb.Append(">");
sb.Append(HttpContext.Current.Server.HtmlEncode(tagValue));
sb.Append("</");
sb.Append(tagText.Replace(" ", "_"));
sb.Append(">");
}
</script>
RSSRender WebPart -
(The OOTBXSLT.xml is an embedded resource that gives it some default rendering OOTB).
using System;
using System.Runtime.InteropServices;
using System.Web.UI;
using System.Web.UI.WebControls.WebParts;
using System.Xml;
using System.Xml.Serialization;
using Microsoft.SharePoint;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint.WebPartPages;
using System.Xml.Xsl;
using System.IO;
using System.Reflection;
using System.Xml.XPath;
namespace RSSRender
{
[Guid("ab18a8de-2765-4c1e-b99a-82f93a27f667")]
public class RSSRender : System.Web.UI.WebControls.WebParts.WebPart
{
private string rssUrl;
private string xslTransform;
[WebBrowsable(true)]
[Personalizable(true)]
public string XSLTransform
{
get { return xslTransform; }
set { xslTransform = value; }
}
[WebBrowsable(true)]
[Personalizable(true)]
public string RssUrl
{
get { return rssUrl; }
set { rssUrl = value; }
}
public RSSRender()
{
this.ExportMode = WebPartExportMode.All;
TextReader ootbXSLTStream =
new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream("RSSRender.OOTBXSLT.xml"));
xslTransform = ootbXSLTStream.ReadToEnd();
}
protected override void Render(HtmlTextWriter writer)
{
XmlDocument rssDoc = new XmlDocument();
try
{
System.Net.WebClient wc = new System.Net.WebClient();
wc.Credentials = System.Net.CredentialCache.DefaultCredentials;
byte[] rssBytes = wc.DownloadData(rssUrl);
string rssText = System.Text.ASCIIEncoding.ASCII.GetString(rssBytes, 3, rssBytes.Length - 3);
rssDoc.LoadXml(rssText);
}
catch (Exception ex)
{
writer.Write("Feed not available at this time! Error message:<pre>" + ex.ToString() + "</pre>");
writer.Write(System.Security.Principal.WindowsIdentity.GetCurrent().Name);
}
XmlDocument xsltDoc = new XmlDocument();
xsltDoc.LoadXml(xslTransform);
writer.Write(Transform(rssDoc, xsltDoc));
}
private static string Transform(IXPathNavigable input, IXPathNavigable xslt)
{
XslCompiledTransform xsltProcessor = new XslCompiledTransform();
xsltProcessor.Load(xslt);
Stream results = new MemoryStream();
if (input is XmlDocument)
{
xsltProcessor.Transform(input, null, results);
}
results.Position = 0;
StreamReader rdr = new StreamReader(results);
return rdr.ReadToEnd();
}
}
}
Vous l'aurez compris en regardant le code, il y a beaucoup d'optimizations possibles aussi en bien en terme de déploiement que de code en lui-même. Sahil entend bien sur l'améliorer, voire créer un projet sur Codeplex si cela s'avère nécessaire.
J'avoue que voir un projet Codeplex nommé CARBURETUR for SharePoint me ferait franchement bien rigolé :)
<Philippe/>