XML(反)序列化无效字符串在c#中不一致?

Posted

技术标签:

【中文标题】XML(反)序列化无效字符串在c#中不一致?【英文标题】:XML (de)serialization invalid string inconsistent in c#? 【发布时间】:2012-11-07 03:46:45 【问题描述】:

在 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 只不过是一个包含一个子元素(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: '♂', 十六进制值 0x0B,是无效字符。第 3 行,位置 12。

序列化的 XML 文件在第 3 行包含以下内容:

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

我知道 \v -> & # xB;是一个非法字符,但是为什么 XMLSerialize 允许它被序列化(没有错误)?我发现它与 .NET 不一致,它允许我毫无问题地序列化某些东西,只是发现我无法反序列化它。

是否有解决方案,XMLSerializer 在序列化之前自动删除非法字符,或者我可以指示反序列化忽略非法字符吗?

目前我确实通过将文件内容作为字符串读取,“手动”替换非法字符然后反序列化它来解决它......但我发现这是一个丑陋的黑客/解决方法。

【问题讨论】:

你可能需要检查一下***.com/questions/4899872/… 【参考方案1】:

1.

你可以设置XmlWriterSettingsCheckCharacters属性来避免写入非法字符。(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); 

【讨论】:

以上是关于XML(反)序列化无效字符串在c#中不一致?的主要内容,如果未能解决你的问题,请参考以下文章

基于 BERT 的 NER 模型在反序列化时给出不一致的预测

在 C# 中使用换行符对字符串元素进行 XML 反序列化

反序列化失败:base-64 字符数组的长度无效

在 C# 中使用德文小数分隔符对双精度值进行 XML 反序列化

将 Web 服务 API 中的 XML 字符串反序列化为 C# 对象

C# XML序列化和反序列化(XmlSerializer)