コンテンツへスキップ

XML などのプロパティの中の「name=”value”」みたいなやつの値をCSV とかに抽出したい。

XML などのプロパティの中の「name=”value”」みたいなやつの値をCSV とかに抽出したい。

例えばこんなやつの「name=」の値を取り出して一覧にしたい。

例えばこんなやつ

<Configuration xmlns:xlink="http://www.w3.org/1999/xlink">
   <Property name="ie.ldap.serverHostName" overridable="true"
             targetFile="codebase/WEB-INF/ieStructProperties.txt"
             value="test.bbtec.net"/>
   <Property name="installedProduct.location.Apache" overridable="true"
             targetFile="codebase/WEB-INF/ieWebServerLocation.txt"
             value="C:\ptc\HTTPServer"/>
   <Property name="ie.ldap.managerPw" overridable="true"
             targetFile="codebase/WEB-INF/ieStructProperties.txt"
             value="encrypted.ie.ldap.managerPw"/>
   <Property name="wt.webapp.name" overridable="true" targetFile="codebase/wt.properties"
             value="Windchill"/>
   <Property name="wt.rmi.server.hostname" overridable="true"
             targetFile="codebase/wt.properties"
             value="test.bbtec.net"/>
</Configuration>

Bing のサンプルコード

Bing 氏によると、Get-Content でXML をプロパティ単位で取得できるとのこと。

# XMLファイルのパス
$xmlFilePath = "path\to\your\file.xml"

# CSVファイルのパス
$csvFilePath = "path\to\your\output.csv"

# XMLファイルを読み込む
[xml]$xml = Get-Content -Path $xmlFilePath

# 必要なプロパティを抽出する
$data = foreach ($item in $xml.Root.Element) {
    [PSCustomObject]@{
        Property1 = $item.Property1
        Property2 = $item.Property2
        # 他のプロパティも追加できます
    }
}

# データをCSVファイルにエクスポートする
$data | Export-Csv -Path $csvFilePath -NoTypeInformation

$xml.Root.Element が下記のXML を前提とた場合の値になっています。

<Root>
    <Element>
        <Property1>Value1</Property1>
        <Property2>Value2</Property2>
    </Element>
    <Element>
        <Property1>Value3</Property1>
        <Property2>Value4</Property2>
    </Element>
</Root>

実行結果がこんな感じになります。

Property1 Property2
--------- ---------
Value1    Value2
Value3    Value4

試してみた結果

上記の例ではプロパティがタグで挟んでありましたが、name=**** でもプロパティとして取得されていたので、「例えばこんなやつ」の場合、下記のように書けます。

# XMLファイルを読み込む
[xml]$xml = Get-Content -Path $xmlFilePath;

# 各Element要素をループしてプロパティを表示
foreach ($item in $xml.Configuration.Property) {
    $data += @(
        [PSCustomObject]@{ 
            Name=$item.name;
            Override=$item.overridable;
            Value=$item.value;
        }
    )
}

# 書き出し
$data | ForEach-Object { $_ } | Export-Csv -Path $csvFilePath -NoTypeInformation;

最初、正規表現を使って抜き出ししようと思ってましたが、理解するとこちらの方がはるかに楽でした。

正規表現で頑張ってみた!

参考までに、無駄な思考錯誤をいかに置いておきます。
最初「$xml.Root.Element」が理解できていなくて、Bing 氏の提案をあきらめて、
正規表現で頑張ってました。

正規表現でダブルクォーテーションで囲まれた値は「”([^”]*)”」

Bing 氏による解説

正規表現の構造
":
ダブルクォーテーションを表します。
これはリテラル文字として、文字列の開始と終了を示します。
([^"]*):
これはキャプチャグループです。キャプチャグループは、括弧 () で囲まれた部分で、マッチした内容を後で参照するために使用されます。
[^"]:
これは否定文字クラスです。[] 内の ^ は否定を意味し、" 以外の任意の文字を表します。
つまり、ダブルクォーテーション以外の任意の文字にマッチします。
*:
これは量指定子で、直前の要素(この場合は [^"])が0回以上繰り返されることを意味します。
つまり、ダブルクォーテーション以外の任意の文字が0回以上続く部分にマッチします。
全体の意味
"([^"]*)":
最初の " はダブルクォーテーションの開始を示します。
([^"]*) はダブルクォーテーション以外の任意の文字が0回以上続く部分をキャプチャします。
最後の " はダブルクォーテーションの終了を示します。

例えば、文字列 This is a "test" string with "multiple" quoted "words". に対してこの正規表現を適用すると、以下の部分がマッチします:

"test"
"multiple"
"words"
そして、キャプチャグループ ([^"]*) によって、以下の文字列が抽出されます:

test
multiple
words

あれこれした結果こんな感じになりました。
コメントアウトしてあるような感じで書くと対象の値が複数の時、全部出力することもできます。
今回は「name」属性だけに絞り込む感じなので、2段階でマッチを評価しています。

配列をCSV に変換する部分は、文字列のlength をCSV に出力してしまう現象を回避した結果こんな感じになりました。
[PSCustomObject] の定義が配列の定義に入れ子になっている感じです。

$xmlFilePath = "site.xconf";
$csvFilePath = "output.csv";
$pattern = 'name="([^"]*)"';
$pattern2 = '"([^"]*)"';
$data = @();

Get-Content -Path $xmlFilePath | ForEach-Object{

    if(($_ -match "name=" )){
        $matches = [regex]::Matches($_, $pattern);
        $matches = [regex]::Matches($matches.Value, $pattern2);
        $data += @( [PSCustomObject]@{ name = $matches.Value.Replace('"','') } );

        #foreach ($match in $matches) {
        #    $match.Groups.Value
        #}
    }
}

$data | ForEach-Object { $_ } | Export-Csv -Path $csvFilePath -NoTypeInformation;

(Visited 15 times, 1 visits today)

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です