我正在尝试将XML位置列表转换为一组对象。
XML文件每个位置都有一个Location元素。 XML属性包含对象属性值。
我希望某些目标属性与源属性具有不同的名称。
稍后我想将对象序列化为CSV文件,因此属性的顺序很重要。
以下是两个位置的示例,用于说明问题:
[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 cmdlet选择重要元素,使用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
}
}
当我有严格模式设置时:
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
第二个元素缺少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
当我关闭严格模式时:
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 expression或Python's dict get method的内容。也许有一种XPath方法可以做到这一点。
答案 0 :(得分: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
}
}
一旦写完这篇文章,我的老编程意见(你不关心的那种)就是如果你想使用严格模式就停止编写脚本并开始编写java,C#,C或C ++。你使用严格模式进行的近似是一种脚本编写,这对我来说非常好地解决了桌面角落的问题。我的观点是,使用严格模式会带来传统编程的所有缺点而没有兴趣,但这只是我的观点。