1

問題

場所の XML リストを一連のオブジェクトに変換しようとしています。

XML ファイルには、場所ごとに 1 つの Location 要素があります。XML 属性には、オブジェクトのプロパティ値が含まれています。

一部のターゲット プロパティに、ソース属性とは異なる名前を付けたいと考えています。

後でオブジェクトを CSV ファイルにシリアル化したいので、プロパティの順序が重要です。

問題を説明するための 2 つの場所の例を次に示します。

[xml] $InputXml = @'
<?xml version="1.0" encoding="UTF-8"?>

<CTLocations xmlns="http://www.cartrawler.com/">
<Country code="AL" name="Albania" continent="Europe">
<Location Id="7188" Name="Tirana Airport" Lat="41.42108838" Lng="19.71271276" CountryCode="AL" Address="Tirana Airport Muhamet Gjollesha Str., Muhamet Gjollesha Str., Tirana" CityName="Tirana" Airport="1" AirportCode="TIA" RailwayStation="0"/>
<Location Id="30768" Name="Tirana Downtown" Lat="41.332" Lng="19.832" CountryCode="AL" Address="Rruga E Durresit. Nr 61, Tirana" CityName="Tirana" Airport="0" RailwayStation="0"/>
</Country>
</CTLocations>
'@

部分解

私のソリューションは、属性の完全なセットを持つ要素に対して機能しますが、属性のいずれかが欠落している場合は失敗します。

Select-Xmlコマンドレットを使用して重要な要素を選択し、PSCustomObjectを使用して、順序付けされ名前が変更されたプロパティを持つオブジェクトを作成しています。

Select-Xml -Xml $InputXml -XPath '//ns:Location' -Namespace @{ns = 'http://www.cartrawler.com/'} |
% {
  $n = $_.Node

  [PSCustomObject] @{
    LocationCode = $n.Id
    LocationName = $n.Name
    Latitude = $n.Lat
    Longitude = $n.Lng
    CountryCode = $n.CountryCode
    FormattedAddress = $n.Address
    CityName = $n.CityName
    ServesAirport = $n.Airport
    AirportCode = $n.AirportCode
    ServesRailwayStation = $n.RailwayStation
  }
}

厳密モードの結果

strict-mode を設定した場合:

Set-StrictMode -Version 3.0

最初の要素にはすべての属性が含まれているため、オブジェクトに変換されます。

LocationCode         : 7188
LocationName         : Tirana Airport
Latitude             : 41.42108838
Longitude            : 19.71271276
CountryCode          : AL
FormattedAddress     : Tirana Airport Muhamet Gjollesha Str., Muhamet Gjollesha Str., Tirana
CityName             : Tirana
ServesAirport        : 1
AirportCode          : TIA
ServesRailwayStation : 0

2 番目の要素には AirportCode 属性がないため、PowerShell は代わりに例外を発生させます。

Property 'AirportCode' cannot be found on this object. Make sure that it exists.
At line:16 char:3
+   [PSCustomObject] @{
+   ~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], PropertyNotFoundException
    + FullyQualifiedErrorId : PropertyNotFoundStrict

Unstrict モードの結果

厳密モードをオフにすると:

Set-StrictMode -Off

PowerShell は両方の場所をオブジェクトに変換します。不足しているプロパティは null です:

LocationCode         : 7188
LocationName         : Tirana Airport
Latitude             : 41.42108838
Longitude            : 19.71271276
CountryCode          : AL
FormattedAddress     : Tirana Airport Muhamet Gjollesha Str., Muhamet Gjollesha Str., Tirana
CityName             : Tirana
ServesAirport        : 1
AirportCode          : TIA
ServesRailwayStation : 0

LocationCode         : 30768
LocationName         : Tirana Downtown
Latitude             : 41.332
Longitude            : 19.832
CountryCode          : AL
FormattedAddress     : Rruga E Durresit. Nr 61, Tirana
CityName             : Tirana
ServesAirport        : 0
AirportCode          : 
ServesRailwayStation : 0

より良い方法はありますか?

より良い方法がある場合、これを機能させるために厳密モードをオフにしたくありません。

厳密モードで動作するものはすべて受け入れられます。T-SQL CASE 式Python の dict get method のようなものを探していました。多分それを行うXPathの方法もあります。

4

1 に答える 1

1

あなたの場合は簡単です:

select-Xml -Xml $InputXml -XPath '//ns:Location' -Namespace @{ns = 'http://www.cartrawler.com/'} |
% {
  $n = $_.Node

  [PSCustomObject] @{
    LocationCode = $n.Id
    LocationName = $n.Name
    Latitude = $n.Lat
    Longitude = $n.Lng
    CountryCode = $n.CountryCode
    FormattedAddress = $n.Address
    CityName = $n.CityName
    ServesAirport = $n.Airport
    AirportCode = $(if($n.Airport -eq '1'){$n.AirportCode}else{""})
    ServesRailwayStation = $n.RailwayStation
  }
}

より一般的に:

select-Xml -Xml $InputXml -XPath '//ns:Location' -Namespace @{ns = 'http://www.cartrawler.com/'} |
% {
  $n = $_.Node

  [PSCustomObject] @{
    LocationCode = $n.Id
    LocationName = $n.Name
    Latitude = $n.Lat
    Longitude = $n.Lng
    CountryCode = $n.CountryCode
    FormattedAddress = $n.Address
    CityName = $n.CityName
    ServesAirport = $n.Airport
    AirportCode = $(if($n.GetAttributeNode("AirportCode") -ne $null){$n.AirportCode}else{""})
    ServesRailwayStation = $n.RailwayStation
  }
}

これを書いたら、私の昔からのプログラマーの意見 (あなたはどうでもいいことです) は、strict モードを使いたければスクリプトをやめて Java、C#、C、または C++ を書き始めるというものです。あなたが厳密モードで戦っている近似の種類は、私にとってテーブルの隅にある問題を迅速に解決するスクリプトの + です。私の意見では、strict モードを使用すると、興味のない従来のプログラミングのすべての欠点がもたらされるということですが、それは単なる私の意見です。

于 2013-10-01T13:39:07.290 に答える