2010-05-05 10 views
7

¿Hay alguna forma de aprovechar la funcionalidad de la clase XmlSerializer de .NET en PowerShell?¿Funcionalidad de XmlSerializer en PowerShell?

Más específicamente, la capacidad de de/serializar fácilmente tipos .NET en Xml, p.

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

sé que puedo llamar encima de PowerShell, pero hay una manera de evitar la definición de MyType en un ensamblado independiente? Gracias

[Editar] Dado que parece que los tipos .NET no se pueden agregar desde PowerShell, permítanme volver a enfocar mi pregunta: ¿hay alguna manera fácil, como XmlSerializer, para serializar los tipos en PowerShell? Tengo que leer/escribir algunos .xml de PS, y preferiría aprovechar esa funcionalidad antes de hacerlo manualmente.

+0

Y donde le tomaría 'MyType' si no es de una asamblea? NO puede definir tipos en PowerShell directamente; tiene que usar 'Add-Type' para eso. – Joey

+0

Esa es exactamente mi pregunta: ¿hay alguna forma de definir de alguna manera el tipo en PowerShell y luego pasarlo para la serialización? En función de su respuesta, parece que no, por lo tanto, tiene que definir los tipos en un ensamblado ... Qué dolor: quería crear una solución completa basada en scripts para un problema sin requerir ensamblajes et al. Gracias. – Ariel

+1

"hay una manera fácil, como XmlSerializer, de serializar tipos en PowerShell" Import/Export-CliXml debería funcionar bien. – stej

Respuesta

9

Claro, puede definir un tipo dentro de Powershell, y usarlo en la serialización.

El primer paso es definir un nuevo tipo. En Powershell 2.0, puede hacerlo llamando al llamando al Add-Type. Una vez que tenga el ensamblado compilado dinámicamente que contiene el nuevo tipo, puede usar el tipo libremente, como cualquier otro tipo .NET.

El paso 2 es simplemente usar la clase XmlSerializer, como lo haría normalmente, simplemente traduzca el código C# que proporcionó en la pregunta a Powershell.

El siguiente ejemplo ilustra. Define un tipo simple, luego se deserializa de una cadena XML para crear una nueva instancia de ese tipo. Luego imprime los valores de propiedad en esa instancia deserializada.

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

Gracias a Keith Hill para señalar Add-Type out.


En PowerShell 1.0, se puede hacer algo similar con código personalizado (ver 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 
    } 
} 
} 

El uso de esta función, la aplicación se convierte en:

$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

¡Gracias por la respuesta! Todavía no lo he intentado, pero la única idea de compilar dinámicamente los tipos abarca todo lo que estaba tratando de completar en mi pregunta. ¡Gracias! – Ariel

+0

Debe consultar el cmdlet Add-Type en PowerShell 2.0, específicamente el parámetro TypeDefinition. Sería * enormemente * simplificar tu script arriba. :-) –

+0

¡No me di cuenta de que PowerShell 2.0 había salido! gracias, lo comprobaré. – Cheeso

Cuestiones relacionadas