松崎 剛 Blog

This Blog's theme : エンタープライズ開発 (Server side)、Office サーバ開発

SharePoint 2010 : リスト定義における XSL を使用したビューのカスタマイズ

SharePoint 2010 : リスト定義における XSL を使用したビューのカスタマイズ

  • Comments 6

環境:
SharePoint 2010
Visual Studio 2010

こんにちは。

ご無沙汰してすみません。少し遅めの夏休みを取得しておりました。。。

今回は、SharePoint 2010 で可能な XSL によるリストビューのカスタマイズ方法について記載します。この XSL を使用したカスタマイズは、SharePoint Designer でも可能ですが、下記の通り、Visual Studio 2010 で作成したリスト定義のビュー (View) もこの方法でカスタマイズできます。

リストのビュー (View) のカスタマイズの全体像

まず、リストで使用されるビュー (.aspx ページ) ですが、このページの実体は、Visual Studio でリスト定義のプロジェクトを作成した際に作成されるスキーマ定義 (schema.xml) を見るとわかるように (こちら を参照)、既定で、%programfiles%\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\Pages フォルダにある viewpage.aspx が使用されています。(下記太字を参照)

<?xml version="1.0" encoding="utf-8"?>
<List xmlns:ows="Microsoft SharePoint" Title="カスタム支払リスト" Name="CustomListDefinition" . . .>
  <MetaData>
    . . .

    <Views>
      <View BaseViewID="0" . . .>
        . . . 

      </View>
      <View BaseViewID="1" DefaultView="TRUE"
            SetupPath="pages\viewpage.aspx"
            Url="AllItems.aspx"
. . .>
        . . .


このため、例えば、リストビューに独自なコントロールを貼り付けたい場合などは、リスト定義の要素ファイル (ElementFile) として独自な .aspx ファイルを作成し、これを schema.xml にビューページとして登録すれば OK です。(この具体的な手順については、こちら で記載したリストフォームのカスタマイズ方法と同様ですので、ここでは説明を省略します。)

上記の viewpage.aspx の中身を見ていただくとわかりますが、このページには、下記の通り、ID 属性が「Main」の WebPartZone が挿入されており、SharePoint 2010 はここに XsltListViewWebPart コントロールを挿入して、リストの一覧を表示しています。

. . .

<asp:Content ContentPlaceHolderId="PlaceHolderMain" runat="server">
  <WebPartPages:WebPartZone runat="server" FrameType="None" ID="Main" Title="loc:Main" />
</asp:Content>
. . .

XSL を使用したビューのカスタマイズ

ビューに部品 (Control) を挿入する程度のカスタマイズであれば、上述の通り、カスタムの .aspx ページを作成して、そこに必要なコントロールを挿入すれば充分ですが、リストアイテムの一覧表示そのものをカスタマイズしなければならない場合、上述の WebPartZone の中をカスタマイズする必要があります。

まずは、以前から使われている手法をご紹介しましょう。
例えば、こちら にも記載したように、CAML を使用して、下記太字の通り schema.xml でレンダリング用の HTML をカスタマイズできます。以下の例では、下図の通り、table タグを使用した簡単なリストのビューが表示されます。
この方法は、下記にように単にテーブルに値を表示する程度なら簡単ですが、複雑な処理を記述したい場合には、記述方法も独自で、結構大変な作業になってきます。

<?xml version="1.0" encoding="utf-8"?>
<List xmlns:ows="Microsoft SharePoint" Title="カスタム支払リスト" Name="CustomListDefinition" . . .>
  <MetaData>
    . . .

    <Views>
      <View BaseViewID="0" Type="HTML" MobileView="TRUE" TabularView="FALSE">
        . . .
      </View>
      <View BaseViewID="1"
            Type="HTML"
            WebPartZoneID="Main"
            SetupPath="pages\viewpage.aspx"
            Url="AllItems.aspx"
            DefaultView="TRUE" . . .>
        <Toolbar Type="Standard" />
        <!--<XslLink Default="TRUE">main.xsl</XslLink>-->
        <!-- CAML で記述した場合 -->
        <ViewHeader>
          <HTML>
            <![CDATA[<table>]]>
          </HTML>
        </ViewHeader>
        <ViewBody>
          <HTML><![CDATA[<tr>]]></HTML>
          <Fields>
            <HTML><![CDATA[<td>]]></HTML>
            <Field />
            <HTML><![CDATA[</td>]]></HTML>
          </Fields>
          <HTML><![CDATA[</tr>]]></HTML>
        </ViewBody>
        <ViewFooter>
          <HTML><![CDATA[</table>]]></HTML>
        </ViewFooter>
        <RowLimit Paged="TRUE">30</RowLimit>
        <ViewFields>
          <FieldRef Name="Attachments"></FieldRef>
          <FieldRef Name="LinkTitle"></FieldRef>
          <FieldRef Name="Cost" />
          <FieldRef Name="PaymentType" />
        </ViewFields>
        . . .
    . . .
   

SharePoint 2010 では、この CAML による方法以外に、上述した XsltListViewWebPart (XSLT リスト ビュー Web パーツ、省略して XLV) を使って、XSLT によるレンダリングのカスタマイズが可能です。以下のいずれかの方法でカスタマイズできます。

  • .xsl ファイルを配置して、schema.xml でこの .xsl ファイルを指定する
  • schema.xml にそのまま XSL を記述する

以下に、後者の方法を使って、簡単なサンプルをご紹介しましょう。

まず、XSL を作成する前に、このリストビューに対して SharePoint から送られてくる XML データのフォーマットを理解しておきましょう。SharePoint では、以下のような XML データがリストに送られてきます。(以下は、「10 行でズバリ!! SharePoint のリスト定義の作成」 で作成したカスタムリストで、サンプルデータを 2 件登録した場合の例です)

<dsQueryResponse ViewStyleID="" BaseViewID="1" TemplateType="10000" RowLimit="30">
  <Rows>
    <Row ID="1"
      PermMask="0x7fffffffffffffff"
      Attachments="0"
      Title="test1"
      FileLeafRef="1_.000"
      FileLeafRef.Name="1_"
      FileLeafRef.Suffix="000"
      FSObjType="0"
      Created_x0020_Date="1;#2010-09-15 13:55:20"
      Created_x0020_Date.ifnew="1"
      FileRef="/sites/test1/Lists/ListDefinitionProject1-ListInstance1/1_.000"
      FileRef.urlencode="%2Fsites%2Ftest1%2FLists%2FListDefinitionProject1%2DListInstance1%2F1%5F%2E000"
      FileRef.urlencodeasurl="/sites/test1/Lists/ListDefinitionProject1-ListInstance1/1_.000"
      File_x0020_Type=""
      HTML_x0020_File_x0020_Type.File_x0020_Type.mapall="icgen.gif||"
      HTML_x0020_File_x0020_Type.File_x0020_Type.mapcon=""
      HTML_x0020_File_x0020_Type.File_x0020_Type.mapico="icgen.gif"
      ContentTypeId="0x00E1C93FE46F781442B28047671F2ADC8C"
      Cost="100"
      Cost.="100.000000000000"
      PaymentType="出張費" />
    <Row ID="2"
      PermMask="0x7fffffffffffffff"
      Attachments="0"
      Title="test2"
      FileLeafRef="2_.000"
      FileLeafRef.Name="2_"
      FileLeafRef.Suffix="000"
      FSObjType="0"
      Created_x0020_Date="1;#2010-09-15 13:56:06"
      Created_x0020_Date.ifnew="1"
      FileRef="/sites/test1/Lists/ListDefinitionProject1-ListInstance1/2_.000"
      FileRef.urlencode="%2Fsites%2Ftest1%2FLists%2FListDefinitionProject1%2DListInstance1%2F2%5F%2E000"
      FileRef.urlencodeasurl="/sites/test1/Lists/ListDefinitionProject1-ListInstance1/2_.000"
      File_x0020_Type=""
      HTML_x0020_File_x0020_Type.File_x0020_Type.mapall="icgen.gif||"
      HTML_x0020_File_x0020_Type.File_x0020_Type.mapcon=""
      HTML_x0020_File_x0020_Type.File_x0020_Type.mapico="icgen.gif"
      ContentTypeId="0x00E1C93FE46F781442B28047671F2ADC8C"
      Cost="200"
      Cost.="200.000000000000"
      PaymentType="雑費" />
  </Rows>
</dsQueryResponse>

この構造を理解しておけば、あとは、この XML を変換する XSL を記述すれば OK です。
ただし、リストに関するメタ情報など (例えば、そのビューで表示するフィールド、データ行の個数、など)、上記の元データ以外の情報については、下記の通り XmlDefinition などの param で受け取ることができるので、これを使用します。

例えば、下記では、そのビューで定義されている ViewFields (そのビューで表示するフィールドの情報。下記を参照) を取得し、リストアイテムの ID, Title と、Attachment 以外の View Field を table タグを使って表示します。

<?xml version="1.0" encoding="utf-8"?>
<List xmlns:ows="Microsoft SharePoint" Title="カスタム支払リスト" Name="CustomListDefinition" FolderCreation="FALSE" Direction="$Resources:Direction;" Url="Lists/ListDefinitionProject1-ListDefinition1" BaseType="0" xmlns="http://schemas.microsoft.com/sharepoint/">
  <MetaData>
    <Fields>
      <Field Type="Number"
             List="CustomListDefinition"
             DisplayName="費用"
             Name="Cost"
             ShowInNewForm="TRUE"
             ShowInEditForm="TRUE" />
      <Field Type="Choice"
             List="CustomListDefinition"
             DisplayName="支出種別"
             Name="PaymentType"
             ShowInNewForm="TRUE"
             ShowInEditForm="TRUE">
        <CHOICES>
          <CHOICE>出張費</CHOICE>
          <CHOICE>雑費</CHOICE>
        </CHOICES>
      </Field>
    </Fields>
    <Views>
      <View BaseViewID="0" . . .>
        . . . . .
      </View>
      <View BaseViewID="1" DefaultView="TRUE"
            SetupPath="pages\viewpage.aspx"
            Url="AllItems.aspx" . . .>
        <Toolbar Type="Standard" />
        <!-- xsl ファイルを使用する場合は下記 -->
        <!--<XslLink Default="TRUE">MyCustom.xsl</XslLink>-->
        <!-- XSL を内部に記述する場合は下記 -->
        <Xsl>
          <![CDATA[
          <xsl:stylesheet xmlns:x="http://www.w3.org/2001/XMLSchema"
            version="1.0"
            exclude-result-prefixes="xsl msxsl ddwrt"
            xmlns:d="http://schemas.microsoft.com/sharepoint/dsp"
            xmlns:ddwrt="http://schemas.microsoft.com/WebParts/v2/DataView/runtime"
            xmlns:asp="http://schemas.microsoft.com/ASPNET/20"
            xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
            xmlns:msxsl="urn:schemas-microsoft-com:xslt"
            xmlns:SharePoint="Microsoft.SharePoint.WebControls">
            <xsl:output method="html" indent="no"/>
            <xsl:decimal-format NaN=""/>
            <xsl:param name="dvt_firstrow" select="1"/>
            <xsl:variable name="FirstRow" select="$dvt_firstrow" />
            <xsl:param name="dvt_RowCount" select="0" />
            <xsl:variable name="LastRow" select="$FirstRow + $dvt_RowCount - 1" />
            <xsl:param name="AllRows" select="/dsQueryResponse/Rows/Row[position() &gt;= $FirstRow and position() &lt;= $LastRow]"/>
            <xsl:param name="XmlDefinition" select="."/>
            <xsl:variable name="Fields" select="$XmlDefinition/ViewFields/FieldRef[not(@Explicit='TRUE')]"/>
            <xsl:template match="/">
              <table border="3" width="100%">
              <tr>
                <th>ID</th>
                <th>タイトル</th>
                <xsl:for-each select="$Fields">
                  <xsl:if test="not(@Name='Attachments' or @Name='LinkTitle')">
                  <th>
                  <xsl:value-of select="@DisplayName"/>
                  </th>
                  </xsl:if>
                </xsl:for-each>
              </tr>
              <xsl:for-each select="$AllRows">
                <xsl:variable name="thisNode" select="."/>
                <tr>
                  <td><xsl:value-of select="$thisNode/@ID"/></td>
                  <td><xsl:value-of select="$thisNode/@Title"/></td>
                  <xsl:for-each select="$Fields">
                    <xsl:if test="not(@Name='Attachments' or @Name='LinkTitle')">
                    <td>
                    <xsl:value-of select="$thisNode/@*[name()=current()/@Name]"/>
                    </td>
                    </xsl:if>
                  </xsl:for-each>
                </tr>
              </xsl:for-each>
              </table>
            </xsl:template>
          </xsl:stylesheet>
          ]]>
        </Xsl>
        <RowLimit Paged="TRUE">30</RowLimit>
        <ViewFields>
          <FieldRef Name="Attachments"></FieldRef>
          <FieldRef Name="LinkTitle"></FieldRef>
          <FieldRef Name="Cost" />
          <FieldRef Name="PaymentType" />
        </ViewFields>
        <Query>
          <OrderBy>
            <FieldRef Name="ID"></FieldRef>
          </OrderBy>
        </Query>
        <ParameterBindings>
          <ParameterBinding Name="NoAnnouncements" Location="Resource(wss,noXinviewofY_LIST)" />
          <ParameterBinding Name="NoAnnouncementsHowTo" Location="Resource(wss,noXinviewofY_DEFAULT)" />
        </ParameterBindings>
      </View>
    </Views>

    . . . . .

</List>

実行結果は、下図の通りになります。

補足 : 複数のリスト定義を作成する際の注意 (重要) :
特に、上記のように <XSL> タグを使用した場合、複数のリスト定義を 同一のフィーチャー (Feature) 内に作成しないようにしてください。リスト インスタンスでは、通常、FeatureId 属性に参照先のリスト定義のフィーチャーを指定しますが (この属性を省略することもできます)、同じ Feature 内に複数のリスト定義が存在すると、複数のリスト インスタンスが、schema.xml 内の同一の XSL View (コンパイルされて、さきに Cache されたほうの View) を表示してしまうことがあります。

補足 : 上記は単純なビューのサンプルですが、SharePoint の既定のビューのように高度なビューが作成できます。
例えば、リスト アイテムの表示 (または編集) で使用する listform.aspx (ダイアログ フォーム) のリンクを表示するには、以下の通り記述します。(表示されるポップアップには、このフォームにあわせたリボンのコマンドも、ちゃんと表示されます。)

. . .
<xsl:param name="FORM_DISPLAY"/>
. . .
<a href="{$FORM_DISPLAY}&amp;ID={$thisNode/@ID}&amp;ContentTypeID={$thisNode/@ContentTypeId}"
  onclick="OpenPopUpPage('{$FORM_DISPLAY}&amp;ID={$thisNode/@ID}&amp;ContentTypeID={$thisNode/@ContentTypeId}', RefreshPage);return false;"
  target="_self">
<xsl:value-of select="$thisNode/@Title"/>
</a>

また、サイトの URL を取得したい場合も、以下の通り ServerRelativeUrl (または RootSiteUrl) の parameter で取得できます。
.
<xsl:param name="ServerRelativeUrl"/>

使用可能なパラメータについては、SharePoint 2010 が既定で持っている main.xsl (および、そこから参照されている fldtypes.xsl、vwstyles.xsl など) が参考になります。

この XSL によるカスタマイズの優れた点は、XSLT という標準的な方法を使って柔軟に表示をカスタマイズできる点と、上記のように schema.xml に直接記述することでサンドボックス ソリューションでも扱えるという点です。(ただし、こちら にも記載したように、schema.xml の内容がキャッシュされることがあるので、開発時は注意してください。)
また、上記の XSL の通り、ASP.NET や Microsoft.SharePoint.WebControls などの XML 名前空間も使用できるため、上記では使用していませんが、用意されているさまざまな ASP.NET のコントロールとの組み合わせも可能です。
XSLT に関する知識武装は必要になりますが、あとは自由自在に表示をカスタマイズできます。

なお、先日 (2010年8月) 更新された新しい SharePoint SDK には、このリスト ビューのカスタマイズに関する豊富なリファレンスやサンプルが含まれていますので、是非参考にしてください。

[MSDN] What's New in the SDK for SharePoint 2010 :
http://msdn.microsoft.com/en-us/library/ff847474.aspx
http://msdn.microsoft.com/en-us/library/ff847475.aspx

 

  • XslLink 要素の値に、モジュールとして配置したXSLファイルを指定しても動作するのでしょうか?

    また、XslLink と Xsl 要素の両方を記述した場合は、どちらかが優先されるのでしょうか?もしくは、両方が適用されるのでしょうか?

  • お世話になっています。

    XslLink では、ハイブ (SharePoint Root) の Template\Layouts\Xsl フォルダからの相対パスになっていますので、ご指摘の Mapped File ではなく「モジュール」として配置して参照する方法は 事実上 むずかしいかもしれません。唯一、絶対パスで書いた場合はどうか、という点は確認してみるともしかしたら可能かもしれません。この方法で、トークンなどを使って書けるようであれば現実的ですが、絶対パスをそのまま書かなければならないとなると、仮に可能であったとしても、現実的な答えにならないと思いますので、ちょっと確認してみます。

    XslLink と Xsl の双方が指定されている場合の動作は Undocumented (仕様上不定) だと思いますので、動かして試してみるしかないかと思いますので、 こちら、時間ができたらこちらでも確認してみますね (こちらに、結果をアップします)。
    なお、Undocumented な実装はバージョンアップなどで変わる可能性もあるので、正直、あまりおすすめはできないです。

  • こちら、内容を確認してみましたが、結論として、「モジュール」で配置して XslLink で参照する方法は不可能でした。

    ルートからの絶対パス (/sites/officedemo/_layouts/xsl/main.xsl など) による参照は不可能で(このため、仮に {SiteUrl} などのトークンが使えたとしても参照できません)、また、相対パスは1階層上まで(../layouts/test.xsl など、ハイブの Template\Layouts 下)は可能ですが、そこから先は参照できませんでした。

    なお、XslLink と Xsl が双方指定されている場合、Xsl が優先されて参照されます。

  • ありがとうございます。

    > なお、XslLink と Xsl が双方指定されている場合、Xsl が優先されて参照されます。

    では、main.xsl の定義を利用しつつ、独自の定義を行う方法として、

    Xsl 要素内において、<xsl:import href="main.xsl" /> は有効となりますでしょうか。

  • お世話になっております。

    すばらしいです。ご指摘の方法だと、ちゃんと「モジュール」として配置した .xsl を参照できました。

    例えば、「サイトのリソースファイル」(SiteAssets) のドキュメントライブラリに test.xsl を保存し、以下の通り記述すると、ちゃんと test.xsl を参照します。(下記の通り、import では、サイトコレクションのトップからの相対パスを指定します。)

    <Xsl>
     <![CDATA[
     <xsl:stylesheet xmlns:x=www.w3.org/.../XMLSchema
       version="1.0"
       exclude-result-prefixes="xsl msxsl ddwrt"
       xmlns:d="schemas.microsoft.com/.../dsp"
       xmlns:ddwrt="schemas.microsoft.com/.../runtime"
       xmlns:asp="schemas.microsoft.com/.../20"
       xmlns:xsl=www.w3.org/.../Transform
       xmlns:msxsl="urn:schemas-microsoft-com:xslt"
       xmlns:SharePoint="Microsoft.SharePoint.WebControls">
       <xsl:import href="/SiteAssets/test.xsl"/>
     </xsl:stylesheet>
     ]]>
    </Xsl>

    このため、サンドボックス ソリューションで、下記の方法と組み合わせてモジュールとして配置した .xsl ファイルを参照可能です。

    blogs.msdn.com/.../sharepoint-2010-module-file-sandboxed-solution-silverlight-project.aspx

    また、Mapped Folder (SharePoint Root の下) に配置されている main.xsl や独自に配置した .xsl (ファーム ソリューションで配置した カスタムの .xsl) なども参照できます。

    ただ、SharePoint が既定で用意している main.xsl は、この中で、さらにリストの表示を制御するための .xsl をインポートしていますので、必要な .xsl のみを再利用してご使用ください。

    この方法でモジュールが参照できるというのは、私自身発見でした。ありがとうございます。

  • ありがとうございます。

    私もモジュールとして配置した .xsl までは想定しておりませんでした。

Page 1 of 1 (6 items)
Leave a Comment
  • Please add 6 and 5 and type the answer here:
  • Post