2010-05-05 26 views
7

Có cách nào để tận dụng chức năng của lớp XmlSerializer của .NET trong PowerShell không?Chức năng của XmlSerializer trong PowerShell?

Cụ thể hơn, khả năng dễ dàng loại bỏ/sắp xếp các loại .NET thành Xml ví dụ:

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

Tôi biết tôi có thể gọi ở trên từ PowerShell, nhưng có cách nào để tránh xác định MyType trong một hội đồng riêng biệt không? Vì có vẻ như các kiểu giống như .NET không thể được thêm vào từ PowerShell, cho phép tôi nhắm mục tiêu lại câu hỏi của mình: có cách nào dễ dàng, như XmlSerializer, để sắp xếp các loại trong PowerShell không? Không, bạn có thể làm như vậy không? Tôi phải đọc/ghi một số .xml từ PS, và muốn sử dụng chức năng như vậy trước khi thực hiện thủ công.

+0

Và nơi mà bạn sẽ mất 'MyType' từ nếu không phải từ một hội đồng? YOu không thể xác định trực tiếp các loại trong PowerShell; phải sử dụng 'Add-Type' cho điều đó. – Joey

+0

Đó chính xác là câu hỏi của tôi - là có cách nào đó để xác định loại trong PowerShell, và sau đó vượt qua sử dụng nó cho serialization? Dựa trên câu trả lời của bạn, có vẻ như không, do đó phải xác định các loại trong một hội đồng ... Thật là một nỗi đau - Tôi muốn tạo ra một giải pháp dựa trên toàn bộ kịch bản cho một vấn đề mà không đòi hỏi phải lắp ráp et al. Cảm ơn. – Ariel

+1

"là có một cách dễ dàng, như XmlSerializer, để sắp xếp các loại trong PowerShell" Import/Export-CliXml nên hoạt động tốt. – stej

Trả lời

9

Chắc chắn, bạn có thể xác định loại trong Powershell và sử dụng nó trong tuần tự.

Bước đầu tiên là xác định loại mới. Trong Powershell 2.0, bạn có thể làm điều đó bằng cách gọi Add-Type. Một khi bạn có assembly được biên dịch động có chứa kiểu mới, bạn có thể sử dụng kiểu này một cách tự do, giống như bất kỳ loại .NET nào khác.

Bước 2 là chỉ sử dụng lớp XmlSerializer, như bạn thường làm - chỉ dịch mã C# mà bạn đã cung cấp trong câu hỏi cho Powershell.

Ví dụ sau minh họa. Nó định nghĩa một kiểu đơn giản, sau đó deserializes từ một chuỗi XML để tạo ra một thể hiện mới của kiểu đó. Sau đó nó in ra các giá trị thuộc tính trên trường hợp đã được tuần tự hóa.

$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) 

Nhờ Keith Hill để trỏ Thêm loại.


Trong Powershell 1.0, bạn có thể làm điều gì đó tương tự với một số mã tùy chỉnh (xem 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 
    } 
} 
} 

Sử dụng chức năng đó, ứng dụng trở thành:

$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

Cảm ơn bạn đã trả lời! Chưa thử điều này nhưng ý tưởng duy nhất về việc tự động biên dịch các kiểu điền vào toàn bộ tôi đã cố gắng điền vào câu hỏi của mình. Cảm ơn! – Ariel

+0

Bạn nên kiểm tra lệnh ghép ngắn Add-Type trong PowerShell 2.0, cụ thể là tham số TypeDefinition. Nó sẽ * rất nhiều * đơn giản hóa kịch bản của bạn ở trên. :-) –

+0

Tôi đã không nhận ra PowerShell 2.0 đã hết! cảm ơn, tôi sẽ kiểm tra nó. – Cheeso

Các vấn đề liên quan