Функциональность XmlSerializer в PowerShell?

Существует ли способ усилить функциональность класса XmlSerializer.NET в PowerShell?

Строго говоря, способность к легко de/serialize.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? Я имею к чтению-записи некоторый .xml's от PS и усилил бы такую функциональность прежде вручную сделать его.

8
задан Ariel 5 May 2010 в 19:11
поделиться

1 ответ

Конечно, вы можете определить тип в 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: компиляция кода c#, хранящегося в строке).

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)
10
ответ дан 5 December 2019 в 17:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: