PowerShell:HTMLビューのレンダリング

エントリー


少し前まで、PowerShellスクリプトからさまざまなHTMLレポートをレンダリングして、さらに電子メールで送信する作業を行いました。 既製のソリューションの検索では、多くは得られませんでした。 誰かが独自の複雑な自転車エンジンであるRazorを接続します。

要件の控えめなリストは次のとおりです。

  1. ビューコードは別のファイルにある必要があります。
  2. ビュー内では、PowerShellでのネストとコード挿入のサポートが必要です。
  3. 追加設定なしでPowerShell 2.0を使用するホストで動作するはずです。


そのようなものは何も見つからなかったため、単純な(同時に強力な)レンダリングエンジンが従来のAspのスタイルで実装されました。









実装の詳細


(PowerShell自体と同様に)問題を調べてみると、文字列内のPowerShell式を計算する構文に気付きました。 たとえば、式" $($env:COMPUTERNAME)"



は実行時に解釈され、出力ではMYCOMPUTER



ようなものが得られます。



実際、これは最も単純な形式でテンプレート化されています。 これにより、非常に複雑なビューをレンダリングできます。



 $Model = @{} $Model.Title = 'Hello, this is a test' $Model.Clients = @('Ivan', 'Sergiy', 'John') $html = "<h1> $($Model.Title) </h1> <div class=""test""> <ul> $( foreach($client in $Model.Clients) {" <li> $( $client ) </li> "}) </ul> </div>" $html
      
      







ご覧のとおり、PowerShellパーサーを使用すると、文字列に$()で囲まれたコードのネストされた挿入を使用できます。これは、分岐とループの実装に非常に便利です。



この方法は、小さなタスクには既に使用できますが、欠点もあります。

  1. ビューコードは、個別のファイルではなく、スクリプトコードに含まれています。
  2. ネストされたビューを使用する方法はありません。
  3. 構文は少しあいまいで、多くの場合、括弧や引用符が欠落しているため、すべてを厳しくチェックする必要があります。
  4. テキスト挿入では二重引用符"



    as ""



    をエンコードする必要があります。




最初の2つの欠点は非常に簡単に解決されます。テンプレートはViewsサブフォルダーの別のファイルに移動され、モデルをレンダリングするための関数が記述されます。



 function RenderViewNativePowerShell( [Parameter(Mandatory=$true)][string] $viewName, [Parameter(Mandatory=$true)][Object] $model ) { $viewFileName = Resolve-Path ('Views\' + $viewName) $templateContent = Get-Content $viewFileName | Out-String return $ExecutionContext.InvokeCommand.ExpandString('"' + $templateContent + '"') }
      
      







その後、次のように呼び出すことができます。



 RenderViewNativePowerShell 'Test_ps.html' $Model
      
      







ネストされたビューがサポートされています。 test_ps.htmlは次のようになります。

 $( RenderViewNativePowerShell 'header_ps.html' $Model ) <div class=""test""> <ul> $( foreach($client in $Model.Clients) {" <li> $( $client ) </li> "}) </ul> </div>
      
      







これで十分なように思えるかもしれませんが、残りの欠点を克服することにしました-ASPブラケット<%...%>の使用に切り替えます。この構文は多くのテキストエディターでサポートされており、ページレイアウトがはるかに読みやすいためです。

したがって、実装の主なアイデアは非常に単純です。すべての角かっこ<%...%>を取得し、PowerShellの同等の$(...)に置き換えます。 いくつかの困難は、ネストされたビューが「...」ブロック内にある必要があるため、ネストされたビューを考慮するために置換があいまいでなければならないことでした。



いくつかの苦痛の後、そのような機能が生じました:



 function RenderView( [Parameter(Mandatory=$true)][string] $viewName, [Parameter(Mandatory=$true)][Object] $model ) { $viewFileName = Resolve-Path ("Views\" + $viewName) $templateContent = Get-Content $viewFileName | Out-String $rx = New-Object System.Text.RegularExpressions.Regex('(<%.*?%>)', [System.Text.RegularExpressions.RegexOptions]::Singleline) $res = @() $splitted = $rx.split($templateContent); foreach($part in $splitted) { if ($part.StartsWith('<%') -and $part.EndsWith('%>')) #transform <%...%> blocks { $expr = $part.Substring(2, $part.Length-4) #remove <%%> quotes $normExpr = $expr.Replace('`n','').Replace('`r','').Trim(); $startClosure = '$(' $endClosure = ')' if ($normExpr.endswith('{')) { $endClosure = '"' } if ($normExpr.startsWith('}')) { $startClosure = '"' } $res += @($startClosure + $expr + $endClosure) } else #encode text blocks { $expr = $part.Replace('"', '""'); $res += @($expr) } } $viewExpr = $res -join '' return $ExecutionContext.InvokeCommand.ExpandString('"' + $viewExpr + '"') }
      
      







PowerShellでの<%%>の必須置換に加えて、テキストブロック内の「by」の置換も実行されます。

その結果、Visual Studioでのビューは非常によく見えます。







結論として、いくつかのテストとサンプルを含むソースコードがGitHubで利用できることに注意してください。



All Articles