2011-11-22 59 views
1

我需要自動將許多.NET對象添加到業務系統中。 PowerShell腳本需要讀取XML輸入文件並通過業務系統的API執行適當的更改。如何將XML映射到PowerShell中的對象上的動態屬性?

我發現的問題是,對象有許多不同的類型,因此具有不同的屬性

這裏是XML的例子:

$xmlItem.BusinessObjects.GetElementsByTagName("BusinessObject") | % { 
    $businessObject = $_ 
    if ($businessObject.Action -eq "Add") { 
     $assemblyName = $businessObject.AssemblyName 
     $className = $businessObject.ClassName 
     $assembly = [Reflection.Assembly]::Load($assemblyName) 
     $obj = $assembly.CreateInstance($className) 
     ### TODO: How to set properties on $obj ??? 
     $api.AddBusinessObject($obj) 
    } 
} 

我可能需要把特定對象的屬性到自己的XML元素,這樣我可以循環:

<BusinessObject> 
    <Action>Add</Action> 
    <Id>{867B6C43-2A20-485D-A3E3-CBFCD50CA6F3}</Id> 
    <AssemblyName>ABC.BusinessObjects, Version=1.0.0.0, Culture=neutral, PublicKeyToken=361ad75badc53918</AssemblyName> 
    <ClassName>ABC.BusinessObjects.HealthService</ClassName> 
    <!-- Properties specific to object --> 
    <HealthServiceName>Jo's GP Super Center</HealthServiceName> 
</BusinessObject> 
<BusinessObject> 
    <Action>Add</Action> 
    <Id>{867B6C43-2A20-485D-A3E3-CBFCD50CA6F3}</Id> 
    <AssemblyName>ABC.BusinessObjects, Version=1.0.0.0, Culture=neutral, PublicKeyToken=361ad75badc53918</AssemblyName> 
    <ClassName>ABC.BusinessObjects.Patient</ClassName> 
    <!-- Properties specific to object --> 
    <PatientName>Anna Smith</PatientName> 
</BusinessObject> 

腳本的相關部分通過他們。我不確定的是在該循環內部要做什麼。

假設每個屬性的XML元素名稱都與$ obj屬性名稱相匹配,那麼如何動態訪問並設置相應XML值的屬性?

回答

2

Your approach,但你也可以利用PowerShell的動態特性和自動類型轉換大大簡化初始化:

$businessObject.Properties.GetElementsByTagName('Property') | % { 
    $obj.($_.Name) = $_.Value 
} 

這裏,PowerShell的將評估​​值,然後調用$obj.___與價值,就像如果你有w^ritten $obj.SomeProperty。它還會將由$_.Value返回的字符串轉換爲適當的類型(如下所示)&lowast;,而SetValue會拋出一個參數異常。


與現有的代碼結合:

$xmlItem.BusinessObjects.GetElementsByTagName('BusinessObject') | % { 
    $businessObject = $_ 
    if($businessObject.Action -eq 'Add') { 
    $assemblyName = $businessObject.AssemblyName 
    $className = $businessObject.ClassName 
    $assembly = [Reflection.Assembly]::Load($assemblyName) 
    $obj = $assembly.CreateInstance($className) 

    if($businessObject.Properties) { 
     $businessObject.Properties.GetElementsByTagName('Property') | % { 
     $obj.($_.Name) = $_.Value 
     } 
    } 

    $obj # $api.AddBusinessObject($obj) 
    } 
} 

我測試此使用下面的XML,改編自問題的例子(AppDomainSetup是一個方便的系統類型有很多可設置的屬性的):

<BusinessObjects> 
    <BusinessObject> 
    <Action>Add</Action> 
    <Id>{867B6C43-2A20-485D-A3E3-CBFCD50CA6F3}</Id> 
    <AssemblyName>mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</AssemblyName> 
    <ClassName>System.AppDomainSetup</ClassName> 
    <Properties> 
     <Property Name="DisallowCodeDownload" Value="True"/> 
     <Property Name="LoaderOptimization" Value="SingleDomain"/> 
     <Property Name="ConfigurationFile" Value="C:\config.xml"/> 
    </Properties> 
    </BusinessObject> 
</BusinessObjects> 

這設置了布爾值DisallowCodeDownload&lt;,枚舉LoaderOptimization和字符串ConfigurationFile屬性爲指定的非默認值。


&lowast;注意:一個簡單的方法是使用普通的PowerShell腳本規則來轉換布爾值,所以只有$null,0和empty被視爲false,其他所有的都被視爲true。這意味着一個Value="False" xml設置將仍然設置屬性爲true,因爲PowerShell看到一個非空字符串'False'並且不進一步解析它。

可以使用空字符串Value=""將屬性設置爲false。然而,爲了讓更多的直觀的解析行爲,您將需要手動調用[Convert]::ToBoolean($_.Value),或[Convert]::ChangeType($_.Value, [bool]),或類似的東西:

$name = $_.Name 
if($obj.$name -is [bool]) { 
    $obj.$name = [Convert]::ToBoolean($_.Value) 
} else { 
    $obj.$name = $_.Value 
} 

(布爾屬性通常有假的默認值,但我可以看到有人想明確初始化或切換單個分配,方法是更改​​值而不是刪除條目,並運行此意外行爲。)

0

我添加屬性子節點屬性元素的XML,並將此腳本:使用PropertyInfo.SetValue肯定會工作

if ($businessObject.Properties) { 
    $businessObject.Properties.GetElementsByTagName("Property") | % { 
     $prop = $_ 
     $pi = $obj.GetType().GetProperty($prop.Name) 
     $pi.SetValue($obj, $prop.Value, $null) 
    } 
} 
相關問題