ページ変換モデルの内容と構成

ページ変換ソリューションの中心は、変換をフィードするモデルです。モデルは、どの Web パーツプロパティが重要であるかをエンジンに伝え、これらのプロパティを操作し、Web パーツのマッピングを動的に選択できるようにします。 ページ変換モデルは XML で表現され、モデルの正確性を検証するために使用されるスキーマが付属しています。

重要

SharePoint PnP モダン化は、PnP フレームワークの一部であり、継続的に進化しています。リリース ノートで常に最新の変更内容を確認してください。 問題が発生した場合は、「PnP フレームワークに関する GitHub の問題リスト」で問題を提出してください。

ページ変換アーキテクチャの概要

下の図で、ページ変換を 4 つの手順に分けて説明します。

  1. まず、ページ変換モデルを提供することにより、希望するページ変換方法を変換エンジンに指定する必要があります。 このモデルは、それぞれのクラシック Web パーツを同等のモダン Web パーツにマップする方法について説明する XML です。 このモデルには、クラシック Web パーツごとの、関連するプロパティとマッピング情報のリストが格納されています。 詳細については、「ページ変換モデルの内容と構成」をご覧ください。 クラシック Web パーツとモダン Web パーツを比較する方法を理解するには、「クラシックとモダンの Web パーツ エクスペリエンス」の記事を確認することをお勧めします。
  2. 次に、変換するページを分析します。変換エンジンは、Web パーツのコレクションに含まれるページを分割し (Wiki テキストは 1 つ以上の Wiki テキスト Web パーツに分割されます)、使用されているレイアウトを検出しようとします。
  3. 手順 2 の分析で取得した情報では、Web パーツを同等のモダン Web パーツにマップするのに不十分な場合があります。このため、手順 3 では、関数を呼び出すことにより必要な情報を補足します。これらの関数は、手順 2 で取得したプロパティを受け取り、手順 2 で入力されたプロパティに基づいて新しいプロパティを生成します。 手順 3 の後に、Web パーツをマップするために必要なすべての情報が用意されています。..ただし、必要に応じて定義されたセレクターを呼び出して、1 つのクラシック Web パーツを複数の最新の構成にマップできる場合に必要なマッピングを理解する必要があります。
  4. 最後の手順では、モダン ページを作成して構成し、マップされた最新の Web パーツを追加します。

ページ変換

ページ変換モデルの構造

ページ変換モデルを開くと、最上位に次の要素が存在します。

  • BaseWebPart: この要素には、すべての Web パーツに適用される構成が格納されています。たとえば、すべての Web パーツの Title プロパティが取得されることが記述されています。 また、既定の Web パーツ マッピングを定義する場所でもあります。Web パーツにマッピングが定義されていない場合、エンジンはこのマッピングにフォールバックして、ターゲット ページ上の Web パーツを表します。

  • アドオン: ページ変換のユーザーとして、カスタム ロジックを適用してニーズを実現する必要がある場合があります。たとえば、カスタム SPFX Web パーツで動作するように特定のプロパティを変換する必要があります。 このフレームワークは、関数やセレクターを備えた独自のアセンブリをユーザーが追加できるようにすることで、これをサポートします。AddOn セクションでそれらのアセンブリを定義し、指定された名前をそれらの前に付けてカスタム関数やセレクターを後から参照するだけで、ページ変換に独自のカスタム コードを使用できるようになります。

  • WebParts: この要素には、変換する各 Web パーツの情報が格納されています。 各 Web パーツについて、使用するプロパティの定義、それらのプロパティで実行する関数、変換対象を定義するのに使用できるマッピング、必要なマッピングを動的に選択するためのセレクターが記述されています。

詳細については後の章で説明します。

ページ変換モデルでの WebPart の定義

ページ変換モデルで Web パーツがどのように構成されるかを、最もわかりやすい XsltListViewWebPart 定義の簡単なサンプルを基に分析してみましょう。

      <!-- XsltListView web part -->
      <WebPart Type="Microsoft.SharePoint.WebPartPages.XsltListViewWebPart, Microsoft.SharePoint, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c">
        <Properties>
          <Property Name="XmlDefinitionLink" Type="string" />
          <Property Name="ListUrl" Type="string" />
          <Property Name="ListId" Type="guid" Functions="{ListWebRelativeUrl} = ListAddWebRelativeUrl({ListId}); {ListServerRelativeUrl} = ListAddServerRelativeUrl({ListId})"/>
          <Property Name="Direction" Type="string"/>
          <Property Name="GhostedXslLink" Type="string" />
          <Property Name="DisableViewSelectorMenu" Type="bool"/>
          <Property Name="XmlDefinition" Type="string" Functions="{ListViewId} = ListDetectUsedView({ListId},{XmlDefinition})"/>
          <Property Name="SelectParameters" Type="string"/>
        </Properties>
        <!-- This selector outputs: Library, List  -->
        <Mappings Selector="ListSelectorListLibrary({ListId})">
          <Mapping Name="List" Default="true">
            <ClientSideText Text="You can map a source web part ({Title}) to a combination of modern web parts :-)" Order="10" />
            <ClientSideWebPart Type="List" Order="20" JsonControlData="&#123;&quot;serverProcessedContent&quot;&#58;&#123;&quot;htmlStrings&quot;&#58;&#123;&#125;,&quot;searchablePlainTexts&quot;&#58;&#123;&#125;,&quot;imageSources&quot;&#58;&#123;&#125;,&quot;links&quot;&#58;&#123;&#125;&#125;,&quot;dataVersion&quot;&#58;&quot;1.0&quot;,&quot;properties&quot;&#58;&#123;&quot;isDocumentLibrary&quot;&#58;false,&quot;selectedListId&quot;&#58;&quot;{ListId}&quot;,&quot;listTitle&quot;&#58;&quot;{Title}&quot;,&quot;selectedListUrl&quot;&#58;&quot;{ListServerRelativeUrl}&quot;,&quot;webRelativeListUrl&quot;&#58;&quot;{ListWebRelativeUrl}&quot;,&quot;webpartHeightKey&quot;&#58;4,&quot;selectedViewId&quot;&#58;&quot;{ListViewId}&quot;&#125;&#125;" />
          </Mapping>
          <Mapping Name="Library" Default="false">
            <ClientSideWebPart Type="List" Order="10" JsonControlData="&#123;&quot;serverProcessedContent&quot;&#58;&#123;&quot;htmlStrings&quot;&#58;&#123;&#125;,&quot;searchablePlainTexts&quot;&#58;&#123;&#125;,&quot;imageSources&quot;&#58;&#123;&#125;,&quot;links&quot;&#58;&#123;&#125;&#125;,&quot;dataVersion&quot;&#58;&quot;1.0&quot;,&quot;properties&quot;&#58;&#123;&quot;isDocumentLibrary&quot;&#58;true,&quot;selectedListId&quot;&#58;&quot;{ListId}&quot;,&quot;listTitle&quot;&#58;&quot;{Title}&quot;,&quot;selectedListUrl&quot;&#58;&quot;{ListServerRelativeUrl}&quot;,&quot;webRelativeListUrl&quot;&#58;&quot;{ListWebRelativeUrl}&quot;,&quot;webpartHeightKey&quot;&#58;4,&quot;selectedViewId&quot;&#58;&quot;{ListViewId}&quot;&#125;&#125;" />
          </Mapping>
        </Mappings>
      </WebPart>

Properties 要素

各 Web パーツについて、モデルは、ターゲットのモダン Web パーツを構成するのに役立つ可能性のあるプロパティを定義します。 特定のプロパティがない場合、このモデルでプロパティを拡張できます。 一部のプロパティでは、Functions 属性が表示されます。この属性には、1 つ以上の関数 (;)を介して個別の関数) が含まれていますソース Web パーツがターゲットモダン Web パーツにマップされるときに実行されます。 関数の構造は次のとおりです。

{Output} = FunctionName({Input1}, {Input2})

関数には、次の 1 つ以上の入力値を指定できます。

  • この Web パーツで定義されているプロパティ (例: {ListId})
  • 元の Web パーツで定義されているプロパティ (例: {Title})
  • 前に関数を実行した際の出力のプロパティ (例: {ListWebRelativeUrl})
  • サイトを対象範囲とする既定のプロパティ: {Host}、{Web}、{Site}、{WebId}、{SiteId}

関数を実行すると、その出力は次のいずれかになります。

  • 単一の文字列値: この値 (サンプルのモデルでは {Output}) は Output という名前が指定されて Web パーツのプロパティのリストに追加され、FunctionName を実行して返された値が値として指定されます。
  • キーと値のペアのリスト (Dictionary<string,string>): この場合、返される各キーと値のペアが Web パーツのプロパティの一覧に追加されます

この関数で出力パラメーターが定義されていない場合、この関数を定義する Web パーツのプロパティ値は関数の結果で上書きされます。

サンプルで確認してみましょう。

<Property Name="ListId" Type="guid" Functions="FormatGuid({ListId})"/>

Web パーツのプロパティに、{AAFAD7D0-D57A-4BB1-8706-969A608C686B} のように書式設定された GUID が含まれているとします。 FormatGuid が実行されると、この値が FormatGuid の出力に設定されます (例: かっこの付かない AAFAD7D0-D57A-4BB1-8706-969A608C686B という GUID)。

関数が複数の値を返す場合は、既に Web パーツのプロパティとして存在する返されたキーと値のペアそれぞれが、そのプロパティの値を上書きします。

注:

すぐに使用できる関数すべてについては、「ページ変換関数とセレクター」で説明されています

Mappings 要素

この要素は、指定したソース Web パーツの 1 つ以上の対象の構成を定義します。 ユーザーは複数の対象を定義できるので、使用するマッピングを決定するためのメカニズムが必要になります。

  • 値が入力された Selector 属性がマッピング要素に含まれている場合、名前を使って正しいマッピングを見つけるために、そのセレクターを実行した出力が使用されます (たとえば、セレクター関数 ListSelectorListLibrary が Library という文字列を返す場合、Library という名前のマッピングが使用されます)。 セレクターは単一の値を返す関数と同じなので、セレクター関数への入力として任意の Web パーツ属性を指定できます。
  • マッピングが 1 つのみ存在する場合、セレクターの結果がなければそのマッピングが使用されます。
  • セレクターの結果がなく、複数のマッピングが定義されている場合は、Default とマークされているマッピングが使用されます。

注:

すぐに使用できるセレクターすべてについては、「ページ変換関数とセレクター」で説明されています

次に、Mapping 要素自体について説明します。

Mapping 要素

Mapping 要素内では、次のスニペットに示すように、1 つ以上の ClientSideText 要素または ClientSideWebPart 要素を使用できます。 マッピングで関数を実行できることに注意してください。これは、特定のマッピングが選択されている場合にのみ処理を実行する場合に便利です。

<Mapping Name="List" Default="true" Functions="{SampleVariable} = SampleFunction({ListId})>
  <ClientSideText Text="You can map a source web part ({Title}) to a combination of modern web parts :-)" Order="10" />
  <ClientSideWebPart Type="List" Order="20" JsonControlData="&#123;&quot;serverProcessedContent&quot;&#58;&#123;&quot;htmlStrings&quot;&#58;&#123;&#125;,&quot;searchablePlainTexts&quot;&#58;&#123;&#125;,&quot;imageSources&quot;&#58;&#123;&#125;,&quot;links&quot;&#58;&#123;&#125;&#125;,&quot;dataVersion&quot;&#58;&quot;1.0&quot;,&quot;properties&quot;&#58;&#123;&quot;isDocumentLibrary&quot;&#58;false,&quot;selectedListId&quot;&#58;&quot;{ListId}&quot;,&quot;listTitle&quot;&#58;&quot;{Title}&quot;,&quot;selectedListUrl&quot;&#58;&quot;{ListServerRelativeUrl}&quot;,&quot;webRelativeListUrl&quot;&#58;&quot;{ListWebRelativeUrl}&quot;,&quot;webpartHeightKey&quot;&#58;4,&quot;selectedViewId&quot;&#58;&quot;{ListViewId}&quot;&#125;&#125;" />
</Mapping>

上のサンプルでは、ソース XSLTListView Web パーツはモダン テキスト パーツ () とモダン Web パーツ (ClientSideTextClientSideWebPart) にマップされています。

  • 先頭を指定するには、Order 属性を使用します。
  • ClientSideWebPart に関しては、Web パーツの Type を指定する必要があります。種類として Custom を選択する場合、必要なカスタム Web パーツを指定するには、ControlId プロパティも指定する必要があります。
  • TextJsonControlData、および ControlId プロパティには、{Token} という形式のトークンを含めることができます。これらは、実行時に実際の値に置き換えられます。 定義されている各トークンは、前の部分で説明したとおり、Web パーツのプロパティまたは関数となることができる必要があります。

ページ変換モデルでの AddOns の定義

アドオンを使用すると、次の 2 つの手順で、カスタム ロジックをマッピング モデルに挿入できます。

  • カスタム関数またはセレクターをホストするカスタム アセンブリを作成します。
  • このカスタム アセンブリを AddOns 要素内で宣言します。

独自のカスタム関数またはセレクター アセンブリを作成します。

独自の関数を作成するには、次に示すように、プロジェクト内で SharePoint.Modernization.Framework アセンブリを参照してから、SharePointPnP.Modernization.Framework.Functions.FunctionsBase クラスを継承するクラスを作成する必要があります。

using Microsoft.SharePoint.Client;
using SharePointPnP.Modernization.Framework.Functions;
using System;

namespace Contoso.Modernization
{
    public class MyCustomFunctions: FunctionsBase
    {
        public MyCustomFunctions(ClientContext clientContext) : base(clientContext)
        {
        }

        public string MyListAddServerRelativeUrl(Guid listId)
        {
            if (listId == Guid.Empty)
            {
                return "";
            }
            else
            {
                var list = this.clientContext.Web.GetListById(listId);
                list.EnsureProperties(p => p.RootFolder.ServerRelativeUrl);
                return list.RootFolder.ServerRelativeUrl;
            }
        }

    }
}

カスタム アセンブリの宣言

ユーザー関数を使用するには、次に示すように、ライブラリまたはクラスごとに 1 つの参照を AddOns 要素に追加して、それらをモデルで宣言する必要があります。

<AddOn Name="Custom" Type="Contoso.Modernization.MyCustomFunctions" Assembly="Contoso.Modernization.dll" />

または、完全修飾パスを指定する必要があります。

<AddOn Name="Custom" Type="Contoso.Modernization.MyCustomFunctions" Assembly="c:\transform\Contoso.Modernization.dll" />

宣言ごとに名前が指定されている (上のサンプルでは Custom) ことにご注意ください。

独自のカスタム関数およびセレクターの使用

アセンブリの定義が完了すると、次の例の Custom というプレフィックスのような名前でそれらを参照することにより、独自のカスタム関数やセレクターを使用できます。

<Property Name="ListId" Type="guid" Functions="{ListServerRelativeUrl} = Custom.MyListAddServerRelativeUrl({ListId})"/>