有没有办法在PowerShell中利用.NET的XmlSerializer类的功能?
更具体地说,能够轻松地将.NET类型/序列化为Xml,例如
XmlSerializer s = new XmlSerializer(typeof(MyType));
TextReader r = new StreamReader("sample.xml");
MyType myType = (MyType)s.Deserialize(r);
r.Close();
我知道我可以从PowerShell上面调用,但有没有办法避免在单独的程序集中定义MyType?感谢
[编辑]由于似乎无法从PowerShell添加类似.NET的类型,请允许我重新定位我的问题:是否有一种简单的方法,如XmlSerializer,在PowerShell中序列化类型?我必须从PS读取/写入一些.xml,并且宁愿在手动执行之前利用这些功能。
答案 0 :(得分:9)
当然,您可以在Powershell中定义一个类型,并在序列化中使用它。
第一步是定义一种新类型。在Powershell 2.0,你可以做到这一点 致电Add-Type。一旦拥有包含新类型的动态编译程序集,就可以像任何其他.NET类型一样自由使用该类型。
第2步是正常使用XmlSerializer类 - 只需将问题中提供的C#代码翻译成Powershell。
以下示例说明。它定义了一个简单类型,然后从XML字符串反序列化以创建该类型的新实例。然后它打印出该反序列化实例上的属性值。
$source1 = @"
using System;
using System.Xml;
using System.Xml.Serialization;
namespace MyDynamicTypes
{
[XmlRoot]
public class Foo
{
[XmlElement]
public string Message { get; set; }
[XmlAttribute]
public int Flavor { get; set; }
}
}
"@
Add-Type -TypeDefinition $source1 -Language "CSharpVersion3" -ReferencedAssemblies System.Xml.dll
$xml1 = @"
<Foo Flavor='19'>
<Message>Ephesians 5:11</Message>
</Foo>
"@
$f1 = New-Object MyDynamicTypes.Foo
$sr = New-Object System.IO.StringReader($xml1)
$s1 = New-Object System.Xml.Serialization.XmlSerializer( $f1.GetType() )
$xtr = New-Object System.Xml.XmlTextReader($sr)
$foo = $s1.Deserialize($xtr)
Write-Output ("foo.Flavor = " + $foo.Flavor)
Write-Output ("foo.Message = " + $foo.Message)
感谢Keith Hill指出Add-Type。
在Powershell 1.0中,您可以使用某些自定义代码执行类似操作(请参阅Powershell: compiling c# code stored in a string)。
function Compile-Code {
param (
[string[]] $code = $(throw "The parameter -code is required.")
, [string[]] $references = @()
, [switch] $asString = $false
, [switch] $showOutput = $false
, [switch] $csharp = $true
, [switch] $vb = $false
)
$options = New-Object "System.Collections.Generic.Dictionary``2[System.String,System.String]";
$options.Add( "CompilerVersion", "v3.5")
if ( $vb ) {
$provider = New-Object Microsoft.VisualBasic.VBCodeProvider $options
} else {
$provider = New-Object Microsoft.CSharp.CSharpCodeProvider $options
}
$parameters = New-Object System.CodeDom.Compiler.CompilerParameters
@( "mscorlib.dll", "System.dll", "System.Core.dll", "System.Xml.dll", ([System.Reflection.Assembly]::GetAssembly( [PSObject] ).Location) ) + $references | Sort -unique |% { $parameters.ReferencedAssemblies.Add( $_ ) } | Out-Null
$parameters.GenerateExecutable = $false
$parameters.GenerateInMemory = !$asString
$parameters.CompilerOptions = "/optimize"
if ( $asString ) {
$parameters.OutputAssembly = [System.IO.Path]::GetTempFileName()
}
$results = $provider.CompileAssemblyFromSource( $parameters, $code )
if ( $results.Errors.Count -gt 0 ) {
if ( $output ) {
$results.Output |% { Write-Output $_ }
} else {
$results.Errors |% { Write-Error $_.ToString() }
}
} else {
if ( $asString ) {
$content = [System.IO.File]::ReadAllBytes( $parameters.OutputAssembly )
$content = [Convert]::ToBase64String( $content )
[System.IO.File]::Delete( $parameters.OutputAssembly );
return $content
} else {
return $results.CompiledAssembly
}
}
}
使用该功能,应用程序变为:
$source1 = @"
using System;
using System.Xml;
using System.Xml.Serialization;
namespace MyDynamicTypes
{
[XmlRoot]
public class Foo
{
[XmlElement]
public string Message { get; set; }
[XmlAttribute]
public int Flavor { get; set; }
}
}
"@
Compile-Code -csharp -code $source1
$xml1 = @"
<Foo Flavor='19'>
<Message>Ephesians 5:11</Message>
</Foo>
"@
$f1 = New-Object MyDynamicTypes.Foo
$sr = New-Object System.IO.StringReader($xml1)
$s1 = New-Object System.Xml.Serialization.XmlSerializer( $f1.GetType() )
$xtr = New-Object System.Xml.XmlTextReader($sr)
$foo = $s1.Deserialize($xtr)
Write-Output ("foo.Flavor = " + $foo.Flavor)
Write-Output ("foo.Message = " + $foo.Message)