August 2012
Volume 27 Number 08
Windows PowerShell - Windows PowerShell による使いやすい XML インターフェイスの構築
Joe Leibowitz | August 2012
Windows PowerShell スクリプト言語は、コマンド ライン ツールで行いたいあらゆること、あるいはそれ以上のことを実行できるため、最終的には VBScript などのテクノロジに置き換わると考えられます。Windows PowerShell の概要と基本的な使い方については、bit.ly/LE4SU6 および bit.ly/eBucBI (英語) を参照してください。
Windows PowerShell は、Microsoft .NET Framework と完全に統合されているため、XML と密接に結び付いています。XML は、現状では、構造化されたテキスト ファイルを使用したデータ交換の国際標準になっています。XML の概要については、bit.ly/JHfzw (英語) を参照してください。
今回は、Windows PowerShell の XML データの表示と操作の機能を説明しながら、XML ファイルの読み取りと編集に使用する比較的シンプルな UI の作成します。ここで使用する考え方は、スキーマに関する情報が事前になくても、任意のファイルの兄弟関係や親子関係を "把握" するアルゴリズムを使用して、XML ファイルの読み取りや編集を簡単かつ便利にするというものです。また、Windows PowerShell での Windows フォームの使い方や XPath クエリなどの関連テクノロジについても説明します。今回作成するアプリケーションでは、XML ファイルを読み取り、XPath クエリを単独で生成することができます。
では、Windows PowerShell で XML ファイルを分析する方法、および高度な技術スキルがなくても使用できる形式で XML ファイルを表示する方法について見ていきましょう。図 1 が、今回作成する GUI のプレビューです。
図 1 GUI の暫定的なビュー
このような GUI を実現するうえで重要なのは、人間によるガイダンスやスキーマに関する事前情報がなくても、Windows PowerShell アプリケーションで XML ファイルを解析して理解できるようにすることです。XML ファイルの自動分析を行う既存のテクノロジを調査した結果、人間によるガイダンスなしで XML ドキュメントを理解するというニーズをに完全に満たすテクノロジを見つけることができなかったため、今回の目的を果たすために解析エンジンを開発することにしました。最近のアプリケーションは全体的に、ある XML ドキュメントの要素、属性、およびスキーマ全体について、開発者やユーザーに十分な知識があることを前提としているように感じられます。ただし、現実の状況 (おそらく多くの状況) において、このパラダイムが当てはまらないことがあります。たとえば、多くのデータ コンシューマーは、XML のエキスパートではないにもかかわらず、さまざまな XML データ ソースにアクセスしなければならない場面があります。このような場合は、十分な知識があるという前提は成り立ちません。また、トレーニングをエキスパートが 1 ~ 2 人いたとしても、組織が構造の異なる何百、何千もの XML ファイルに対処することになれば、人間によるアプローチはすぐに役に立たなくなってしまいます。
そのため、最小限のトレーニングしか受けていない一般ユーザーでも、任意の XML ファイルの検索や編集に使用でき、XML ファイルを読み取り XPath を生成する解析エンジンが必要です。
XML 解析エンジン
XML の構造が成り立つには、ドキュメントの始めと終わりの要素が対応している必要があります。たとえば、要素 <ABC> が存在するならば、同じファイルのこの要素よりも後に要素 </ABC> が存在しなければなりません。この始めと終わりの要素の間で、ほぼすべての要素を理論的に発生させることができます。ここでは、この XML の基本原則を使用して、一連の包括的な XPath クエリを自動的に構築する方法を示します。この XPath クエリがあれば、比較的経験の少ない XML データ コンシューマーでも XML ファイル内のデータを見つけて操作することができます。
まず、XML ファイルの始めと終わりのすべての要素を保持する一連の配列を作成します。
[int[]]$leading_brackets = @()
[int[]]$closing_brackets = @()
[string[]]$leading_value = @()
[string[]]$closing_value = @()
Windows PowerShell で厳密に型指定され、サイズが不明の配列を構築するには、[<型>[]] で始まり、$<名前>、サイズが不明の配列を表す @() という 3 つの要素が必要です。Windows PowerShell の変数は、先頭に $ 文字を付けます。これらの配列には、XML ドキュメントの始めと終わりの要素の場所のインデックスと、これらの要素名を表す文字列値を格納します。たとえば、<PS1>text value</PS1> という XML 行では、始めの要素の整数インデックスは 0 で、終わりの要素のインデックスは 15 で、要素名を表す値は PS1 です。
対象となる XML をメモリに読み込むには、次のコードを使用します。
$xdoc = New-Object System.Xml.XmlDocument
$xdoc.Load("C:\temp\XMLSample.xml")
図 2 は、実際に使用する XML ファイルの一部を示したものです。
図 2 サンプル XML ファイルの一部
<?xml version="1.0" encoding="utf-8"?>
<Sciences>
<Chemistry>
<Organic ID="C1" origination="Ancient Greece" age="2800 yrs">
<branch ID="C1a">
<size>300</size>
<price>1000</price>
<degree>easy></degree>
<origin>Athens</origin>
// Text for organic chem here
</branch>
<branch name="early" ID="C1b" source="Egypt" number="14">
<size>100</size>
<price>3000</price>
<degree>hard></degree>
<origin>Alexandria</origin>
// Text for original Egyptian science
</branch>
</Organic>
</Chemistry>
<Physics></Physics>
<Biology ID="B" origination="17th century" >
.
.
.
<Trees4a name="trees4a" age="40000000">
<type ID="Tda1">oakda</type>
<type ID="Tda2">elmda</type>
<type ID="Tda3">oakd3a</type>
</Trees4a>
</Plants>
</Biology>
</Sciences>
読み込み操作が終われば、この XML データがメモリ内にコピーされます。XML を操作および分析するため、$xdoc 変数にインスタンスが作成されたドキュメント オブジェクト モデルを使用します (ただし、いくつか特殊な目的のため、XPathNavigator テクノロジも使用する必要があります。このことについては後半で説明します)。
# Create an XPath navigator (comments in PowerShell code take the \"#\" leading character)
$nav = $xdoc.CreateNavigator()
Windows PowerShell の最も興味深い機能の 1 つが、Get-Member という組み込み関数 (コマンドレット) です。これにより、Windows PowerShell の任意のオブジェクトのメソッドやプロパティを開発時に IDE から直接操作できます。図 3は、先ほど作成した $nav オブジェクトでこのコマンドレットを呼び出した結果を示しています。また、図 4 は、Get-Help コマンドレットを呼び出したとき、Windows PowerShell Integrated Scripting Environment (ISE) に表示される結果を示しています。
図 3 Get-Member 呼び出しの結果
Get-Member -InputObject $nav
TypeName: System.Xml.DocumentXPathNavigator
Name MemberType Definition
---- ---------- ----------
AppendChild Method System.Xml.XmlWriter AppendChild(), System.V...
AppendChildElement Method System.Void AppendChildElement(string prefix...
CheckValidity Method bool CheckValidity(System.Xml.Schema.XmlSche...
Clone Method System.Xml.XPath.XPathNavigator Clone()
ComparePosition Method System.Xml.XmlNodeOrder ComparePosition(Syst...
Compile Method System.Xml.XPath.XPathExpression Compile(str...
CreateAttribute Method System.Void CreateAttribute(string prefix, s...
CreateAttributes Method System.Xml.XmlWriter CreateAttributes()
CreateNavigator Method System.Xml.XPath.XPathNavigator CreateNaviga...
DeleteRange Method System.Void DeleteRange(System.Xml.XPath.XPa...
DeleteSelf Method System.Void DeleteSelf()
Equals Method bool Equals(System.Object obj)
Evaluate Method System.Object Evaluate(string xpath), System...
GetAttribute Method string GetAttribute(string localName, string...
GetHashCode Method int GetHashCode()
TypeName: System.Xml.DocumentXPathNavigator
.
.
.
.
.
Value Property System.String Value {get;}
ValueAsBoolean Property System.Boolean ValueAsBoolean {get;}
ValueAsDateTime Property System.DateTime ValueAsDateTime {get;}
ValueAsDouble Property System.Double ValueAsDouble {get;}
ValueAsInt Property System.Int32 ValueAsInt {get;}
ValueAsLong Property System.Int64 ValueAsLong {get;}
ValueType Property System.Type ValueType {get;}
XmlLang Property System.String XmlLang {get;}
XmlType Property System.Xml.Schema.XmlSchemaType XmlType {get;}
図 4 Windows PowerShell の Get-Help コマンドレットの結果
Get-Member コマンドレットは、通常、Windows PowerShell 開発を正しい方向に進めるために使いますが、関連する Get-Help コマンドレットも便利であることがわかります。
コマンド ラインで「get-help xml」と入力すると (図 4 参照)、次のように出力されます。
getName Category Synopsis
---- -------- --------
Export-Clixml Cmdlet Creates an XML-based representation of an object or...
Import-Clixml Cmdlet Imports a CLIXML file and creates corresponding obj...
ConvertTo-XML Cmdlet Creates an XML-based representation of an object.
Select-XML Cmdlet Finds text in an XML string or document.
about_format.ps1xml HelpFile The Format.ps1xml files in Windows PowerShell defin...
about_types.ps1xml HelpFile Explains how the Types.ps1xml files let you extend ...
「get-help about_types.ps1xml」と入力すると、図 5に示す結果が表示されます。
図 5 Types.ps1xml ファイルのヘルプ情報
TOPIC
about_Types.ps1xml
SHORT DESCRIPTION
Explains how the Types.ps1xml files let you extend the Microsoft .NET Framework types of the objects that are used in Windows PowerShell.
LONG DESCRIPTION
The Types.ps1xml file in the Windows PowerShell installation directory ($pshome) is an XML-based text file that lets you add properties and methods to the objects that are used in Windows PowerShell. Windows PowerShell has a built-in Types.ps1xml file that adds several elements to the .NET Framework types, but you can create additional Types.ps1xml files to further extend the types.
SEE ALSO
about_Signing
Copy-Item
Get-Member
Update-TypeData
構文を確認するための Windows PowerShell 統合システムは、包括的で、比較的使いやすいものです。この統合システムに関しては、別の記事にして説明する価値があります。
XML を分析可能な状態にするには、XpathNavigator の Select メソッドを使用します。
$nav.Select("/") | % { $ouxml = $_.OuterXml }
このステートメントの最初の部分では、単純な XPath クエリ "/" で .Select を呼び出し、XML コンテンツ全体を指定します。次の部分では、Windows PowerShell のオブジェクト パイプラインとして使用する | 記号の後に、エイリアス % で表される foreach 処理を行います (エイリアスではなく foreach を使用することもできます)。ループ内では、ループで処理されるオブジェクトの .OuterXML プロパティから、作業用の XML 文字列データの変数である $ouxml を構築します。図 3 に戻ると、.OuterXML が XPathNavigator オブジェクトのプロパティの 1 つであることがわかります。このプロパティによって、XML ファイル内のすべての要素の完全なセットが提供されます。これは、解析エンジンが適切に機能するために必要です。
パイプラインを通じて処理されるオブジェクトでは、$_ が特定のインスタンスを示す記号で、各インスタンスのプロパティおよびメソッドを取得するためのドット表記と共に使用されます。パイプラインのすべてのオブジェクトは、$_ 記号を使用して処理または参照されます。$_ オブジェクトの属性を取得する場合は、$_.Name のように使用します (Name は特定のオブジェクトのメンバー プロパティとします)。Windows PowerShell のパイプラインを通じて渡されるのは、プロパティとメソッドを備えたオブジェクトのみです。
解析前の最後の準備として、<ShortNode/> などの特殊なケースに対処することで、XML テキストを "正規化" します。つまり、解析エンジンはこの要素を <ShortNode></ShortNode> という形式で見ることになります。次のコードでは、正規表現を使用して一致する項目を検索し、この変換を開始します。
$ms = $ouxml | select-string -pattern "<([a-zA-Z0-9]*)\b[^>]*/>" -allmatches
foreach($m in $ms.Matches){ ‘regularize’ to the longer format }
これで、このアプリケーションの主となる分析コードの完成です。解析エンジンは、上の一覧で示した 4 つの配列を設定します。図 6 は、始めの要素について、ファイルをテストするコードを示しています。
図 6 始めの要素についてファイルをテストする
# if you run out of “<” you’re done, so use the “$found_bracket” Boolean variable to test for presence of “<”
$found_bracket = $true
while($found_bracket -eq $true)
{
# Special case of first, or root element, of the XML document;
# here the script-level variable $ctr equals zero.
if($Script:ctr -eq 0)
{
#to handle the top-level root
$leading_brackets += $ouxml.IndexOf("<",$leading_brackets[$Script:ctr])
$leading_value += $ouxml.Substring(0,$ind)
$closing_brackets += $ouxml.IndexOf("</" + $leading_value[0].Substring(1))
$Script:ctr+=1
}
}
図 6 のコードは、XML ドキュメントのルート要素が特殊な場合に対処します。XML のもう 1 つの基本規則として、すべてのスキーマには全体にわたる要素のルート セットを 1 つだけ含みます。この全体を囲むルート要素の内部に、前述の要素の対応規則に従う方法で XML データを構造化することができます。つまり、"<ABC>" があれば、必ず "</ABC>" があります。
配列に項目を追加するには、+= 構文を使用します。配列に項目を設定してしまえば、$leading_brackets[3] のようにインデックスを使用して配列の項目にアクセスできます。
IndexOf 引数では、メソッドの 2 つ目のパラメーターで表される検索の開始位置で、$Script:ctr への参照を示します。Windows PowerShell では、変数にそれぞれ独自のスコープがあります。このスコープは、変数が作成された場所によって決まります。ここでは、$ctr 変数は関数のスコープ外で作成されているため、スクリプト レベルの変数と見なされます。スクリプト レベルの変数は、$Script を参照しないで関数内で変更することはできません。関数内ではなくループ内では、$Script 参照が必要ない場合がありますが、スコープについて常に注意を払うことをお勧めします。
コーディング時、スコープ違反を見つける手掛かりとなるのは、値が変更されているはずなのに変更されていない変数です。このような違反は通常、変数がスコープ外に存在するため、プレフィックスを付けて処理しなければならない場合に起こります。
ルート要素を処理したら、その他のすべての要素を 1 つの else ブロック内で処理します。
else
{
# Check for more \"<\"
$check = $ouxml.IndexOf("<",$leading_brackets[$Script:ctr-1]+1)
if($check -eq - 1)
{
break
}
まず、ファイルの最後まで処理が完了しているかどうかを確認します。この判断基準となるのは、< 記号がそれ以上確認されないことです。前述のコードでこの処理を実行しています。もう < 記号が存在しなければ、break が呼び出されます。
コードの次のセグメントでは、< の場合と </ の場合を区別します。
#eliminate "</" cases of "<"
if($ouxml.IndexOf("</",$leading_brackets[$Script:ctr-1]+1) -ne `
$ouxml.IndexOf("<",$leading_brackets[$Script:ctr-1]+1))
始めの要素をすべて累積しようとしているため、解析エンジン操作のこの段階では始めの要素だけを特定します。比較で "等しくない" ことを表す Windows PowerShell 構文は -ne です。他にも関連する演算子として、-eq、-lt、-gt などがあります。また、Visual Basic のように (C# とは異なります)、コード行を連結するには、行の折り返し文字であるアクサン グラーブ (`) を使用する必要があります。
テストが成功したら、$leading_brackets 配列に新しい要素を設定します。
$leading_brackets += $ouxml.IndexOf("<",$leading_brackets[$Script:ctr-1]+1)
始めの要素の最新の反復処理を終えたら、次は、関連する要素名を分離します。ここでは、次の 2 つの例で示すように、最初の始まり記号 (<) と要素名 (<ElementName) の後には、スペース 1 つと 1 つ以上の属性が続くか、終わりの記号 (>) が続きます。
<ElementName attribute1="X" attribute2 = "Y">, or
<ElementName>
これらの 2 つの例を次のコードを使用して分離します。このコードでは、スペースまたは > 記号のいずれが続いているかを調べます。
$indx_space = $ouxml.IndexOf(" ",$leading_brackets[$Script:ctr])
$indx_close = $ouxml.IndexOf(">",$leading_brackets[$Script:ctr])
if($indx_space -lt $indx_close)
{
$indx_to_use = $indx_space
}
else
{
$indx_to_use = $indx_close
}
正しく要素の終わりが決まったら、$indx_to_use を使用して、目的の要素に関連する要素名文字列を分離します。
$leading_value += $ouxml.Substring($leading_brackets[$Script:ctr],($indx_to_use -
$leading_brackets[$Script:ctr]))
これで、始めの要素の値は < で始まり、1 つのスペースまたは > で終わる文字列になります。
次は、</ElementName という文字列を見つけることで、対応する終わり要素を見つけます。
$closing_brackets += $ouxml.IndexOf("</" + $leading_value[$Script:ctr].Substring(1),`
$leading_brackets[$Script:ctr]+1)
$Script:ctr+=1
最後に、< と </ を区別できない場合に備えて、配列要素をインクリメントして続行します。
else
{
$leading_brackets[$Script:ctr-1] +=1
}
この処理の最後には、次のように 3 つの配列でデータの各部分が示されるようになります。
$leading_brackets:
0 18 62 109 179 207 241 360 375 447 475 509 625 639 681 713 741 775 808 844 900 915 948 976 1012 1044 1077 1142 1154 1203 1292 1329 1344 1426 1475 1490 1616 1687 1701 1743 1810 1842 1890 1904 1941 1979 2031 2046 2085 2138 2153 2186 2235 2250 2315 2362 2378 2442 2476 2524 2539 2607 2643 2718
$leading_value:
<Sciences <Chemistry <Organic <branch <size <price <degree <origin <branch <size <price <degree <origin <Physics <Biology
$closing_brackets:
2718 1687 625 360 179 207 241 273 612 447 475 509 541 1142 900 713 741 775 808 844 882 1129 948 976 1012 1044 1077 1
ノードの関係を確立する
解析エンジン操作の第 2 段階に入ります。この段階は複雑で、$leading_brackets と $closing_brackets のシーケンスで、解析対象の XML のすべてのノードの親子関係および兄弟関係を確立します。まず、いくつか変数を用意します。
# These variables will be used to build an automatic list of XPath queries
$xpaths = @()
$xpaths_sorted = @()
$xpath = @()
[string]$xpath2 = $null
次に、隣接する始めの要素と終わりの要素の最初の組み合わせを決めます。
$first_open = $leading_brackets[0]
$first_closed = $closing_brackets[0]
$second_open = $leading_brackets[1]
$second_closed = $closing_brackets[1]
そして、ループ カウンターをいくつか作成します。
$loop_ctr = 1
$loop_ctr3 = 0
エンジンでは、$leading_brackets などの配列を構築する最初の段階でインクリメントされた $ctr 変数値の回数分、解析を繰り返します (次の if ステートメントが、XML のノード構造を確立するうえで基準となります)。
if($second_closed -lt $first_closed)
$second_closed 値が $first_closed 値より小さい (-lt) 場合、子の関係が確立されます。
<ElementOneName>text for this element
<ChildElementName>this one closes up before its parent does</ChildElementName>
</ElementOneName>
子ノードを検出すると、変数を次の 2 つの隣接する始めと終わりの要素の組み合わせに再設定し、カウンターをインクリメントします。また、重要な役割を果たす $xpath 配列に新しい要素を設定します。
$first_open = $leading_brackets[$loop_ctr]
$first_closed = $closing_brackets[$loop_ctr]
$second_open = $leading_brackets[$loop_ctr + 1]
$second_closed = $closing_brackets[$loop_ctr + 1]
$loop_ctr2 +=1
#if($loop_ctr2 -gt $depth){$loop_ctr2 -= 1}
$depth_trial+=1
$xpath += '/' + $leading_value[$loop_ctr-1]
$loop_ctr+=1
続いて、解析エンジンの重要な処理段階に入ります。ここでは、親子関係が保持されなくなった場合に行う処理について説明します。
この処理の準備として、解析エンジン操作の過程で発生する重複を取り除きます。これを行うには、XPath クエリの配列全体を保持する変数 (解析エンジンが構築するキー値) を要素ごとに調べ、$xpaths に包含されることになる新しい候補を保持していないことを確認します。この候補は、現時点では、図 7 のコードの 8 行目で確立される、$xpath の現在の値です。
図 7 Xpaths の重複の確認
$is_dupe = $false
foreach($xp in $xpaths)
{
$depth = $xpath.Length
$xp = $xp.Replace('/////','')
$xpath2 = $xpath
$xpath2 = $xpath2.Replace(" ","")
$xpath2 = $xpath2.Replace("<","")
if($xp -eq $xpath2)
{
$is_dupe = $true
#write-host 'DUPE!!!'
break
}
$xpath の現在値が重複していなければ、$xpaths 配列に付加し、$xpath を次回使用のために空の配列として再作成します。
if($is_dupe -eq $false){$xpaths += ($xpath2 + '/////');}
$xpath = @()
$xpath2 = $null
XML を繰り返し処理するために解析エンジンが使用する基本的なデバイスは、繰り返しのたびに配列を再構築します。これを行うには、まず、新しい中間配列オブジェクトを移行用のデバイスとして作成します。
$replacement_array_values = @()
$replacement_array_opens = @()
$replacement_array_closes = @()
$finished = $false
$item_ct = 0
エンジンは $leading_value 配列をループ処理し、現在の値をフィルター処理します。
foreach($item in $leading_value)
{
if($item -eq $leading_value[$loop_ctr - 1] -and $finished -eq $false)
{
$finished = $true
$item_ct+=1
continue #because this one should be filtered out
}
フィルター処理されなかった値は、中間配列に設定します。要素名値の配列は、始めと終わりの要素の配列のインデックスに対応付けられるため、3 つの配列はすべて関連付けを通じて設定されます。
$replacement_array_values += $item
$replacement_array_opens += $leading_brackets[$item_ct]
$replacement_array_closes += $closing_brackets[$item_ct]
$item_ct +=1
3 つの中間配列を設定したら、3 つの固定配列に新しい値を代入します。
$leading_value = $replacement_array_values
$opening_brackets = $replacement_array_opens
$closing_brackets = $replacement_array_closes
$loop_ctr+=1
解析エンジンの最初の段階での次の反復処理は、1 つ目の隣接する要素の組み合わせを初期化することで実行できるようになります。
$first_open = $leading_brackets[0]
$first_closed = $closing_brackets[0]
$second_open = $leading_brackets[1]
$second_closed = $closing_brackets[1]
$loop_ctr = 1
$loop_ctr2 = 1
continue # Sends the engine back to the top of the loop
最後に、一連の XPath クエリを完了するには、前述した処理には含まれていない短いパスを生成します。たとえば、現在の例では、この最後の手順を行わなければ、XPath \Sciences\Chemistry が含まれないことになります。これは、XPath クエリの短いバージョンも、すべて重複することなく存在することをテストするというロジックに基づいています。この手順を実行する関数は AddMissingShortPaths です。詳細については、次の記事のコード ダウンロードで確認できます (archive.msdn.microsoft.com/mag201208PowerShell、英語)。
XPath の自動クエリをすべて用意したら、ユーザー向けに Windows フォーム アプリケーションを構築できるようになります。それまでの間、生成された XPath クエリを、Windows PowerShell の出力構文を通じて C:\PowerShell\XPATHS.txt ファイルに保存します。
Windows フォーム アプリケーションを構築する
Windows PowerShell では .NET ライブラリや .NET クラスをホストするため、次のコードを作成して、Windows フォーム アプリケーションや .NET の Drawing クラスで利用できます。
[void] [Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing")
このような基本ビルディング ブロックを作成したら、次のようにフォームやコントロールを構築できます。
$form= New-Object Windows.Forms.Form
$form.Height = 1000
$form.Width = 1500
$drawinfo = 'System.Drawing'
$button_get_data = New-Object Windows.Forms.button
$button_get_data.Enabled = $false
$text_box = New-Object Windows.Forms.Textbox
$button_get_data.Text = "get data"
$button_get_data.add_Click({ShowDataFromXMLXPathFilter})
add_Click はコントロールにイベントをアタッチする Windows PowerShell 構文です。この場合、ボタンのクリック イベントに関数呼び出しをアタッチしています。図 8 のコードは、ボタンとテキスト ボックスを追加します。
図 8 ボタンとテキスト ボックスの追加
$pointA = New-Object System.Drawing.Point
$listbox = New-Object Windows.Forms.Listbox
$form.Controls.Add($listbox)
$listbox.add_SelectedIndexChanged({PopulateTextBox})
$form.Controls.Add($button_get_data)
$form.Controls.Add($text_box)
$pointA.X = 800
$pointA.Y = 100
$button_get_data.Location = $pointA
$button_get_data.Width = 100
$button_get_data.Height = 50
$pointA.X = 400
$pointA.Y = 50
$text_box.Location = $pointA
$text_box.Width = 800
$listbox に XPath クエリのコレクションを設定するため、次のコードを実行します。
foreach($item in $xpaths)
{
$listbox.Items.Add($item.Substring(0,$item.Length - 5))
# Each row in the listbox should be separated by a blank row
$listbox.Items.Add(' ')
}
UI
図 9 は、左側の一覧にあるツールで生成される XPath クエリが表示された UI を示しています。このクエリの 1 つがユーザーによって選択されています。
図 9 XPath クエリの選択
最後に、ユーザーが [GetXMLData] ボタンを押すと、図 10 に示す結果が生成されます。
図 10 結果のウィンドウ
これで、XML ファイルの読み取りと編集が可能なシンプルな UI の完成です。これら全体が Windows PowerShell で作成されています。次回の MSDN マガジンのオンライン記事では、引き続きこのような UI について、名前空間を使用する XML ファイルを処理する方法を紹介します。また、今回説明した手法を使用して、今回のインターフェイスを通じて XML ファイルを編集する方法について説明します。
Joe Leibowitz は、インフラストラクチャ プロジェクトを専門とするコンサルタントです。連絡先は joe.leibowitz@bridgewaresolutions.com (英語のみ) です。
この記事のレビューに協力してくれた技術スタッフの Thomas Petchel に心より感謝いたします。