如何将 XML 映射到 PowerShell 中对象的动态属性?
我需要自动将许多 .NET 对象添加到业务系统中。 PowerShell 脚本需要读取 XML 输入文件并通过业务系统的 API 执行适当的更改。
我发现的问题是对象有许多不同的类型,因此具有不同的属性。
下面是 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>
脚本的相关部分:
$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 元素中,以便可以循环遍历它们。我不确定的是在该循环内要做什么。
假设每个属性的 XML 元素名称与 $obj 属性名称匹配,如何从相应的 XML 值动态访问和设置该属性?
I need to automate the addition of many .NET objects to a business system. A PowerShell script needs to read an XML input file and perform the appropriate changes via the business system's API.
The problem I'm finding is that the objects are of many different types and therefore have different properties.
Here's an example of the 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>
Relevant portion of script:
$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)
}
}
I probably need to put the object-specific properties into their own XML element so that I can loop through them. What I'm not sure about is what to do inside that loop.
Assuming each property's XML element name matches the $obj property name, how do I dynamically access and set the property from its corresponding XML value?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您的方法使用
PropertyInfo.SetValue
当然可以,但您也可以利用 PowerShell 的动态特性,自动类型转换大大简化了初始化:在这里,PowerShell 将评估
($_.Name)
值,然后使用该值调用$obj.___
,就像如果您编写了$obj.SomeProperty
。它还会将$_.Value
返回的字符串转换为适当的类型(如下所示)*,而SetValue
会抛出一个参数例外。与您现有的代码相结合:
我使用以下 xml 对此进行了测试,该 xml 改编自问题的示例 (AppDomainSetup 是一种方便的系统类型,具有许多可设置的属性):
这设置了布尔值将
DisallowCodeDownload
*、枚举LoaderOptimization
和字符串ConfigurationFile
属性设置为指定的非默认值。* 注意: 这种简单方法的一个需要注意的是,普通的 PowerShell 脚本规则用于转换布尔值,因此只能使用
$null
、0
、 和空被视为假,其他一切都被视为真。这意味着 xml 中的Value="False"
设置仍然将属性设置为 true,因为 PowerShell 会看到非空字符串'False'
并没有进一步解析它。您可以使用空字符串
Value=""
将属性设置为 false。但是,为了实现更直观的解析行为,您需要手动调用[Convert]::ToBoolean( $_.Value )
,或[转换]::ChangeType( $_.Value, [ bool] )
,或类似的东西:(布尔属性通常有一个默认值 false,但我可以看到有人想要显式初始化,或者通过更改值而不是删除条目来切换单个分配,并运行面对这种意想不到的行为。)
Your approach using
PropertyInfo.SetValue
will certainly work, but you can also take advantage of PowerShell's dynamic nature and automatic type conversion to greatly simplify the initialization:Here, PowerShell will evaluate the
($_.Name)
value, and then invoke$obj.___
with that value, just as if you had written$obj.SomeProperty
. It will also convert the string returned by$_.Value
to the appropriate type (as shown below)∗, whereasSetValue
would throw an argument exception.Combining with your existing code:
I tested this using the following xml, adapted from the question's example (AppDomainSetup being a convenient system type with a lot of settable properties):
This sets the boolean
DisallowCodeDownload
∗, the enumLoaderOptimization
, and the stringConfigurationFile
properties to the specified non-default values.∗ Note: One caveat to the simple approach is that the normal PowerShell scripting rules are used to convert boolean values, so only
$null
,0
, and empty are treated as false, and everything else as true. This means aValue="False"
setting in xml will still set the property to true, because PowerShell sees a non-empty string'False'
and does not parse it further.You can use an empty string,
Value=""
, to set a property to false. However, to allow the more intuitive parsing behavior, you would need to manually call[Convert]::ToBoolean( $_.Value )
, or[Convert]::ChangeType( $_.Value, [bool] )
, or something similar:(Boolean properties usually have a default value of false, but I could see someone wanting explicit initialization, or toggling a single assignment by changing the value instead of deleting the entry, and running across this unexpected behavior.)
我向 XML 添加了一个带有 Property 子节点的 Properties 元素,并添加了以下脚本:
I added a Properties element with Property child nodes to the XML and added this script: