【问题标题】:How do I have to change this XML string so that XDocument.Parse reads it in?如何更改此 XML 字符串以便 XDocument.Parse 读取它?
【发布时间】:2011-01-05 10:52:59
【问题描述】:

在下面的代码中,我将一个对象序列化成一个 XML 字符串

但是当我尝试使用 XDocument.Parse 将这个 XML 字符串 读入 XDocument 时,它给了我这个错误

根级别的数据无效。

XML 是:

<?xml version="1.0" encoding="utf-8"?>
<Customer xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <Id>1</Id>
   <FirstName>Jim</FirstName>
   <LastName>Jones</LastName>
   <ZipCode>23434</ZipCode>
</Customer>

更新:这是十六进制:

![alt text][1] Mod 编辑 - 禁用超链接:指向恶意软件的链接

我必须对这个 XML 执行什么操作才能使它正确地读入 XDocument?

using System;
using System.Collections.Generic;
using System.Xml.Serialization;
using System.IO;
using System.Xml;
using System.Text;
using System.Xml.Linq;

namespace TestSerialize2342
{
    class Program
    {
        static void Main(string[] args)
        {
            List<Customer> customers = Customer.GetCustomers();

            Console.WriteLine("--- Serializing ------------------");

            foreach (var customer in customers)
            {
                Console.WriteLine("Serializing " + customer.GetFullName() + "...");
                string xml = XmlHelpers.SerializeObject<Customer>(customer);

                XDocument xdoc = XDocument.Parse(xml);

            }

            Console.ReadLine();
        }

    }

    public static class StringHelpers
    {
        public static String UTF8ByteArrayToString(Byte[] characters)
        {
            UTF8Encoding encoding = new UTF8Encoding();
            String constructedString = encoding.GetString(characters);
            return (constructedString);
        }

        public static Byte[] StringToUTF8ByteArray(String pXmlString)
        {
            UTF8Encoding encoding = new UTF8Encoding();
            Byte[] byteArray = encoding.GetBytes(pXmlString);
            return byteArray;
        } 
    }

    public static class XmlHelpers
    {
        public static string SerializeObject<T>(object o)
        {
            MemoryStream ms = new MemoryStream();
            XmlSerializer xs = new XmlSerializer(typeof(T));
            XmlTextWriter xtw = new XmlTextWriter(ms, Encoding.UTF8);
            xs.Serialize(xtw, o);
            ms = (MemoryStream)xtw.BaseStream;
            return StringHelpers.UTF8ByteArrayToString(ms.ToArray());
        }

        public static T DeserializeObject<T>(string xml)
        {
            XmlSerializer xs = new XmlSerializer(typeof(T));
            MemoryStream ms = new MemoryStream(StringHelpers.StringToUTF8ByteArray(xml));
            XmlTextWriter xtw = new XmlTextWriter(ms, Encoding.UTF8);
            return (T)xs.Deserialize(ms);
        }
    }

    public class Customer
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Street { get; set; }
        public string Location { get; set; }
        public string ZipCode { get; set; }

        private int internalValue = 23;

        public static List<Customer> GetCustomers()
        {
            List<Customer> customers = new List<Customer>();
            customers.Add(new Customer { Id = 1, FirstName = "Jim", LastName = "Jones", ZipCode = "23434" });
            customers.Add(new Customer { Id = 2, FirstName = "Joe", LastName = "Adams", ZipCode = "12312" });
            customers.Add(new Customer { Id = 3, FirstName = "Jack", LastName = "Johnson", ZipCode = "23111" });
            customers.Add(new Customer { Id = 4, FirstName = "Angie", LastName = "Reckar", ZipCode = "54343" });
            customers.Add(new Customer { Id = 5, FirstName = "Henry", LastName = "Anderson", ZipCode = "16623" });
            return customers;
        }

        public string GetFullName()
        {
            return FirstName + " " + LastName + "(" + internalValue + ")";
        }

    }
}

回答:

感谢 Andras,GetPreamble() 修复了它,所以对于其他处理这个问题的人来说,这里有一个小方法来清理你的 BOM 的 XML:

public static string RemoveUtf8ByteOrderMark(string xml)
{
    string byteOrderMarkUtf8 = Encoding.UTF8.GetString(Encoding.UTF8.GetPreamble());
    if (xml.StartsWith(byteOrderMarkUtf8))
    {
        xml = xml.Remove(0, byteOrderMarkUtf8.Length);
    }
    return xml;
}

【问题讨论】:

  • 该 XML 没有任何问题。您确定是同一个 XML 导致了异常吗?
  • 根级别的无效数据,第 1 行,第 1 个字符。当我将文本复制到 NotePad++ 时,第一个字符是“?”在其他编辑器中,一些控制字符...
  • 然后你在剪切和粘贴过程中丢失了打开的“
  • 它是字节顺序标记或类似的 - 但我不认识那个!
  • 我想我有一个更优雅的解决方案,看看我的答案。

标签: c# xml xml-serialization linq-to-xml


【解决方案1】:

您可以通过使用StreamReaderMemoryStream 中的数据转换为字符串来解决您的问题:

public static string SerializeObject<T>(object o)
{
    using (MemoryStream ms = new MemoryStream())
    {
        XmlSerializer xs = new XmlSerializer(typeof(T));
        using (XmlWriter xtw = XmlWriter.Create(ms))
        {
            xs.Serialize(xtw, o);
            xtw.Flush();
            ms.Seek(0, SeekOrigin.Begin);
            using (StreamReader reader = new StreamReader(ms))
            {
                return reader.ReadToEnd();
            }
        }
    }
}

【讨论】:

  • -1:XmlTextWriter 已弃用。请改用XmlWriter.Create
  • @John:编译器没有发布关于 XmlTextWriter 被弃用的信息。我知道XmlWriter.Create 的建议,但我不想为了解决问题而过多地更改 OP 代码。尽管如此,还是更新了我的代码示例以遵循建议。
【解决方案2】:

以上所有内容都是正确的,您应该使用以下代码代替您的代码来跳过 BOM:

 public static string SerializeObject<T>(object o)
        {
            MemoryStream ms = new MemoryStream();
            XmlSerializer xs = new XmlSerializer(typeof(T));
            //here is my code
            UTF8Encoding encoding = new UTF8Encoding(false);
            XmlTextWriter xtw = new XmlTextWriter(ms, encoding);
            //XmlTextWriter xtw = new XmlTextWriter(ms, Encoding.UTF8);
            xs.Serialize(xtw, o);
            ms = (MemoryStream)xtw.BaseStream;
            return StringHelpers.UTF8ByteArrayToString(ms.ToArray());
       }

通过在构造函数中指定 false 你说“没有提供 BOM”。享受! =)

【讨论】:

  • -1,-1,-1:您需要在 MemoryStreamXmlWriter 周围放置 using 块。您不需要使用自 .NET 2.0 以来已弃用的 XmlTextWriter - 请改用 XmlWriter.Createo 参数应该是T 类型;除其他外,这将允许您的调用者不指定 - 它通常由参数的类型暗示。
  • 同意,但这是原始代码的副本,仅进行了一次修改,因此我的目标不是审查它并找出漏洞和设计问题。如果您尝试阅读此讨论,您可能会注意到我已经解决了我被要求的问题。所以把你的“-1”拿出来,先生。
【解决方案3】:

这是因为数据在流的开头包含 unicode 或 utf8 BOM marks

您需要跳过流中的任何字节顺序标记 - 您可以通过 System.Text.Encoding.GetPreamble() 方法识别这些。

【讨论】:

  • 您在记事本中创建 XML 文件时经常遇到此问题。 VS 有时也可以添加它们。
  • 使用 GetPreamble() 是为了解决后果而不是推理。请看我的回答。
  • 是的,这是一个很好的答案 - 如果编码始终是 UTF8,它就可以工作。但是,通过使用 GetPreamble 方法,您可以自动检测文件的编码,这意味着您不仅限于一个文件。选择后,您可以调整代码示例以适应任何编码。
  • 同意,但是为什么你应该有更复杂的解决方案来预见未来永远不需要的编码。如果您目前只需要 UTF8,我不建议这样做。雅格尼。
  • 真的没那么难也不复杂,我在一个常用的参考库中有一个扩展方法,我用的大概是10-15行代码。我知道你在说什么,而且我原则上同意,但有时完整的解决方案是值得的,尤其是在它不会增加任何复杂性的情况下。
猜你喜欢
  • 2011-11-03
  • 1970-01-01
  • 2021-11-23
  • 2021-05-13
  • 1970-01-01
  • 2019-10-02
  • 2019-05-27
  • 1970-01-01
  • 2013-10-30
相关资源
最近更新 更多