zoukankan      html  css  js  c++  java
  • C# UTF8的BOM导致XML序列化与反序列化报错:Data at the root level is invalid. Line 1, position 1.

      最近在写一个xml序列化及反序列化实现时碰到个问题,大致类似下面的代码:  

        class Program
        {
            static void Main1(string[] args)
            {
                var test = new Test() { A = "test" };
    
                var ms = new MemoryStream();
                using (XmlWriter xmlWriter = XmlWriter.Create(ms, new XmlWriterSettings() { Encoding = Encoding.UTF8, OmitXmlDeclaration = true }))//OmitXmlDeclaration表示是否需要xml申明头
                {
                    XmlSerializer xz = new XmlSerializer(typeof(Test));
                    XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
                    ns.Add(string.Empty, string.Empty);//去掉xmlns属性
                    xz.Serialize(xmlWriter, test, ns);
    
                    var xml = Encoding.UTF8.GetString(ms.ToArray());//得到xml
                    XmlDocument xmlDocument = new XmlDocument();
                    xmlDocument.LoadXml(xml);//报错:Data at the root level is invalid. Line 1, position 1.
                }
            }
        }
        public class Test
        {
            public string A { get; set; }
        }

      上面代码序列化出来的那个xml变量值是:<Test><A>test</A></Test>,但是在XMLDocument.LoadXml(xml)方法报错:Data at the root level is invalid. Line 1, position 1.

      于是我将xml变量的值在调试状态下复制出来,接着在Main方法中写了下面的测试代码:   

        static void Main(string[] args)
        {
            string str1 = "<Test><A>test</A></Test>";
            string str2 = "<Test><A>test</A></Test>";
            Console.WriteLine("str1 == str2:" + (str1 == str2));//str1 == str2:False
            Console.WriteLine("str1.Length=" + str1.Length);//str1.Length=24
            Console.WriteLine("str2.Length=" + str2.Length);//str2.Length=25
            Console.ReadKey();
        }

      因为一直没遇到过这个问题,所以感觉很奇怪,然后查了一些资料,最后发现是UTF-8的BOM在作怪.

      什么是BOM?BOM的全称叫做" Byte Order Mark",UTF-8编码数据会在文件开头使用“EF BB BF”这三个字节表示BOM,而BOM的存在是为了区别字节序,存在BOM表示采用小端法,即低位在前边。

      对于UTF-8而言,因为它的编码单元就是字节,所以是没有字节序问题,但是UTF-16和UTF-32的编码单元分别是16-bit和32-bit,就对字节序要求了。

      比如,"u4FA5"对应中文的“侥“,"u5AF4"对应中文的“嫴“,如果两台不同的字节序的客户端A,B,A给B发送数据"u4FA5",B可能就会认为是“嫴“,这就出错了。

      UTF-8虽然没有字节序问题,但为了兼容,UTF-8也会加上BOM。

      其实,如果注意一下,上面的例子中,str2的第一个字符是一个空字符,而不是<,而我们要解决UTF-8的BOM导致的数据问题时,只需要使用UTF8Encoding类传入false参数即可,例如上面的例子:  

        class Program
        {
            static void Main(string[] args)
            {
                var test = new Test() { A = "test" };
    
                var ms = new MemoryStream();
                using (XmlWriter xmlWriter = XmlWriter.Create(ms, new XmlWriterSettings() { Encoding = new UTF8Encoding(false), OmitXmlDeclaration = true }))//使用UTF8Encoding
                {
                    XmlSerializer xz = new XmlSerializer(typeof(Test));
                    XmlSerializerNamespaces ns = new XmlSerializerNamespaces(); 
                    ns.Add(string.Empty, string.Empty);//去掉xmlns属性
                    xz.Serialize(xmlWriter, test, ns);
    
                    var xml = Encoding.UTF8.GetString(ms.ToArray());//得到xml,不含BOM
                    XmlDocument xmlDocument = new XmlDocument();
                    xmlDocument.LoadXml(xml);//不报错报错
                }
            }
        }
        public class Test
        {
            public string A { get; set; }
        }
    一个专注于.NetCore的技术小白
  • 相关阅读:
    git 使用命令
    Mac上部署Jenkins,用git插件更新项目代码时报错的记录
    pycharm找不到本项目中的其他包或模块
    小米8线刷pixel experience全过程记录
    python环境清理
    怎么实现无遮罩屏蔽某些按钮的点击事件
    ios 上 WebCamTexture尺寸是16X16
    关于月份拆分
    关于const let的使用
    关于promise,const函数的使用
  • 原文地址:https://www.cnblogs.com/shanfeng1000/p/14465030.html
Copyright © 2011-2022 走看看