2010-05-05 82 views
7

有沒有方法在PowerShell中利用.NET的XmlSerializer類的功能?XmlSerializer在PowerShell中的功能?

更具體地說,能夠輕鬆地將.NET類型解析/序列化到Xml中,例如

XmlSerializer s = new XmlSerializer(typeof(MyType)); 
TextReader r = new StreamReader("sample.xml"); 
MyType myType = (MyType)s.Deserialize(r); 
r.Close(); 

我知道我可以從上面的PowerShell呼籲,但有一種方法,以避免在一個單獨的組件限定的MyType?謝謝

[編輯]由於似乎是類似於.NET的類型不能從PowerShell添加,請允許我重新定位我的問題:是否有一種簡單的方法,比如XmlSerializer,在PowerShell中序列化類型?我必須從PS讀取/寫入一些.xml文件,並且寧願在手動執行之前利用這些功能。

+0

你會在哪裏拿'MyType'從如果不從程序集? YOu無法直接在PowerShell中定義類型;必須使用'Add-Type'。 – Joey 2010-05-05 19:04:07

+0

這正是我的問題 - 有沒有辦法以某種方式在PowerShell中定義類型,然後將其用於序列化?根據你的回答,似乎沒有,因此必須在程序集中定義類型......真是一種痛苦 - 我想爲一個問題創建一個完整的基於腳本的解決方案而不需要程序集等。謝謝。 – Ariel 2010-05-05 19:09:09

+1

「有沒有一種簡單的方法,像XmlSerializer,在PowerShell中序列化類型」Import/Export-CliXml應該可以正常工作。 – stej 2010-05-06 06:04:46

回答

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指定添加類型。


在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) 
+0

感謝您的回答!還沒有嘗試過,但動態編譯類型的唯一想法填補了整個我試圖填補我的問題。謝謝! – Ariel 2010-05-06 18:47:29

+0

您應該查看PowerShell 2.0中的Add-Type cmdlet,特別是TypeDefinition參數。它會大大地簡化你的腳本。 :-) – 2010-05-07 04:40:08

+0

我沒有意識到powershell 2.0出來了!謝謝,我會檢查出來的。 – Cheeso 2010-05-07 10:21:32