2010-05-05 10 views
7

C'è un modo per sfruttare la funzionalità della classe XmlSerializer di .NET in PowerShell?Le funzionalità di XmlSerializer in PowerShell?

Più specificamente, la capacità di facilmente DE/serializzare tipi NET esempio in XML

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

so che posso chiamare in precedenza da PowerShell, ma c'è un modo per evitare di definire MyType in un assembly separato? Grazie

[Modifica] Poiché sembra che i tipi simili a .NET non possano essere aggiunti da PowerShell, permettimi di ri-indirizzare la mia domanda: c'è un modo semplice, come XmlSerializer, di serializzare i tipi in PowerShell? Devo leggere/scrivere alcuni .xml da PS, e preferirei sfruttare tale funzionalità prima di farlo manualmente.

+0

e dove si vorrebbe 'MyType' se non da un assieme? Non è possibile definire direttamente i tipi in PowerShell; devo usare 'Aggiungi tipo 'per quello. – Joey

+0

Questa è esattamente la mia domanda: esiste un modo per definire in qualche modo il tipo in PowerShell e quindi utilizzarlo per la serializzazione? Sulla base della risposta, non sembra, quindi, devono definire i tipi in un assembly ... Che dolore - volevo creare un'intera soluzione basata su script per un problema senza richiedere assemblaggi et al. Grazie. – Ariel

+1

"c'è un modo semplice, come XmlSerializer, per serializzare i tipi in PowerShell" Import/Export-CliXml dovrebbe funzionare bene. – stej

risposta

9

Certo, è possibile definire un tipo in Powershell e usarlo in serializzazione.

Il primo passaggio è la definizione di un nuovo tipo. In Powershell 2.0, è possibile farlo tramite chiamando il numero Add-Type. Una volta ottenuto l'assembly compilato dinamicamente contenente il nuovo tipo, è possibile utilizzare liberamente il tipo, come qualsiasi altro tipo .NET.

Fase 2 è usare solo la classe XmlSerializer, come si farebbe normalmente - basta tradurre il codice C# che hai fornito nella domanda di PowerShell.

Il seguente esempio illustra. Definisce un tipo semplice, quindi deserializza da una stringa XML per creare una nuova istanza di quel tipo. Quindi stampa i valori delle proprietà su quell'istanza de-serializzata.

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

Grazie a Keith Hill per indicare Add-Type out.


in PowerShell 1.0, si può fare qualcosa di simile con un po 'di codice personalizzato (vedi 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 
    } 
} 
} 

Usando questa funzione, l'applicazione diventa:

$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

Grazie per la risposta! Non ho ancora provato questo, ma l'unica idea di compilare dinamicamente i tipi riempie tutto ciò che stavo cercando di completare la mia domanda. Grazie! – Ariel

+0

È necessario controllare il cmdlet Add-Type in PowerShell 2.0, in particolare il parametro TypeDefinition. Semplificherebbe * notevolmente * il tuo script sopra. :-) –

+0

Non avevo realizzato PowerShell 2.0! grazie, lo controllerò. – Cheeso

Problemi correlati