Eine Liste innerhalb der Websitesammlung anzeigen

Eine Frage, die immer wieder aufkommt, ist die, wie man die Daten einer Liste oder einer Bibliothek in einer anderen Website anzeigen kann.

Bei SharePoint 2007 gab es in der Datenquellenbibliothek von SharePoint Designer 2007 den Link "Mit einer anderen Website verbinden". Damit konnte man sich mit jeder Website innerhalb der Websitesammlung verbinden und dann ganz einfach die Daten aller dort vorhandenen Listen und Bibliotheken anzeigen lassen. Diese Möglichkeit besteht jetzt zwar nicht mehr, aber es ist trotzdem nicht schwierig.

Man geht dazu auf eine beliebige Webpart-Seite der Website, in der sich die Liste oder Bibliothek befindet. Man kann dazu auch einfach die default.aspx verwenden. Man versetzt die Seite in den Bearbeitungsmodus…

…und fügt dann das Webpart der Liste oder Bibliothek ein, das man unter "Listen und Bibliotheken" findet.

Natürlich kann man zum Einfügen des Webparts auch den SharePoint Designer verwenden. Wenn man eine Webpart-Seite geöffnet hat, findet man alle Listen und Bibliotheken im Reiter "Einfügen" unter "Datenansicht".

Das Aussehen des Webparts kann man jetzt nach Belieben verändern. Sobald man damit zufrieden ist, öffnet man die Seite im SharePoint Designer (falls noch nicht geschehen) und markiert das Webpart. Im Reiter "Webpart" findet man oben rechts die Funktion "In Websitekatalog":

Wenn man darauf klickt, erscheint ein Dialog, bei dem man einen Namen und optional eine Beschreibung angeben kann. Voreingestellt ist der Name der Liste oder Bibliothek. Unter diesem Namen erscheint das Webpart später im Webpartkatalog. Wenn man den Dialog mit "OK" bestätigt, erscheint folgende Messagebox:

Hier muß unbedingt auf "Ja" geklickt werden, sonst funktioniert das Webpart später nicht wie erwartet!

Das war’s auch schon. Die Ansicht ist jetzt als wiederverwendbares Webpart im Webpartkatalog gespeichert und kann innerhalb der gesamten Websitesammlung verwendet werden. Man findet es in der Kategorie "Custom" oder "Benutzerdefiniert", aber das läßt sich im Webpartkatalog ändern.

Das Webpart, das weiter oben eingefügt wurde, kann jetzt getrost wieder entfernt werden. Es diente nur dazu, die gewünschte Ansicht in den Webpartkatalog speichern zu können und ist nicht mehr länger notwendig.

CAML-Abfragen in SharePoint

In diesem Beitrag soll gezeigt werden, wie CAML-Abfragen in SharePoint gemacht werden können. Er gilt gleichermaßen für SharePoint 2007 und SharePoint 2010. Die offizielle Referenz zum verwendeten XML-Schema findet sich hier auf MSDN (für SharePoint 2010).

Die Motivation zu diesem Beitrag entstand dadurch, daß ich selbst etwas zum Nachschlagen brauchte. Die Methoden zum Abfragen unterschiedlicher Feldtypen und die verwendbaren Token und Vergleichsoperatoren habe ich auch nicht immer auswendig parat. Ich werde die Sammlung im Laufe der Zeit ergänzen, wenn mir selbst etwas Neues unterkommt oder wenn ich auf Fehlendes hingewiesen werde.

Als Entwickler kommt man mit CAML wahrscheinlich am Häufigsten beim Abfragen von Listenelementen per Code in Kontakt. Man gibt für die Abfrage ein oder mehrere Kriterien an, nach denen die Ergebnismenge gefiltert wird, und optional ein oder mehrere Felder, nach denen die Ergebnisse sortiert werden sollen.

Eine einfache Abfrage kann z.B. so aussehen:

SPQuery query = new SPQuery();
query.Query = @“<Where>
                  <Eq>
                    <FieldRef Name=’Title’/>
                    <Value Type=’Text‘>Hallo</Value>
                  </Eq>
                </Where>
                <OrderBy>
                  <FieldRef Name=’ID’/>
                </OrderBy>“;
SPListItemCollection items = myList.GetItems(query);

Diese Abfrage liefert alle Listenelemente, deren Titel Hallo entspricht, aufsteigend sortiert nach ID. Beim Zusammenstellen der Query kann man auch auf System.Xml.Linq zurückgreifen. Dieselbe Abfrage sieht dann so aus:

query.Query = new XElement(„Where“,
                new XElement(„Eq“,
                  new XElement(„FieldRef“, new XAttribute(„Name“, „Title“)),
                  new XElement(„Value“, new XAttribute(„Type“, „Text“), „Hallo“)
                )
              ).ToString(SaveOptions.DisableFormatting) +
              new XElement(„OrderBy“,
                new XElement(„FieldRef“, new XAttribute(„Name“, „ID“))
              ).ToString(SaveOptions.DisableFormatting);

FieldRef

Beim Name-Attribut der FieldRef-Elemente muß immer der interne Name der Felder angegeben werden. Der sichtbare Name kann nicht verwendet werden. Anstelle von Name kann auch ein ID-Attribut angegeben werden, das dann die GUID des Feldes enthalten muß. Eine Liste mit den internen Namen und IDs der Standardfelder findet man z.B. hier.

Sortierung

Wenn nichts anderes angegeben wird, wird immer in aufsteigender Reihenfolge sortiert. Wenn in absteigender Reihenfolge sortiert werden soll, wird ein zusätzliches Ascending-Attribut mit dem Wert FALSE angegeben:

<FieldRef Name=’ID‘ Ascending=’FALSE’/>

Natürlich kann auch nach mehreren Feldern sortiert werden, indem man mehrere FieldRef-Elemente angibt. Sie werden in der angegebenen Reihenfolge und in der jeweils angegebenen Sortierrichtung berücksichtigt.

Mehrere Werte abfragen

Wenn man mehrere Werte abfragen möchte, muß man die Einzelabfragen mit And– oder Or-Elementen klammern:

<Where>
  <Or>
    <Eq>
      <FieldRef Name=‘Title‘/>
      <Value Type=‘Text‘>Hallo</Value>
    </Eq>
    <Eq>
      <FieldRef Name=‘Title‘/>
      <Value Type=‘Text‘>Welt</Value>
    </Eq>
  </Or>
</Where>

Diese Abfrage liefert alle Elemente, deren Titel entweder Hallo oder Welt entspricht.

Es können immer nur zwei Einzelabfragen geklammert werden. Wenn man mehr Abfragen braucht, muß man eine neue Klammer verwenden:

<Where>
  <And>
    <Or>
      <Eq>
        <FieldRef Name=‘Title‘/>
        <Value Type=‘Text‘>Hallo</Value>
      </Eq>
      <Eq>
        <FieldRef Name=‘Title‘/>
        <Value Type=‘Text‘>Welt</Value>
      </Eq>
    </Or>
    <Gt>
      <FieldRef Name=‘ID‘/>
      <Value Type=‘Number‘>15</Value>
    </Gt>
  </And>
</Where>

Diese Abfrage liefert alle Elemente, deren Titel entweder Hallo oder Welt entspricht und deren ID größer als 15 ist.

Vergleichsoperatoren

Folgende Vergleichsoperatoren können verwendet werden:

Eq ist gleich (equals)
Neq ist nicht gleich (not equals)
Gt größer als (greater than)
Geq größer als oder gleich (greater or equals)
Lt kleiner als (less than)
Leq kleiner als oder gleich (less or equals)
IsNull ist null, d.h. leer
IsNotNull ist nicht null, d.h. nicht leer
BeginsWith beginnt mit (Zeichenfolge)
Contains enthält (Zeichenfolge)
Nachschlagefelder

Bei Nachschlagefeldern muß man aufpassen. Wenn nichts weiter beachtet wird, muß als Value der Texteintrag des Nachschlagefeldes angegeben werden. Wenn man stattdessen die nachgeschlagene ID abfragen möchte, muß es so aussehen:

<FieldRef Name=“Lookup“ LookupId=“True“/>
<Value Type=“Lookup“>15</Value>

Personenfelder

Personenfelder sind intern wie Nachschlagefelder aufgebaut (weil damit in der Benutzerliste nachgeschlagen wird) und verhalten sich deshalb ähnlich. Wenn man nichts weiter beachtet, muß man als Value den Anmeldenamen verwenden. Wenn man nach der ID eines bestimmten Benutzers filtern möchte, muß man bei Value Type=“Integer“ angeben.

Filtern nach dem aktuellen Benutzer, d.h. nach dem Benutzer, der die Abfrage ausführt, kann man so:

<Value Type=“Integer“><UserID/></Value>

Gruppenmitgliedschaft auflösen

Bei Elementen mit einem Personenfeld gibt es eine Möglichkeit alle Elemente zu erhalten, bei denen in diesem Feld Personen aus Gruppen stehen, bei denen auch der aktuelle Benutzer Mitglied ist. Das funktioniert so z.B. bei der vordefinierten Ansicht Nach meinen Gruppen bei Aufgabenlisten. Die Abfrage dazu sieht so aus:

<Where>
  <Membership Type=“CurrentUserGroups“>
<FieldRef Name=“AssignedTo“/>
</Membership>
</Where>

Ja/Nein Felder

Bei Ja/Nein-Feldern muß als Value 0 oder 1 angegeben werden. True oder false funktionieren nicht!

<Value Type=“Boolean“>0</Value>

Datumsfelder

Auch Datumsfelder müssen besonders beachtet werden. Ohne weiteres Zutun wird bei Datumsvergleichen nur der Tagesanteil beachtet und der Zeitanteil wird ignoriert. Wenn der Zeitanteil ebenfalls beachtet werden soll, muß dem Value-Element ein IncludeTimeValue-Attribut mit dem Wert True hinzugefügt werden. Das Datum selbst muß in folgendem Format angegeben werden:

<Value Type=“DateTime“ IncludeTimeValue=“True“>yyyy-MM-ddThh:mm:ssZ</Value>

Wie man wiederkehrende Ereignisse einer Kalenderliste abfragen kann, habe ich in einem separaten Beitrag hier beschrieben.

Token

Als Value können folgende Token verwendet werden:

<Today/> liefert das aktuelle Datum ohne Zeitanteil. Es kann ein Attribut Offset oder OffsetDays angegeben werden, das einen Offset in ganzen Tagen angibt (kann auch negativ sein):

<Today OffsetDays=“2″/>

<Now/> liefert das aktuelle Datum inklusive Zeitanteil.

<UserID/> liefert die ID des aktuellen Benutzers.

List-Joins und ProjectedFields

Wie man mehrere Listen in Abfragen verbinden kann, habe ich in einem separaten Beitrag gezeigt.

Was es sonst noch zu beachten gibt

Abfragen mit SPQuery liefern standardmäßig immer alle Felder der Listenelemente, auch alle versteckten. Wenn man die nicht alle braucht, kann man die gewünschten Felder angeben, was sich besonders bei Listen mit sehr vielen Feldern empfiehlt. Dazu belegt man die Eigenschaft ViewFields des SPQuery-Objekts mit ein oder mehreren FieldRef-Elementen. Die Abfrage liefert dann nur noch die angegebenen Felder.

Standardmäßig liefert SPQuery nur Elemente, die sich im Root-Ordner einer Liste befinden. Wenn man auch Elemente aus Unterordnern haben möchte, belegt man die Eigenschaft ViewAttributes mit Scope=“Recursive“. Wenn man auch die Ordner selbst haben möchte, kann man Scope=“RecursiveAll“ angeben.