XSL パラメーターから値を取得する

 

Kurt Cagle
2000 年 6 月 22 日

内容

XSLT パラメーターと変数 を理解する A ヴィンテージ 設定パラメーター の選択の概要

ASP ページを作成したことがある場合は、外部リソースからの情報の読み取りと、他の (一般的に変更された) 情報を他のリソースに保存するという 2 つのアクティビティに取り組んでいる可能性があります。これは、クライアントに送信される最終的な出力に対してのみ偶発的な重要性を持ちます。 その一部は、クエリ文字列要求からの情報の格納など、状態情報ですが、フォーム投稿からデータベースを更新したり、ファイルを格納したりする場合もあります。

以前の XSL (XSL と XML パターンに関する Microsoft の 1998 年 12 月の申請に基づくもの) を使い始めたとき、出力コードの生成を根本的に簡素化する必要がある力をすぐに実感しました。 XSLフィルター(スタイルシートを呼び出す際)は、データベース呼び出しをテーブルに変換し、ボイラープレートのHTMLコードを安全に組み込み、簡単な処理タスクを実行することもできます。

ただし、XSL には、深刻で頑丈な持ち上げに関するいくつかの制限がありました。 最大の問題はパラメーターでした。スタイルシートの基になるコードを深く知らなくても、XSL 構造を変更するクリーン方法はありませんでした。 多くの場合、XSLT 変換に情報を渡す唯一の方法は、XML 入力にパラメーターを配置することでした。 もう 1 つの問題は、プロセッサの現在の状態に関する情報を内部的に保持することでした。 出力ストリームに送信される XML マークアップがある場合は、一時的に保存して複数の場所で使用することはできませんでした。 最後に、XSL 環境内で状態を保存する実際の方法はありませんでした。XSL 変換の結果を取得し、ドキュメント オブジェクト モデル (DOM) 呼び出しでフィルター処理し、フィルター内で行われた中間状態を実質的に失う必要がありました。

テクノロジ プレビュー XML パーサーは、新しいXSL-Transformation仕様 (にあります http://www.w3.org/TR/xslt) のサポートを提供します。 この新しい仕様には、MICROSOFT の 1998 年 12 月バージョンの XSL よりもはるかに高い能力を持つ XSLT を実現する革新的な機能が多数含まれています。 また、この仕様により、XSLT はサーバー ツールとしてのスクリプト言語の競合企業として深刻になります。 これに加えて、Microsoft はスクリプト コード (W3C 標準に準拠しているコード) を統合する新しい方法も導入しました。これにより、サーバー側プログラミングに関する考え方が完全に変わる可能性があります。

XSLT パラメーターと変数について

理想的な世界では、XSLT フィルターは "ブラック ボックス" であり、1 つ以上の入力を受け取り、1 つ以上の出力を作成するフィルターです。 そのボックス内で何が起きっているのかを知る必要はありません。 関数では、情報をブラック ボックスに渡すことはパラメーターを使用して実行されます。 XSL ドキュメントでは、プロセスはパラメーター (具体的には <xsl:param> 要素) を使用して実行されます。 これらの XSLT 要素は、宣言型の世界 (データ ストリームが変換され、ストリームアウトされる世界) で同じ目的の一部を提供します。関数パラメーターは、手続き型の世界 (毎日のコードが最高の位置にある) で機能します。 ただし、この 2 つの値は同じではありません。

XSLT には変数も含まれます。 変数とパラメーターの主な違いは、パラメーターが現在のテンプレートの外部にあるソースからコンテンツを割り当て、変数が内部的に割り当てられるという点です。 これは、従来の関数に似ています。通常、関数の本体内で宣言される変数はプライベートであり、関数を呼び出すコードでは、そのような変数が存在することを認識したり、気にしたりしないでください。 その点で XSLT 変数も同様にプライベートです。

xsl:param 要素または xsl:variable 要素について考える最善の方法は、パラメーターを名前とコンテンツに関連付けると、その要素は不変です。書き込み一度読み取り多くの CD-ROM に書き込んだ場合もあります。 このスポットは基本的に取得され、同じ名前の別のパラメーターを作成しようとすると (少なくとも、同じスコープ内で、さらに後で)、パーサーはその場で試行を拒否します。 これは、ほとんどの手続き型言語のパラメーターとは大きく異なり、関数に対して内部的に簡単に変更できます。

さらに、xsl:param 要素と xsl:variable 要素には、実際には、値を割り当てる 2 つの異なる方法があります。 これらは、W3C 仕様の xsl:param オブジェクトの正式な説明で確認できます。

<xsl:param
   name = qname
   select = expression>
   <!-- Content: template -->
</xsl:param>

<xsl:variable
   name = qname
   select = expression>
   <!-- Content: template -->
</xsl:variable>

xsl:param 要素のコンテンツを設定する最も明白な方法は、内部コンテンツ (xsl:param タグと </xsl:param タグの間の<マテリアル) に要素を割り当てることです>。> 単純なケースとして、 パラメーターにテキストを割り当てることができます。 たとえば、ユーザーの姓をパラメーターに渡す場合は、内部コンテンツとして含めるだけです。

<xsl:param name="last_name">Cagle</xsl:param>

この方法でパラメーターを定義すると、後で XSLT でその名前の前にドル記号 ($) を付けて参照できます (これは、変数にも同様に関係します)。 たとえば、テンプレート内の <last_name> 要素に挿入するには、xsl:value-of 要素を使用します。

<last_name><xsl:value-of select="$last_name"/></last_name>

ただし、 パラメーターに XML タグを割り当てることもできます。 たとえば、人の完全なレコードを作成するとします。 これを行うには、param ステートメントを使用します。

<xsl:param name="person">
   <record>
       <first_name>Kurt</first_name>
       <last_name>Cagle</last_name>
       <vocation>Writer</vocation>
   </record>
</xsl:param>

この形式で構造を扱うことはもう少し複雑ですが、それほど複雑ではありません。 式 <xsl:value-of select="$person" を>使用しようとすると、出力ストリームに書き込むのは次のとおりです。

KurtCagleWriter

これはおそらくあなたが意図したものではありません。 <一方、xsl:copy-of select="$person> ステートメントを使用すると、XML 構造体全体を出力できます。

<record>
      <first_name>Kurt</first_name>
      <last_name>Cagle</last_name>
      <vocation>Writer</vocation>
</record>

ここでは、興味深いものが得られます。 パラメーター (およびその兄弟変数) について覚えておくべき重要な点は、後で解釈するために一致パターンを格納するのではなく、パラメーターまたは変数が検出されたときにパーサーによって自動的に解釈される点です。 パーサーが変数またはパラメーター内で XSL 式を検出した場合、その式はその時点で自動的に評価され、パラメーターの名前に関連付けられているスペースに書き込まれます。 この興味深い小さな事実は、パラメーターと変数 を非常に 便利にします。

たとえば、次のことを考慮してください。

<xsl:param name="first_name">Kurt</xsl:param>
<xsl:param name="last_name">Cagle</xsl:param>
<xsl:param name="vocation">Writer</xsl:param>
<xsl:param name="record">
   <first_name><xsl:value-of select="$first_name"/></first_name>
   <last_name><xsl:value-of select="$last_name"/></last_name>
   <vocation><xsl:value-of select="$vocation"/></vocation>
</xsl:param>

record パラメーターは、前の 3 つのパラメーターの値を評価して、パラメーターの設定に関係なく、レコードにパラメーターからの更新値が反映されるようにします。 XSL ドキュメントに単純なパラメーターを簡単に入力して、より複雑なオブジェクトを作成できるようになりました。

結果ツリーフラグメント

ただし、これには大きな制限があります。 W3C の XSLT 委員会内で、より熱く争われた議論の 1 つは、変数のコンテンツを処理する方法の問題を扱いました。 コンテンツは、要素のタグ (つまり、要素の "text") 内にある要素のその部分です。 XSLT 変数に対して select ステートメントを実行すると、select ステートメントによって変数にノード セットが割り当てられます。これは、ドキュメント内の他のノード セットであるかのように操作できます。

一方、W3Cは、ノード内のコンテンツが整形式であっても、コンテンツが正しく形成されていない危険性は、 コンテンツが結果ツリーフラグメントと呼ばれる独自のタイプであることを指定するのに十分であると判断しました。 このようなフラグメントは、XSLT では第 2 クラスの市民と見なされます。 一部の操作 (最上位ノードの名前の取得など) を実行できますが、ほとんどの XPath ナビゲーション演算子を適用することはできません。

したがって、上記のレコードの場合、式は次のようになります。

<xsl:value-of select="$record/first_name"/>

、既存の入力ストリームに作用する選択値からレコードを割り当てた場合でも、XSLT 仕様に従って無効です。

<xsl:variable name="record select="//record[1]"/>

その後、同じステートメントが完全に合法になります。

MSXML テクノロジ プレビュー パーサーの現在の動作では、この制限は認識されないことに注意してください。 変数要素の内容から作成されたフラグメントは、select ステートメントと同じ特権を持つと見なされます。 これは重要な機能です。これは、名前付きテンプレート操作の結果 (検索パターンを通じて照合されるのではなく、関数のように呼び出すことができるテンプレート) から要素にアクセスする方法を提供するため、重要な機能です。これについては、今後の列で説明します。 たとえば、テンプレートが並べ替えおよびフィルター処理された要素の場合、フィルター処理されていないセットではなく、並べ替えられた要素を反復処理できます。これは、"ページ" 出力を作成するための重要な機能です。

この点で W3C の動作に準拠するために、Microsoft は最終的な MSXML Web リリースでこの主要な機能の使用を非推奨にする可能性がありますが、次のように拡張機能を介して最終的な MSXML Web リリースで使用できるようになる可能性があります。

<xsl:value-of select="msxsl:node set($record)/first_name"/>

さらに、Microsoft は、コンテンツを完全な状態のノード セットとして扱う機能が XSLT で実行できる機能を大幅に拡張するため、この機能を XSLT 2.0 仕様に含めるようプッシュしています。

ヴィンテージの選択

select 属性は、パラメーターまたは変数を設定する 2 つ目の方法を提供します。 パラメーターを持つ select ステートメントは、select ステートメントが他の場所で動作するのとまったく同じように動作します。属性内の式を XPath 式として解釈できる場合、パーサーは指定された式を満たすすべてのノードを検索し、変数に配置しようとします。 たとえば、入力ストリームが多数のユーザーの名前と職業を示す多数のレコードで構成されたとします。 最初のストリームでライターであるすべてのユーザーを取得するために、変数を設定できます (ここではパラメーターは実際に必要ありません)。

<xsl:variable name="writers" select="//record[vocation='Writer']">

この変数を取得すると、基本的には、$writersをルートとして持つノード フラグメントが作成され、子としてライターでもある人だけが作成されます。 このセットを反復処理する場合は、$writersがルート ノードであることを覚えている限り、xsl:apply-templates> または <xsl:for-each> 要素を<使用してコンテキストを順番に設定できます。

<xsl:template match="/">
<ul>
<xsl:for-each select="$writers/*">
       <li><xsl:value-of select="first_name"/><xsl:text> </xsl:text></xsl:value-of select="last_name"/></li>
</xsl:for-each>
</ul>
</xsl:template>

これにより、最初のストリーム内のすべてのライターの HTML 箇条書きが作成されます。 この 1 つの効果は、コンテキスト (ドキュメント内の場所) がテンプレートの即時コンテキストに依存しなくなったことに注意してください。 ところで、式 <xsl:text></xsl:text> は空白文字を出力に配置します。 少し醜いですが、XSLT は生のテキストではなく、生成された XML 用に最適化されていることに注意することが重要です。

select ステートメントは変数またはパラメーター タグの内容を自動的にオーバーライドしますが、技術的には両方を使用する XSLT 違反と見なされます。 幸い、MSXML パーサーではエラーはスローされません。両方を使用すると便利な場合があるためです。

select ステートメントを使用して式を評価したり、テキストを含めたりすることもできますが、後者の場合は注意する必要があります。 XSLT パーサーは、select 属性内で見つかったテキストを XPath 式の一部として自動的に解釈します。ただし、そのテキストが特に二重引用符 (二重引用符の中に単一引用符で囲まれた場合、またはその逆) でない限り、XPath 式の一部として解釈されます。 したがって、次のように、職業フィールドを "writer" に設定できます。

<xsl:param name="vocation" select="'writer'"/>

式の評価はもう少し複雑ですが、それほど複雑ではありません。 select 属性は、要素の現在のコンテキストに基づいて、任意の XPath 式のウィンドウと考えるのに役立ちます。 XPath には、プライマリ DOM をナビゲートできるだけでなく、式の評価に使用できる関数が多数含まれており、これらの式には、XSLT の機能を大幅に拡張する算術演算、文字列演算、またはその他の操作を含めることができます。 たとえば、請求書内のアイテムの一覧を示す XML 構造があるとします。これには、特定のアイテムの数と、これらのアイテムのコスト (次に示すように) が含まれます。

<lineItems>
   <lineItem>
      <code>42AC5</code>
      <title>Loopy Fruit Cereal</title>
      <amount>12</amount>
      <cost>4.25</cost>
   </lineItem>
   <lineItem>
      <code>H343A</code>
      <title>MicroSecond Rice</title>
      <amount>14</amount>
      <cost>2.35</cost>
   </lineItem>
   <lineItem>
      <code>EA198</code>
      <title>Crescent Toothpaste</title>
      <amount>18</amount>
      <cost>1.95</cost>
   </lineItem>
</lineItems>

その後、XPath に組み込まれている組み込み関数の一部を使用して、行項目のセット全体の総コストを変数に割り当てることができます。

<xsl:variable name="lineItemSubTotals">
   <xsl:for-each select="//lineItem">
      <subTotal><xsl:value-of select="number(amount)*number(cost)"/></subTotal>
   </xsl:for-each>
</xsl:variable>
<xsl:variable name="lineItemsTotal">
   <xsl:value-of select="sum($lineItemSubTotals/subTotal)"/>
</xsl:variable>

この場合、 変数 $lineItemSubTotalsは、小計>要素で<構成される下位 XML 構造を作成し、それらを lineItemTotals 変数に割り当てます。 上記の例では、基本的に次と同じです。

<xsl:variable name="lineItemTotals">
   <subTotal>51</subTotal>
   <subTotal>32.9</subTotal>
   <subTotal>35.1</subTotal>
</xsl:variable>

2 番目の変数 $lineItemsTotalでは、 sum() XPath 関数を使用して項目の合計をまとめて追加し、結果の値 119 を lineItemsTotal 変数に割り当てます。 これは手続き型のアプローチとは異なります。アルゴリズムでは (これは非常に単純です)、 $lineItemsTotal、各行項目エントリの合計を含む変数はトランザクションで使用されないためです。 また、レコードの出力を変更して、明細を読み取り、追加されたフィールドを含む新しい明細を作成し、小計情報を保持して合計合計を取得することもできます。

<xsl:variable name="newLineItems">
   <xsl:for-each select="//lineItem"">
      <lineItem>
         <xsl:copy-of select="*"/>
         <subTotal><xsl:value-of select="number(amount)*number(cost)"/></subTotal>
      </lineItem>
   </xsl:for-each>
</xsl:variable>
<xsl:variable name="lineItemsTotal">
   <xsl:value-of select="sum($newLineItems/subTotal)"/>
</xsl:variable>

この一連のコードは、新しい一連の行項目を作成し、合計を実行します。これは、XSL フィルターが中間処理情報を組み込むために既存の XML ドキュメントを本質的に拡大 (または削減) する方法を示しています。

パラメーターの設定

パラメーターを使用するには、パラメーターを設定する必要があります。 ここで説明する XSLT は ASP 環境内で動作することを意図している場合は、ASP でもパラメーターを設定する必要があります。 これは、最初にサーバーに情報を送信する方法に応じてさまざまな方法がありますが、ほとんどの場合、XML DOM が含まれます。

ほとんどの場合、実際のパラメーターを設定するには、パラメーターの select プロパティを設定するか、そのプロパティにテキストを割り当てます。 たとえば、first_name、last_name、および vocation プロパティがクエリ文字列として送信されると仮定して、Visual Basic Scripting Edition (VBScript) で DOM 呼び出しを使用して addRecord.xsl フィルターの新しいレコードを作成するようにプロパティを設定できます。

<%
firstName=request.queryString("first_name")
lastName=request.queryString("last_name")
vocation=request.queryString("vocation")
set addRecordFilter=createObject("MSXML2.DOMDocument")
addRecordFilter.async=false
addRecordFilter.load server.mapPath("addRecord.xsl")
set
firstNameNode=addRecordFilter.selectSingleNode("//xsl:param[@name=
'first_name']")
firstNameNode.setAttribute "select","'"+firstName+"'"
set
lastNameNode=addRecordFilter.selectSingleNode("//xsl:param[@name=
'last_name']")
lastNameNode.setAttribute "select","'"+lastName+"'"
set
vocationNode=addRecordFilter.selectSingleNode("//xsl:param[@name=
'vocation']")
vocationNode.setAttribute "select","'"+vocation+"'"
set stubDoc=createObject("MSXML.DOMDocument")
stubDoc.loadXML "<stub/>"
response.write stubDoc.transformNode(addRecordFilter)
%>

たとえば、式 "//xsl:param[@name='first_name'] は、パラメーターに名前first_nameでアクセスし、select 属性の内容をクエリ文字列から取得した値に置き換え、単一引用符で囲んで XPath 式としてではなく文字列として評価されるようにします。

XML テクノロジ プレビュー パーサーの一部である XSLTemplate を使用して、プロセスを多少簡略化することもできます。 (テンプレートから派生した) プロセッサには、パラメーターとオブジェクトを更新するためのインターフェイスが多数用意されています。

<%
firstName=request.queryString("first_name")
lastName=request.queryString("last_name")
vocation=request.queryString("vocation")
set addRecordFilter=createObject("MSXML2.DOMDocument")
addRecordFilter.async=false
addRecordFilter.load
server.mapPath("addRecord.xsl")
set template=createObject("MSXML2.XSLTemplate")
set template.stylesheet=addRecordFilter
set processor=template.createProcessor
processor.AddParameter "first_name",firstName
processor.AddParameter "last_name",lastName
processor.AddParameter "covation",vocation
set stubDoc=createObject("MSXML.DOMDocument")
stubDoc.loadXML "<stub/>"
processor.input=stubDoc
processor.transform
processor.output=response
%>

XSLT ドキュメントは、実際には、変換する XML ドキュメントに関して何も気にしない点に注意してください。 ドキュメントの唯一の目的は、強制的に出力することです。 これは、XSLT の操作時にプライマリ入力ストリームを特に使用する必要がないようにするためです。 ここでも、これは、将来の列のトピックである変数よりも名前付きテンプレートの方が理にかなっています。 実際の作業は 、document() 関数と persistDocument() 関数を使用して行われます。この関数は、レコードの構造に読み込み、ノード (順序付け) をレコードに追加してから、それらの構造体を保存します。

ここでの目的は、アプリケーション固有のコードを可能な限り減らし、広範なコードの再作業を回避できるようにするためです。 これを行う 1 つの方法は、 queryString コレクションと Form コレクションの両方を列挙して使用可能なパラメーター値を取得し、そのようなパラメーターが存在する場合はパラメーターに値を割り当てることです。

これにより、興味深い可能性も生まれます。XSL フィルターの名前を、変数 "filter" に含まれているのと同じ方法で引数として渡すことができます。このようにして、同じ ASP ファイルで、任意の数の XSLT フィルターの処理をより汎用的に処理できます。

<%
' XSLServer.asp
function main()
   xslFilter=request("filter")
   if right(xslFilter,4,1)<>"." Then
      xslFilter=xslFilter+".xsl"
   end if
   set xslDoc=createObject("MSXML2.DOMDocument")
   xslDoc.async=false
   xslDoc.load server.mapPath(xslFilter+".xsl")
   for each key in request.form
            set paramNode=xslDoc.selectSingleNode("//xsl:param[name='"+key+"']")
            if not (paramNode is nothing) then
                  paramNode.setAttribute "select","'"+request(key)+"'"
            end if
      next
      for each key in request.queryString
            set paramNode=xslDoc.selectSingleNode("//xsl:param[name='"+key+"']")
            if not (paramNode is nothing) then
                  paramNode.setAttribute "select","'"+request(key)+"'"
            end if
      next
      set stubDoc=createObject("MSXML.DOMDocument")
      stubDoc.loadXML "<stub/>"
      response.write stubDoc.transformNode(xslDoc)
end main
 
main
%>

クエリ文字列またはフォーム パラメーターは、XSLT パラメーターが既に存在する場合にのみ XSLT パラメーターにマップされることに注意してください。 これにより、XSL ファイルの名前をフィルター コードに渡す方法も提供されます。 filter という名前のパラメーターを設定するだけです。 また、拡張子が指定されていない場合は、コードによって文字列 .xsl がフィルター名に追加されることに注意してください。 このタッチにより、フィルターはファイル名よりもコマンドのように見えます。

したがって、クエリ文字列は次のようになります。

http://www.myserver.com/xslserver.asp?filter=addrecord &first_name=Kurt&last_name=Cagle&vocation=Writer

は、その情報を addRecord.xsl フィルターに渡します。 これにより、使用するメソッドの名前を含むフィルターと、関連付けられたパラメーターを保持する他のすべてのクエリ文字列引数を含む、合理的に強力な URL ベースの API 規則の基礎が得られます。

また、XML ノード、XML ノード セット (選択インターフェイスを介して)、さらには DOM ドキュメント全体をパラメーターとして渡すこともできます。 この場合は、 要素を子として パラメーターに追加し、select ステートメントを削除するだけです。

<%
' XSLServer.asp
function main()
      set newUserDoc=createObject("MSXML2.DOMDocument")
      newUserDoc.load  "newUser.xml"
      set xslDoc=createObject("MSXML2.DOMDocument")
      xslDoc.async=false
      xslDoc.load server.mapPath("addRecord.xsl")
      set newRecordNode=xslDoc.selectSingleNode("//xsl:param[name='record']")
      newRecordNode.appendChild newUserDoc.documentElement
      newRecordNode.removeAttribute "select"
      set stubDoc=createObject("MSXML.DOMDocument")
      stubDoc.loadXML "<stub/>"
      response.write stubDoc.transformNode(xslDoc)
end main
 
main
%>

これは、XSL プロセッサを使用すると、 transformNode 関数を使用するのと同じくらい理にかなっているもう 1 つのケースです。 XSLT の原則的な問題は、変換を実行する必要があるたびにスタイル シートを解析することは非常にコストがかかるということです。特に、多くの場合、各ケースで使用されるのと同じ XSLT スクリプトを処理している場合です。 Processor オブジェクト (セッション変数に保存) でレンダリングされるのと同じ機能も、次のように書き込まれる場合があります。

<%
' XSLServer.asp
function main()

   if typename(session("addRecord"))="IXSLProcessor" then
      set addRecord=session("xslProc")
      set stubDoc=session("stubDoc")
   else
      set xslDoc=createObject("MSXML2.DOMDocument")
      xslDoc.async=false
      xslDoc.load server.mapPath("addRecord.xsl")
      set xslTemplate=createObject("MSXML2.XSLTemplate")
      set xslTemplate.stylesheet=xslDoc
      set addRecord=xslTemplate.createProcessor
      session("addRecord")=addRecord
      set stubDoc=createObject("MSXML.DOMDocument")
      stubDoc.async=false
      stubDoc.loadXML "<stub/>"
      session("stubDoc")=stubDoc
   end if
   set newUserDoc=createObject("MSXML2.DOMDocument")
      newUserDoc.load "newUser.xml"
   addRecord.addParameter "record",newUserDoc
   addRecord.input=stubDoc
   addRecord.output=response
   addRecord.transform
end main
 
main
%>

これは前の 2 つのサンプルとほぼ同じですが、個々の文字列ではなく、DOM ツリーを XSL スタイル シートに渡します。 これは、処理されたノードを XSLT フィルターに戻す場合に便利です。

XSLTemplate オブジェクトと XSLProcess オブジェクトの詳細については、「Inside MSXML3 Performance by Chris Lovett」を参照してください。

まとめ

変数とパラメーターは、中間情報を保持するメカニズムを提供し、渡されないプロパティの既定値を提供し、外部ドキュメントのルート ノードとして機能し、スタイル シートをより動的にする方法を公開することで、XSLT でできることを大幅に拡張できます。 また、特に他のコンポーネントを操作するための車両としてパラメーターを使用することもできます。特に、それらのコンポーネントへの参照を提供するか、デバイスの場所を計算する方法を許可することで、スクリプトと組み合わせて使用できます。 パラメーターは、XML 開発者のレパトアの重要な部分と見なす必要があります。

Kurt Cagle は、XML および関連するインターネット テクノロジを専門とするライターおよび開発者です。 彼は妻とワシントン州オリンピアの2人の娘と一緒に住んでおり、VB XMLの電子メールcagle@olywa.netまたは彼の共有Webサイトで連絡することができます。