以UTF-16编码格式反序列化xml文件时出现XmlException

时间:2014-08-14 00:38:22

标签: c# xml encoding xmlserializer xmlexception

使用C#的XmlSerializer。

在反序列化给定文件夹中的所有xml文件的过程中,我看到了XmlException "There is an error in XML document (0, 0)".和InnerException是"There is no Unicode byte order mark. Cannot switch to Unicode".

目录中的所有xmls都是“UTF-16”编码的。唯一不同的是,一些xml文件缺少在反序列化时使用的对象类中定义的元素。

例如,考虑我的文件夹中有3种不同类型的xmls:

file1.xml

<?xml version="1.0" encoding="utf-16"?>
<ns0:PaymentStatus xmlns:ns0="http://my.PaymentStatus">
</ns0:PaymentStatus>

file2.xml

<?xml version="1.0" encoding="utf-16"?>
<ns0:PaymentStatus xmlns:ns0="http://my.PaymentStatus">
<PaymentStatus2 RowNum="1" FeedID="38" />
</ns0:PaymentStatus>

file3.xml

<?xml version="1.0" encoding="utf-16"?>
<ns0:PaymentStatus xmlns:ns0="http://my.PaymentStatus">
<PaymentStatus2 RowNum="1" FeedID="38" />
<PaymentStatus2 RowNum="2" FeedID="39" Amt="26.0000" />
</ns0:PaymentStatus>

我有一个代表上面的xml的类:

[XmlTypeAttribute(AnonymousType = true, Namespace = "http://my.PaymentStatus")]
[XmlRootAttribute("PaymentStatus", Namespace = "http://http://my.PaymentStatus", IsNullable = true)]
public class PaymentStatus
{

    private PaymentStatus2[] PaymentStatus2Field;

    [XmlElementAttribute("PaymentStatus2", Namespace = "")]
    public PaymentStatus2[] PaymentStatus2 { get; set; }

    public PaymentStatus()
    {
        PaymentStatus2Field = null;
    }
}

[XmlTypeAttribute(AnonymousType = true)]
[XmlRootAttribute(Namespace = "", IsNullable = true)]

public class PaymentStatus2
{

    private byte rowNumField;
    private byte feedIDField;
    private decimal AmtField;
    public PaymentStatus2()
    {
        rowNumField = 0;
        feedIDField = 0;
        AmtField = 0.0M;
    }

    [XmlAttributeAttribute()]
    public byte RowNum { get; set; }

    [XmlAttributeAttribute()]
    public byte FeedID { get; set; }
    [System.Xml.Serialization.XmlAttributeAttribute()]
    public decimal Amt { get; set; }
}

以下代码段对我进行反序列化:

foreach (string f in filePaths)
{
  XmlSerializer xsw = new XmlSerializer(typeof(PaymentStatus));
  FileStream fs = new FileStream(f, FileMode.Open);
  PaymentStatus config = (PaymentStatus)xsw.Deserialize(new XmlTextReader(fs));
}

我错过了什么吗?它必须是编码格式的东西,因为当我尝试用UTF-8手动替换UTF-16时,它似乎工作正常。

3 个答案:

答案 0 :(得分:4)

我今天遇到了与第三方网络服务一样的错误。

我通过使用StreamReader并设置编码来遵循Alexei的建议。之后,StreamReader可以在XmlTextReader构造函数中使用。这是使用原始问题中的代码实现的:

foreach (string f in filePaths)
{
  XmlSerializer xsw = new XmlSerializer(typeof(PaymentStatus));
  FileStream fs = new FileStream(f, FileMode.Open);
  StreamReader stream = new StreamReader(fs, Encoding.UTF8);
  PaymentStatus config = (PaymentStatus)xsw.Deserialize(new XmlTextReader(stream));
}

答案 1 :(得分:1)

最有可能encoding="utf-16"与编码无关的XML存储因此导致解析器无法以UTF-16文本的形式读取流。

因为你有评论改为&#34;编码&#34;参数到&#34; utf-8&#34;让你阅读我认为文件实际上是UTF8的文本。您可以通过在所选编辑器(即Visual Studio)中打开文件作为二进制而不是文本来轻松验证。

最有可能导致这种不匹配的原因是将XML保存为writer.Write(document.OuterXml)(首先获取字符串表示,然后使用#34; utf-16&#34;,而不是使用utf-8编码通过写入字符串进行流式处理默认值)。

可能的解决方法 - 以对称编写代码的方式读取XML - 读取为字符串,而不是从字符串加载XML。

正确修复 - 确保正确存储XML。

答案 2 :(得分:0)

我不知道这是否是最佳方式,但如果我的输入流不包含BOM,我只需使用XDocument来处理不同的编码......例如:

public static T DeserializeFromString<T>(String xml) where T : class
    {
        try
        {
            var xDoc = XDocument.Parse(xml);
            using (var xmlReader = xDoc.Root.CreateReader())
            {
                return new XmlSerializer(typeof(T)).Deserialize(xmlReader) as T;
            }
        }
        catch ()
        {
            return default(T);
        }
    }

当然你可能想要抛弃任何异常,但是在我复制的代码的情况下,我不需要知道它是否或为什么失败...所以我只是吃了异常。