Sharepoint RSS Viewer Web Part mit XSLT optimieren
Sharepoint RSS Viewer Web Part mit XSL optimieren
In diesem Posting beschreibe ich meine Erfahrung mit dem Microsoft Sharepoint RSS Viewer Web Part, insbesondere die Optimierung per XSL Editor.
Übersicht
Bei einem großen Kunden wurde für ca. 45.000 Mitarbeiter ein neues Intranet auf Basis von Microsoft SharePoint 2013 On-premise eingeführt. Im Intranet befinden sich sowohl redaktionelle Inhalte der globalen Unternehmenskommunikation, als auch Inhalte von lokalen Kommunikationsabteilungen und anderer Unternehmensorganisationen (z. B. Informationen von Produktmanagern). Das Design des Intranet ist an die CI des Kunden angelehnt und in einem Styleguide beschrieben.
Problemstellung
Im Rahmen des Media Monitoring sollen RSS Feeds in das Intranet eingebunden werden. Die Feeds stammen sowohl von internen, als auch von externen Quellen und liegen ausschließlich im Format RSS, Version 2.0 vor. Auf die Eigenschaften der Feeds kann keinen Einfluss genommen werden.
Wie sich bei einer Validierung [1] der einzubindenden Feeds zeigte, übertragen manche Feeds ein falsch kodiertes Veröffentlichungsdatum, welches nicht von der Funktion ddwrt:FormatDate erkannt wird. Dadurch erscheinen diese Feeds ohne Datum in der Ausgabe des Web Parts. Außerdem ist ein Feed dabei, der falsch kodierte HTML-Zeichen übermittelt, was es dem Leser erschwert, den Feed zu lesen.
Für die Einbindung der Feeds soll das RSS Viewer Web Part [2] verwendet werden. Dessen Darstellung des Feeds entspricht allerdings nicht dem Layout des Intranets, siehe Abbildung 1. Die Anpassung der CSS-Sammlung durch die IT soll vermieden werden.
Lösungsansatz
Die Ausgabe des RSS Viewer Web Parts kann per XSL-Editor verändert werden. In der XSL-Datei können Variablen definiert und berechnet werden und es können CSS-Klassen sowie kleine HTML-Snippets definiert werden.
Bezüglich des fehlerhaft übermittelten Veröffentlichungsdatums soll eine neue Variable myPubdate definiert werden, die das korrekt formatierte Veröffentlichungsdatum enthält. Dieses muss zuvor aus dem falsch formatierten Datum pubDate ermittelt werden.
Hinsichtlich der Darstellung des Feeds wurden im Styleguide bestimmte CSS-Klassen und HTML tags definiert, die für die Darstellung des Feeds verwendet werden sollen.
pubDate korrigieren
RSS Version 2.0 verlangt die Darstellung eines Datums im Format RFC-822 [3]. Die Fehlermeldung im online Feed Validator lautete deshalb: pubDate must be an RFC-822 date-time
Das übertragene Datum lautete beispielsweise "Monday, 28 November, 2016 – 15:19". Es war in mehrfacher Hinsicht nicht korrekt formatiert:
- Vollständiger Name des Wochentags, statt der Abkürzung mit 3 Buchstaben
- Vollständiger Monatsname, statt der Abkürzung mit 3 Buchstaben
- Angabe des Jahres mit Komma getrennt
- Angabe der Uhrzeit ohne Sekunden
- Angabe der Uhrzeit getrennt mit Leer- und Minuszeichen
- Keine Angabe der Zeitzone
Aus diesem Grund wurde die standardmäßige Ermittlung des Veröffentlichungsdatums des Web Parts, siehe Listing 1, ersetzt durch eine eigene Ermittlung, siehe Listing 2. Darin kann man Schritt für Schritt erkennen, wie der neue Wert der Variablen myPubDate aus den Bestandteilen des vorhandenen pubDate Strings ermittelt wird. Als Zeitzone wird fix CET gesetzt und dabei die Ungenauigkeit während der Gültigkeit von CEST in Kauf genommen. Das resultierende Datum kann jetzt problemlos von der Funktion ddwrt:FormatDate interpretiert werden.
Listing 1
<xsl:when test="string-length(pubDate) > 0">
<xsl:variable name="pubDateLength" select="string-length(pubDate) - 3" />
<xsl:value-of select="ddwrt:FormatDate(substring(pubDate,0,$pubDateLength),number($rss_LCID),3)"/>
</xsl:when>
Listing 2
<xsl:when test="string-length(pubDate) > 0">
<xsl:variable name="myDay" select="substring(pubDate,0,4)" />
<xsl:variable name="tmp" select="substring-before(pubDate, ' - ')" />
<xsl:variable name="myDate" select="substring-after($tmp, ', ')" />
<xsl:variable name="myTime" select="substring-after(pubDate, ' - ')" />
<xsl:variable name="myPubDate" select="concat($myDay,', ',$myDate,' ',$myTime,':00 +0100')" />
<xsl:value-of select="ddwrt:FormatDate($myPubDate,number($rss_LCID),3)"/>
</xsl:when>
Alles eine Frage der Darstellung
Mit Hilfe des Styleguides lässt sich bestimmen, wie die einzelnen Items des Feeds dargestellt werden sollen. Über die zentrale CSS Sammlung ließen sich entsprechende Klassen und HTML tags ermitteln. Die Aufgabe bestand darin, den einzelnen Bestandteilen eines Feed-Items die entsprechenden Klassen bzw. HTML tags zuzuweisen.
Da im aktuellen Fall alle RSS Feeds tatsächlich im Format RSS, in Version 2.0, bezogen werden können, reicht es aus, wenn man die Anpassungen auf das RSSMainTemplate beschränkt. Im einfachsten Fall muss nur die Klasse description ersetzt werden durch, z.B. die Klasse teaser, die es für das Portal bereits gab. Die Klasse description wird im Original allerdings mehrfach verwendet. In Abbildung 2 lässt sich der Zusammenhang zwischen XSL-Datei und ausgespieltem Inhalt ermitteln. Für die Darstellung des Veröffentlichungsdatums soll die Klasse news-slide-date verwendet werden. Dazu wird Zeile 88 in ein DIV tag eingefasst, siehe Listing 3 im Original bzw. Listing 4 mit der DIV-Erweiterung.
Listing 3
<xsl:value-of select="ddwrt:FormatDate(substring(pubDate,0,$pubDateLength),number($rss_LCID),3)"/>
Listing 4
<div class="news-slide-date">
<xsl:value-of select="ddwrt:FormatDate(substring(pubDate,0,$pubDateLength),number($rss_LCID),3)"/>
</div>
In gleicher Weise verfährt man mit dem "See more" Link, der im Original ab Zeile 83 definiert wird, siehe Listing 5. Im Portal Styleguide werden solche "See more" Links zwar in einer eigenen Klasse beschrieben (Klasse more), aber nicht in einem DIV tag, sondern in einem paragraph tag. Entsprechend abgeändert sieht Zeile 83 ff aus, siehe Listing 6.
Listing 5
<div class="description">
<a href="{ddwrt:EnsureAllowedProtocol(string(link))}">More...</a>
</div>
Listing 6
<p class="more">
<a href="{ddwrt:EnsureAllowedProtocol(string(link))}">Weiterlesen...</a>
</p>
Escaping
Bei der Validierung eines der Feeds trat die Fehlermeldung "title should not contain HTML: sup" auf. Die betroffene Zeile 61 steht in Listing 7.
Listing 7
<xsl:value-of select="title"/>
Im ersten Moment bin ich davon ausgegangen, dass der HTML tag <sup> falsch interpretiert wird oder dass der Feed Generator den tag nicht korrekt deklariert hat. Meine erste Lösung bestand darin, die Deklaration zu korrigieren durch die in Listing 8 genannten Zeilen.
Listing 8
<xsl:variable name="newtitle" select="translate(title,'</sup>','')"/>
<xsl:value-of select="$newtitle"/>
Damit konnte das Problem vorübergehend gelöst werden. Für eine allgemeinere Lösung bietet sich ein Blick in die RSS Spezifikation [4] an. Dort gibt es eine eigene Sektion mit Encoding Beispielen [5], aus der ersichtlich ist, dass "<sup>®</sup>" durchaus eine zulässiger String in einem Titel oder einer Beschreibung ist. Der gängige Lösungsvorschlag in einschlägigen Foren lautet daher den String mit dem Attribut "disable-output-escaping" und dem Wert "yes" zu versehen, siehe beispielsweise diesen Beitrag [6]. Dieses Vorgehen löst das Problem zuverlässig. Im Microsoft SharePoint Designer Team Blog [7] wird allerdings zu Recht darauf hingewiesen, dass dadurch das Risiko steigt, für Cross Site Scripting anfällig zu sein. Die bessere Lösung scheint die Verwendung der GetSafeHtml Methode [8] zu sein. Die fertige Lösung steht in Listing 9.
Listing 9
<xsl:if test="string-length(title) > 0">
<xsl:variable name="safeHtmlTitle">
<xsl:call-template name="GetSafeHtml">
<xsl:with-param name="Html" select="title"/>
</xsl:call-template>
</xsl:variable>
<xsl:value-of select="$safeHtmlTitle" disable-output-escaping="yes"/>
</xsl:if>
Bei dieser Lösung wird der Titel, der evtl. HTML tags enthält und falls er länger 0 ist, der Methode GetSafeHtml übergeben. Beim Rückgabewert der Methode kann dann Escaping deaktiviert werden, ohne gesteigertes XSS Risiko.
Ergebnis
Sind alle Änderungen im XSL-Editor eingepflegt und wurde die Seite eingecheckt bzw. veröffentlicht, dann sieht das Resultat wie in Abbildung 3 dargestellt aus.
Im Vergleich zur in Abbildung 1 gezeigten Ausgabe des Web Parts wird nun das Datum angezeigt und ist korrekt formatiert. Ausserdem wird der Titel des Feed Items und der eigentliche Inhalt mit der richtigen Formatierung dargestellt. Bei Bedarf kann natürlich noch der Hyperlink beim Titel entfernt werden.
Der zuvor unscheinbare Link "More..." wird jetzt dem Styleguide entsprechend als unterstrichener Hyperlink angezeigt mit grauem Hintergrund.
Fazit
Das RSS Viewer Web Part ist zwar alt, aber gut geeignet um RSS Feeds in einer SharePoint Umgebung anzuzeigen. Mittels XSL-Editor bietet es eine sehr flexible, wenn auch nicht intuitive Möglichkeit, die Ausgabe des Web Parts zu optimieren und abzusichern.
Links
[1] FEED Validator, http://www.feedvalidator.org/
[2] Add RSS feeds from external sites to your site, https://support.office.com/en-us/article/Add-RSS-feeds-from-external-sites-to-your-site-52C26FB9-F1E7-44B7-B684-DEA7B5788590?CorrelationId=dd764e66-e0cc-42e7-b7f5-dde1b52a2d96&ui=en-US&rs=en-US&ad=US&ocmsassetID=HA102851053
[3] RFC 822: Date and Time Specification, http://www.faqs.org/rfcs/rfc822.html
[4] RSS 2.0 specification, https://validator.w3.org/feed/docs/rss2.html
[5] Encoding & item-level descriptions, https://cyber.harvard.edu/rss/encodingDescriptions.html
[6] How to remove special characters in RSS feeds (RSS Viewer Web Part), https://social.technet.microsoft.com/Forums/office/en-US/2fd97888-a293-42a7-b751-a394bb80f61b/how-to-remove-special-characters-in-rss-feeds-rss-viewer-web-part?forum=sharepointadminlegacy
[7] Using “Disable Output Escaping” in Data View, https://msdn.microsoft.com/en-us/library/office/aa603437%28v=office.14%29.aspx