C # XML-сериализация - ведущие знаки вопроса - PullRequest
8 голосов
/ 19 марта 2009

Задача

Используя некоторые примеры, которые я нашел в Интернете здесь , я написал несколько методов сериализации XML.

  • Метод 1: Сериализует объект и возвращает: (a) тип, (b) строку xml
  • Метод 2: Принимает (a) и (b) выше и возвращает вам Объект.

Я заметил, что строка xml из Method1 содержит начальный символ '?'. Кажется, это нормально при использовании Method2 для реконструкции объекта.

Но, проводя какое-то тестирование в приложении, иногда мы получали «???» вместо. Это заставило Method2 выдать исключение при попытке восстановить Объект. «Объект» в этом случае был просто int.

System.InvalidOperationException не было обработано Сообщение = «В документе XML есть ошибка (1, 1).» Источник = "System.Xml" Трассировки стека: в System.Xml.Serialization.XmlSerializer.Deserialize (события XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents) в System.Xml.Serialization.XmlSerializer.Deserialize (XmlReader xmlReader, String encodingStyle) в System.Xml.Serialization.XmlSerializer.Deserialize (Поток потока) в XMLSerialization.Program.DeserializeXmlStringToObject (String xmlString, String objectType) в C: \ Documents and Settings \ ... Проекты \ XMLSerialization \ Program.cs: строка 96 в XMLSerialization.Program.Main (String [] args) в C: \ Documents and Settings \ ... Проекты \ XMLSerialization \ Program.cs: строка 49

Кто-нибудь сможет пролить свет на то, что может быть причиной этого?

Пример кода

Вот пример кода из мини-тестера, который я написал во время кодирования, который работает как консольное приложение VS. Он покажет вам строку XML. Вы также можете раскомментировать регионы, чтобы добавить дополнительные ведущие '??' воспроизвести исключение.



using System;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;

namespace XMLSerialization
{
    class Program
    {
        static void Main(string[] args)
        {
            // deserialize to string
            #region int
            object inObj = 5;
            #endregion

            #region string
            //object inObj = "Testing123";
            #endregion

            #region list
            //List inObj = new List();
            //inObj.Add("0:25");
            //inObj.Add("1:26");
            #endregion

            string[] stringArray = SerializeObjectToXmlString(inObj);

            #region include leading ???
            //int indexOfBracket = stringArray[0].IndexOf('<');
            //stringArray[0] = "??" + stringArray[0];
            #endregion

            #region strip out leading ???
            //int indexOfBracket = stringArray[0].IndexOf('<');
            //string trimmedString = stringArray[0].Substring(indexOfBracket);
            //stringArray[0] = trimmedString;
            #endregion

            Console.WriteLine("Input");
            Console.WriteLine("-----");
            Console.WriteLine("Object Type: " + stringArray[1]);
            Console.WriteLine();
            Console.WriteLine("XML String: " + Environment.NewLine + stringArray[0]);
            Console.WriteLine(String.Empty);

             // serialize back to object
            object outObj = DeserializeXmlStringToObject(stringArray[0], stringArray[1]);

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

            #region int
            Console.WriteLine("Object: " + (int)outObj);
            #endregion

            #region string
            //Console.WriteLine("Object: " + (string)outObj);
            #endregion

            #region list
            //string[] tempArray;
            //List list = (List)outObj;

            //foreach (string pair in list)
            //{
            //    tempArray = pair.Split(':');
            //    Console.WriteLine(String.Format("Key:{0} Value:{1}", tempArray[0], tempArray[1]));
            //}
            #endregion

            Console.Read();
        }

        private static string[] SerializeObjectToXmlString(object obj)
        {
            XmlTextWriter writer = new XmlTextWriter(new MemoryStream(), Encoding.UTF8);
            writer.Formatting = Formatting.Indented;
            XmlSerializer serializer = new XmlSerializer(obj.GetType());
            serializer.Serialize(writer, obj);

            MemoryStream stream = (MemoryStream)writer.BaseStream;
            string xmlString = UTF8ByteArrayToString(stream.ToArray());

            string objectType = obj.GetType().FullName;

            return new string[]{xmlString, objectType};
        }

        private static object DeserializeXmlStringToObject(string xmlString, string objectType)
        {
            MemoryStream stream = new MemoryStream(StringToUTF8ByteArray(xmlString));
            XmlSerializer serializer = new XmlSerializer(Type.GetType(objectType));

            object obj = serializer.Deserialize(stream);

            return obj;
        }

        private static string UTF8ByteArrayToString(Byte[] characters)
        {
            UTF8Encoding encoding = new UTF8Encoding();
            return encoding.GetString(characters);
        }

        private static byte[] StringToUTF8ByteArray(String pXmlString)
        {
            UTF8Encoding encoding = new UTF8Encoding();
            return encoding.GetBytes(pXmlString);
        } 


    }
}


Ответы [ 2 ]

9 голосов
/ 19 марта 2009

Когда я сталкивался с этим раньше, это обычно было связано с кодированием. Я бы попробовал указать кодировку при сериализации вашего объекта. Попробуйте использовать следующий код. Кроме того, есть ли какая-то конкретная причина, по которой вам нужно возвращать массив string[]? Я изменил ваши методы для использования обобщений, поэтому вам не нужно указывать тип.

private static string SerializeObjectToXmlString<T>(T obj)
{
    XmlSerializer xmls = new XmlSerializer(typeof(T));
    using (MemoryStream ms = new MemoryStream())
    {
        XmlWriterSettings settings = new XmlWriterSettings();
        settings.Encoding = Encoding.UTF8;
        settings.Indent = true;
        settings.IndentChars = "\t";
        settings.NewLineChars = Environment.NewLine;
        settings.ConformanceLevel = ConformanceLevel.Document;

        using (XmlWriter writer = XmlTextWriter.Create(ms, settings))
        {
            xmls.Serialize(writer, obj);
        }

        string xml = Encoding.UTF8.GetString(ms.ToArray());
        return xml;
    }
}

private static T DeserializeXmlStringToObject <T>(string xmlString)
{
    XmlSerializer xmls = new XmlSerializer(typeof(T));

    using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(xmlString)))
    {
        return (T)xmls.Deserialize(ms);
    }
}

Если у вас все еще есть проблемы, попробуйте использовать Encoding.ASCII в своем коде везде, где вы видите Encoding.UTF8, если у вас нет особых причин для использования UTF8. Я не уверен в причине, но я видел кодировку UTF8, вызывающую эту проблему в некоторых случаях при сериализации.

3 голосов
/ 19 марта 2009

Это символ спецификации. Вы можете удалить его

if (xmlString.Length > 0 && xmlString[0] != '<')
{
    xmlString = xmlString.Substring(1, xmlString.Length - 1);
}

Или используйте UTF32 для сериализации

using (StringWriter writer = new StringWriter(CultureInfo.InvariantCulture))
{
    serializer.Serialize(writer, instance);
    result = writer.ToString();
}

И десериализовать

object result;
using (StringReader reader = new StringReader(instance))
{
    result = serializer.Deserialize(reader);
}

Если вы используете этот код только внутри .Net приложений, использующих UTF32, не создаст проблем, так как это кодировка по умолчанию для всего внутри .Net

...