14

C# (.net 4.0 および 4.5 / vs2010 および vs12) で、XMLSerializer を使用して不正な文字を含む文字列を含むオブジェクトをシリアル化すると、エラーはスローされません。ただし、その結果を逆シリアル化すると、「無効な文字」エラーがスローされます。

        // add to XML
        Items items = new Items();
        items.Item = "\v hello world"; // contains "illegal" character \v

        // variables
        System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(Items));
        string tmpFile = Path.GetTempFileName();

        // serialize
        using (FileStream tmpFileStream = new FileStream(tmpFile, FileMode.Open, FileAccess.ReadWrite))
        {
            serializer.Serialize(tmpFileStream, items);
        }
        Console.WriteLine("Success! XML serialized in file " + tmpFile);

        // deserialize
        Items result = null;
        using (FileStream plainTextFile = new FileStream(tmpFile, FileMode.Open, FileAccess.Read))
        {
            result = (Items)serializer.Deserialize(plainTextFile); //FAILS here
        }

        Console.WriteLine(result.Item);

「Items」は、xsd /c Items.xsd によって自動生成される小さなクラスです。Items.xsd は、1 つの子 (Item) を含むルート要素 (Items) にすぎません。

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" attributeFormDefault="unqualified">
    <xs:element name="Items">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="Item" type="xs:string" />
            </xs:sequence>
        </xs:complexType>
    </xs:element>
</xs:schema>

逆シリアル化中にスローされるエラーは

未処理の例外: System.InvalidOperationException: XML ドキュメントにエラーがあります (3、12)。---> System.Xml.XmlException: '♂'、16 進値 0x0B は無効な文字です。行 3、位置 12。

シリアライズされた XML ファイルの 3 行目には、次の内容が含まれています。

<Item>&#xB; hello world</Item>

私は \v -> & # xB; を知っています。は不正な文字ですが、なぜ XMLSerialize で (エラーなしで) シリアライズできるのでしょうか? 問題なくシリアル化でき、逆シリアル化できないことがわかっただけで、.NET とは矛盾していると思います。

XMLSerializer がシリアル化する前に不正な文字を自動的に削除するか、逆シリアル化に不正な文字を無視するように指示することができる解決策はありますか?

現在、ファイルの内容を文字列として読み取り、不正な文字を「手動で」置き換えてから逆シリアル化することで解決しています...しかし、いハック/回避策が見つかりました。

4

1 に答える 1

27

1.

XmlWriterSettingsのプロパティを設定CheckCharactersして、不正な文字を書き込まないようにすることができます (Serializeメソッドは例外をスローします) 。

using (FileStream tmpFileStream = new FileStream(tmpFile, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
    var writer = XmlWriter.Create(tmpFileStream, new XmlWriterSettings() { CheckCharacters = true});
    serializer.Serialize(writer, items);
}

2.

独自の XmlTextWriter を作成して、シリアル化中に不要な文字を除外できます

using (FileStream tmpFileStream = new FileStream(tmpFile, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
    var writer = new MyXmlWriter(tmpFileStream);
    serializer.Serialize(writer, items);
}

public class MyXmlWriter : XmlTextWriter
{
    public MyXmlWriter(Stream s) : base(s, Encoding.UTF8)
    {
    }

    public override void WriteString(string text)
    {
        string newText = String.Join("", text.Where(c => !char.IsControl(c)));
        base.WriteString(newText);
    }
}

3.

独自の XmlTextReader を作成することで、逆シリアル化中に不要な文字を除外できます

using (FileStream plainTextFile = new FileStream(tmpFile, FileMode.Open, FileAccess.Read))
{
    var reader = new MyXmlReader(plainTextFile);
    result = (SomeObject)serializer.Deserialize(reader); 
}

public class MyXmlReader : XmlTextReader
{
    public MyXmlReader(Stream s) : base(s)
    {
    }

    public override string ReadString()
    {
        string text =  base.ReadString();
        string newText = String.Join("", text.Where(c => !char.IsControl(c)));
        return newText;
    }
}

4.

XmlReaderSettingsCheckCharactersプロパティを false に設定できます。デシリアライズがスムーズに動作するようになりました。(あなたは\v戻ってきます。)

using (FileStream plainTextFile = new FileStream(tmpFile, FileMode.Open, FileAccess.Read))
{
    var reader = XmlReader.Create(plainTextFile, new XmlReaderSettings() { CheckCharacters = false });
    result = (SomeObject)serializer.Deserialize(reader); 
}
于 2012-11-19T09:29:23.123 に答える