Hey, Scripting Guy!車を追いかけるのと、XML を追求するのと

Microsoft Scripting Guy

この記事で使用しているコードのダウンロード: HeyScriptingGuy2007_02.exe (150KB)

古いジョークに、 「家の犬は車を見ると追いかけるんだけど、車を捕まえてどうするつもりなんだろう」というのがあります。

良い質問ですが、Scripting Guy は正解を知りません。ただし、近所にいる犬のルーシーであれば話は別です。ルーシーは車を捕まえてしまいますから。ルーシーは酒屋を襲って車で逃走するに違いありません。前庭の状態から考えると、ルーシーは途中で一息付くこともないでしょう。

このジョークを今日のハイテク時代に合わせてアレンジすると、「うちの会社のシステム管理者は XML をずっと勉強しているんだけど、もしも実際に XML を習得したらどうするつもりなんだろう」になるでしょう。

誤解のないように言っておきますが、私たちは使い古されたジョークを現代風にアレンジしただけで、システム管理者を馬鹿にするつもりはありません。

正直な感想としては、少なくともシステム管理の点においては、XML は過剰に宣伝されたテクノロジなのかもしれません。多くの管理者は XML ファイルを処理するスクリプトを記述することなく幸せに暮らしています。これが近い将来に変わることはないと思います。

しかし、データ ストレージの標準として XML を使用するアプリケーションが増えているのも事実です。当然ですよね。フォーマットされたテキスト ファイルではありますが、XML データ ファイルは、すばやく簡単に作成できるだけでなく、プラットフォーム間での移植性があり、複雑な (高度な) データベース プログラムを必要としません。オペレーティング システムとテキスト エディタさえあれば、すぐに XML データベースを作成できます。

つまり、システム管理者が XML を使ってできることが少なくとも 1 つあって、それは、本格的なデータベースであるかのように XML ファイルをクエリするスクリプトを記述することです。その点については、Scripting Guy の右に出るものはいません。

ルーシーですか? 我らがルーシーはどこかの花壇を掘り返すことに夢中で、XML についてのコラムを書く暇はないと思います。

まず、「Hey, Scripting Guy!」のコラムで紹介した 4 つのスクリプトを含むデータベース ファイルであるシンプルな XML ファイルを見てみましょう (図 1)。

Figure 1 Hey, Scripting Guy! XML のスクリプト

<?xml version="1.0" encoding="ISO-8859-1"?>
<Repository>
  <Script>
    <Category>Microsoft Office</Category>
    <Subcategory>Microsoft Access</Subcategory>
    <Keyword>databases</Keyword>
    <Title>How Can I Print a Microsoft Access Report?</Title>
    <URL>https://www.microsoft.com/technet/scriptcenter/resources/qanda/oct06/hey1020.mspx</URL>
  </Script>
  <Script>
    <Category>Microsoft Office</Category>
    <Subcategory>Microsoft Access</Subcategory>
    <Keyword>databases</Keyword>
    <Title>How Can I Compact a Microsoft Access Database?</Title>
    <URL>https://www.microsoft.com/technet/scriptcenter/resources/qanda/oct06/hey1009.mspx</URL>
  </Script>
  <Script>
    <Category>Microsoft Office</Category>
    <Subcategory>Microsoft Word</Subcategory>
    <Keyword>hyperlinks</Keyword>
    <Title>How Can I Change an Existing Hyperlink in a Microsoft Word Document?</Title>
    <URL>https://www.microsoft.com/technet/scriptcenter/resources/qanda/oct06/hey1016.mspx</URL>
  </Script>
  <Script>
    <Category>Enterprise Servers</Category>
    <Subcategory>Microsoft SQL Server</Subcategory>
    <Keyword>databases</Keyword>
    <Title>How Can I Create a Table in a SQL Server Database?</Title>
    <URL>https://www.microsoft.com/technet/scriptcenter/resources/qanda/oct06/hey1016.mspx</URL>
  </Script>
</Repository>

ご覧のとおり、これは非常にシンプルなファイルです。個々のスクリプトは、<Script> タグの下にあります。ここから、これらのスクリプトをレコードして参照します。お察しのとおり、XML の熱狂的信者は、これらの項目をレコードとは呼びません。でもご心配なく。私たちの目的は、皆さんが既にご存じのデータベースへのクエリ技術を異なる新しい種類のデータ ソースに適用する方法について紹介することです。まず、その方法を説明した後で、時間があれば適切な用語を使用しましょう。

レコードに戻りましょう。それぞれのレコードには、<Category>、<Subcategory>、<Keyword>、<Title>、および <URL> というフィールドがあります。

皆さんは私たちが予想していたほど驚かないようですね。では、この XML ファイルを開いてコンテンツをエコー バックできるスクリプトを紹介しましょう。

Set xmlDoc = CreateObject("Microsoft.XMLDOM")
xmlDoc.Async = "False"
xmlDoc.Load("C:\Scripts\Scripts.xml")

Set colNodes = xmlDoc.selectNodes _
("/Repository/Script/*")

For Each objNode in colNodes
   Wscript.Echo objNode.Text
Next

これらのタグ名では大文字と小文字が区別されることに注意してください。これは "/Repository/Script" です。"/repository/script" や "/REPOSITORY/SCRIPT" ではありません。

思ったとおり、これでも皆さんはあまり驚きませんね。しかし、これは、ほんの序の口です。

コードを見てわかるように、私たちは Microsoft.XMLDOM オブジェクトの作成から開始します。これは、XML ファイルを処理するための COM オブジェクトです。その後、Async プロパティを False に設定します。これで、制御がスクリプトに返される前にファイル全体がメモリに読み取られます。次に、Load メソッドを使用して、C:\Scripts\Scripts.xml ファイルを読み取ります。

xmlDoc.Load("C:\Scripts\Scripts.xml")

ファイルがメモリに読み取られると、selectNodes メソッドを使用して、指定したレコードをデータベースから選択できます。

Set colNodes = xmlDoc.selectNodes _
("/Repository/Script/*")

selectNodes に渡されたパラメータに注意してください。これは、XML ファイル内のパスを表します。この XML ファイルの構造を次に示します。

<Repository>
    <Script>
        <Category></Category>
        <Subcategory></Subcategory>
        <Keyword></Keyword>
        <Title></Title>
        <URL></URL>
    </Script>
</Repository>

このことが重要なのでしょうか。答えは、「はい」です。XML ファイルを処理する場合は、構造が非常に重要です。たとえば、レコードの個々のプロパティを取得するにはどうすればよいでしょうか。それは簡単です。<Repository> タグにアクセスします。このタグの後ろには <Script> タグおよび個々のプロパティ タグが続きます。さて、どうでしょう。これは、selectNodes へのパラメータとして指定したパスと同じです。私たちは、"これらのレコードのすべてのプロパティを選択する" を意味する /* を使って、このパスをたどります。言い換えれば、返されたコレクションには、データベース内のすべてのレコードのすべてのプロパティが含まれています。これは、Windows® Management Instrumentation (WMI) の "Select * From" クエリと同じです。

注 : シンプルなスクリプトを試すと、私たちが言っている意味がわかるはずです。

スクリプトの残りの部分は簡単で、For Each ループを設定してコレクションを処理し、各項目とそれぞれのプロパティの Text プロパティの値をエコー バックするだけです。

For Each objNode in colNodes
   Wscript.Echo objNode.Text
Next

車を追いかけるよりも、ずっと簡単です。

しかし、皆さんがおっしゃるとおりですね。ファイルのコンテンツ全体をエコー バックするだけであれば、その XML のすべてをバイパスして FileSystemObject を使用すれば済むことです (実際は、それよりも少し複雑になるかもしれませんが、ほんの少しだけです)。私たちの目的は皆さんを惑わせて「この XML というのは便利なんだ」と思わせることなので、もう少しお付き合いください。。

さて、どんな方法があるのかを考えてみましょう。最初のスクリプトでは、すべてのレコードのすべてのプロパティ値を取得しました。これで問題はないのですが、必要なのはスクリプト タイトルだけだったとしたらどうでしょうか。それは可能でしょうか。ちょっと待ってくださいね。

ルーシーによると、必要な処理は、selectNodes コマンドを変更してパスの最後に目的のプロパティを追加することだけです。つまり、次のようになります。

    Set colNodes=xmlDoc.selectNodes _    ("/Repository/Script/Title")

おわかりのように、最初にすべてのプロパティが取得された理由は、* ワイルドカードを使用したからです。ここでは、Title プロパティだけを取得します。なぜでしょうか。それは、これが取得するように言われた唯一のプロパティ値だからです。

注 : XML では、求めたものが正確に返されました。犬のルーシーに悪気はないのですが、XML は人類の最良の友になりました。

もちろん、1 つのプロパティ以上のものを返すことも可能です。たとえば、この変更されたコマンドは、Title プロパティと URL プロパティの両方を返します。

    Set colNodes=xmlDoc.selectNodes _    ("/Repository/Script/(Title | URL)")

構文は少し変に見えますが、慣れれば問題ありません。始めるには、以前と同様にパスの親の部分を指定します。

    /Repository/Script/

次に、かっこのセットを追加して、返すプロパティをかっこの内側で指定します。個々のプロパティを区切るには、パイプ区切り文字 ( | ) を使用します。つまり、次のようになります。

    (Title | URL)

少し変に見えますが、これで問題なく機能します。

もちろん、2 つ以上のプロパティを返すことも可能です。パイプ区切り文字を使用している限り、必要な情報をすべて返すことができます。たとえば、次のコマンドでは 3 つのプロパティ(Title、URL、および Keyword) が返されます。

    Set colNodes=xmlDoc.selectNodes _    ("/Repository/Script/(Title | URL |          Keyword)")

なかなか便利だと思いませんか。

私たちは、結構良いと思ったんですよ。皆さんは難しい方ばかりですね。でも、良い点にお気付きです。ここまでやったことは、データベース内のすべてのレコードに関する情報を取得することだけです。しかし、それで何も悪いことはありません。多くの場合は、これだけで十分です。しかし、これらのレコードのサブセットの情報だけを取得する場合の方が多いのです。たとえば、databases というキーワード (Keyward) を含むスクリプトに関する情報だけを取得するとします。お察しのとおり、次のような構文を使用します。

    Set colNodes=xmlDoc.selectNodes _
    ("/Repository/Script " & _
    "[Keyword = ‘databases’]")

この構文も少し変に見えます。しかし、この構文は簡単でわかりやすいのが特長です。親パスを指定した後、"Where" 句 (x = y など) を角かっこの内側に配置します。

/Repository/Script [Keyword = ‘databases’]

既にお気付きかもしれませんが、Where 句に相当する部分がスクリプトに対して "Keyword 属性が databases に等しい項目だけを返す" ように指示しています。databases という語が引用符で囲まれていることに注意してください。これは必須です。フィルタする語を二重引用符で囲んだ場合、スクリプトを実行すると構文エラーが発生します。

その理由がわかりますか。クエリ文字列全体 ("/Repository/Script [Keyword = ‘databases’]") が二重引用符で囲まれているからです。

もちろん、データをフィルタするときは、等号以外も使用できます。大なり (>) 小なり (<) 記号に加えて、以上 (<=) および以下 (>=) 記号が使用可能です。また、これらの記号の前に感嘆符を配置して、記号をネゲートすることもできます。たとえば、次のコマンドは、Keyword が databases に等しくないすべてのスクリプトを取得します (!= に注意してください)。

    Set colNodes=xmlDoc.selectNodes _
    ("/Repository/Script " & _
    "[Keyword != ‘databases’]")

ちょっと待ってください。「フィルタは設定できるけど、フィルタを設定すると同時に返すプロパティを指定することはできないでしょう」という質問ですか。もちろん、できます。

    Set colNodes=xmlDoc.selectNodes _
    ("/Repository/Script " & _
    "[Keyword = ‘databases’]/Title")

何の問題もなければ、このコマンドは、Keyword が databases であるすべてのスクリプトの Title プロパティだけを返します。確認してみましょう。

    How Can I Print a Microsoft Access Report?
    How Can I Compact a Microsoft Access Database?
    How Can I Create a Table in a SQL Server     Database?

最後に、もう 1 つコマンドを含めることができるかどうか見てみましょう。かなりの進歩が見られましたが、まだ必要以上のレコードが返されている可能性があります。結局のところ、前のコマンドは Microsoft® Access® スクリプトと Microsoft SQL Server™ スクリプトの組み合わせを返します (その理由は、これらのすべてのスクリプトが databases という Keyword を使用するからです)。返されるデータを databases という Keyword と、Microsoft SQL Server という Subcategory のあるスクリプトに制限した場合はどうなるでしょうか。複数の条件に基づいてフィルタすることは可能でしょうか。

次の構文を見てください。

    Set colNodes=xmlDoc.selectNodes _
    ("/Repository/Script " & _
    "[Keyword = ‘databases’ and " & _
    "Subcategory = ‘Microsoft SQL Server’]")

基本構文は同じです。2 つの条件 (Keyword = ‘databases’ および Subcategory = ‘Microsoft SQL Server’) を使用して、これらの 2 つを AND 演算子で接続しました。

注 : はい。おっしゃるとおりです。このシンプルな XML ファイルでは、Subcategory が Microsoft SQL Server であるすべてのスクリプトをリクエストできました。しかし、これでは何もおもしろくありませんし、学ぶべきこともありません。

OR 句を使用することもできます。たとえば、Subcategories が Microsoft Excel®、Microsoft PowerPoint®、Microsoft Outlook® などに等しい大量の Microsoft Office スクリプトがあるとします。返されるデータを Microsoft Word または Microsoft Access というサブカテゴリ (subcategories) からのスクリプトだけに制限することは可能でしょうか。もちろん可能です。

    Set colNodes=xmlDoc.selectNodes _
    ("/Repository/Script " & _
    "[Subcategory = ‘Microsoft Word’ " & _
    "or Subcategory = ‘Microsoft Access’]")

それらしくなりましたね。このコラムで皆さんの人生が変わるとは思えませんが、この方法で XML ファイルをクエリすることはできます。基本的な XML 技法を学習するか、車を追いかけるかは、皆さん方次第です。ご自由にどうぞ (後者を選んでルーシーに出くわした場合、Scripting Guy がよろしく言っていたと伝えてください。また、私たちの庭には近づかないようにとも伝えておいてください)。

Hey, Scripting Guy! - Every Day

今月の「Hey, Scripting Guy!」コラムを読んだ皆さんは、これが今まで読んだ中で最高の技術文書だと思ったはずです。これまで人類が記述したものの中で最高傑作と思っているかもしれません。ひょっとしたら、このような文書をもっと読みたくて郵便受けの前で次の TechNet Magazine を待っている方もいるかもしれません。

一体何を待っているのですか。我らがルーシーのことをもっと知りたいのですか。それとも、Scripting Son の最新の冒険談を読みたいのですか。去年の Turducken Bowl の結果をご存じですか。「Hey, Scripting Guy!」コラムを毎日読んで、重要な問題に遅れを取らないようにしてください。私たちは、毎週月曜日から金曜日まで (主な休日および Scripting Guy の休暇を除く)、高校野球、大学フットボールとバスケットボールに関するニュース、そして時には地域の天気予報をお知らせしています ("地域" というのはレドモンドのことですが、レドモンドの天候なんか興味がないでしょう)。

さらに、スクリプト記述に関する新しい事項を毎日学習できます。事実、この興味深いコラムの目玉はスクリプト記述に関する情報です。各コラムでは、Scripting Guy が実在すると信じている人々から寄せられた実際の質問に Scripting Guy がお答えします。毎日のコラムは、microsoft.com/japan/technet/scriptcenter/resources/qanda で読むことができます。また、これまでに Scripting Guy は多くの質問に答えているので、アーカイブは非常に豊富なスクリプト記述に関するソースとして活用できます (microsoft.com/japan/technet/scriptcenter/resources/qanda/hsgarch.mspx を参照してください)。

Scripting Guy に質問がある場合は、scripter@microsoft.com (英語) に質問を送信してください (送信されない質問にはお答えできません。しかし、送信された質問に Scripting Guy がお答えする確率は宝くじの当選率よりも高いはずです)。

Microsoft Scripting Guyは、マイクロソフトの仕事をしています。正確に言うと、マイクロソフトに雇われています。野球をプレイ、監督、観戦 (または他のさまざまな活動を) しているのでない限り、Scripting Guy は TechNet Script Center を運営しています。詳細については、https://www.microsoft.com/japan/technet/scriptcenter/default.mspx を参照してください。

© 2008 Microsoft Corporation and CMP Media, LLC. All rights reserved; 許可なしに一部または全体を複製することは禁止されています.