【问题标题】:C# Xml Serialization & DeserializationC# Xml 序列化和反序列化
【发布时间】:2012-02-02 01:47:30
【问题描述】:

我正在尝试序列化对象并将其保存到 Sql server 2008 xml 字段中。我还有一些反序列化代码可以重新水合对象。我能够将对象序列化并保存到数据库中,但会出现“缺少根元素”异常。

[XmlRoot("Patient")]
public class PatientXml
{
    private AddressXml _address = null;
    private EmergencyContactXml _emergencyContact = null;
    private PersonalXml _personal = null;

    [XmlElement]
    public PersonalXml Personal
    {
        get { return _personal; }
        set { _personal = value; }
    }

    [XmlElement]
    public AddressXml Address
    {
        get { return _address; }
        set { _address = value; }
    }

    [XmlElement]
    public EmergencyContactXml EmergencyContact
    {
        get { return _emergencyContact; }
        set { _emergencyContact = value; }
    }

    public PatientXml(){}
    public PatientXml(Patient patient)
    {
        _address = new AddressXml(patient.Address);
        _emergencyContact = new EmergencyContactXml(patient.EmergencyInfo);
        _personal = new PersonalXml(patient);
    }
}

public class PersonalXml
{
    private string _firstName = string.Empty, _lastName = string.Empty, _dateOfBirth = string.Empty, _phone = string.Empty;

    [XmlAttribute]
    public string FirstName
    {
        get { return _firstName; }
        set { _firstName = value; }
    }

    [XmlAttribute]
    public string LastName
    {
        get { return _lastName; }
        set { _lastName = value; }
    }

    [XmlAttribute]
    public string DateOfBirth
    {
        get { return _dateOfBirth; }
        set { _dateOfBirth = value; }
    }

    [XmlAttribute]
    public string Phone
    {
        get { return _phone; }
        set { _phone = value; }
    }

    public PersonalXml(){}
    public PersonalXml(Patient patient)
    {
        _firstName = patient.FirstName;
        _lastName = patient.LastName;
        _dateOfBirth = patient.DateOfBirth.ToShortDateString();
        _phone = patient.Phone;
    }
}

public class AddressXml
{
    private string _address1 = string.Empty, _address2 = string.Empty, _city = string.Empty, _state = string.Empty, _zip = string.Empty;

    [XmlAttribute]
    public string Address1
    {
        get { return _address1; }
        set { _address1 = value; }
    }

    [XmlAttribute]
    public string Address2
    {
        get { return _address2; }
        set { _address2 = value; }
    }

    [XmlAttribute]
    public string City
    {
        get { return _city; }
        set { _city = value; }
    }

    [XmlAttribute]
    public string State
    {
        get { return _state; }
        set { _state = value; }
    }

    [XmlAttribute]
    public string Zip
    {
        get { return _zip; }
        set { _zip = value; }
    }

    public AddressXml(){}
    public AddressXml(Address address)
    {
        _address1 = address.Address1;
        _address2 = address.Address2;
        _city = address.City;
        _state = address.State;
        _zip = address.ZipCode;
    }
}

public class EmergencyContactXml
{
    private string _name = string.Empty, _phone = string.Empty, _relationship = string.Empty;

    [XmlAttribute]
    public string Name
    {
        get { return _name; }
        set { _name = value; }
    }

    [XmlAttribute]
    public string Phone
    {
        get { return _phone; }
        set { _phone = value; }
    }

    [XmlAttribute]
    public string Relationship
    {
        get { return _relationship; }
        set { _relationship = value; }
    }

    public EmergencyContactXml(){}
    public EmergencyContactXml(EmergencyContact contact)
    {
        _name = contact.ContactName;
        _phone = contact.Phone;
        _relationship = contact.Relationship;
    }
}

序列化 Xml 输出:

<Patient 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Personal FirstName="Test" LastName="User 1" DateOfBirth="3/13/1966" Phone="6304449866" />
    <Address Address1="123 Some St" City="Bartlett" State="CT" Zip="60111" />
    <EmergencyContact Name="Dr Chanduwarthana" Phone="6309769484" Relationship="Father" />
</Patient>

序列化和反序列化代码:

public static class XmlSerializer
{
    public static string Serialize<T>(T item)
    {
        MemoryStream memStream = new MemoryStream();
        using (XmlTextWriter textWriter = new XmlTextWriter(memStream, Encoding.Unicode))
        {
            System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(T));
            serializer.Serialize(textWriter, item);

            memStream = textWriter.BaseStream as MemoryStream;
        }
        if (memStream != null)
            return Encoding.Unicode.GetString(memStream.ToArray());
        else
            return null;
    }

    public static T Deserialize<T>(string xmlString)
    {
        if (string.IsNullOrWhiteSpace(xmlString))
            return default(T);

        using (MemoryStream memStream = new MemoryStream())
        {
            using (XmlTextWriter textWriter = new XmlTextWriter(memStream, Encoding.Unicode))
            {
                memStream.Position = 0;
                System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(T));
                return (T)serializer.Deserialize(memStream);
            }
        }
    }
}

【问题讨论】:

    标签: c# c#-4.0 c#-3.0 xml-serialization c#-2.0


    【解决方案1】:

    在您的反序列化代码中,您正在创建一个 MemoryStream 和 XmlTextWriter,但您没有给它提供要反序列化的字符串。

    using (MemoryStream memStream = new MemoryStream())
    {
        using (XmlTextWriter textWriter = new XmlTextWriter(memStream, Encoding.Unicode))
        {
            // Omitted
        }
    }
    

    您可以将字节传递到内存流并完全取消 XmlTextWriter。

    using (MemoryStream memStream = new MemoryStream(Encoding.Unicode.GetBytes(xmlString)))
    {
        System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(T));
        return (T)serializer.Deserialize(memStream);
    }
    

    【讨论】:

    • 成功了!!只是好奇...... TextWriter 发生了什么?
    • @KP。反序列化不需要 XmlTextWriter,因为您没有构建任何 XML。在这种情况下,它是通过对 MemoryStream 的引用创建的,并被指示使用 Unicode,但在创建之外没有被引用。我还注意到序列化代码中的 MemoryStream 没有被释放。您可能应该考虑修改代码以将其包装在 using 块中。
    【解决方案2】:

    看起来您已经掌握了序列化为 XML 的方法,因此请采纳我的建议,将 XML 存储在字符串字段(varchar、nvarchar、text、ntext)中,而不是专门的字段中。

    如果你做了那个小开关,你就可以开始了……不需要进一步的修改。

    XML 字段需要经过验证,而且有不少令人头疼的问题,如果您的应用程序只是该字段的生产者和消费者,那么您不妨走这条捷径。 SQL2008(甚至是 2005)足够强大,可以补偿您通过编译 xml 字段可能节省的资源。

    然而, 我会稍微优化你的代码,看起来你写的代码比你必须写的多。 例如,您不再需要创建一个私有字段来存储您的财产中的数据,例如:

    public PersonalXml Personal
    {
        get { return _personal; }
        set { _personal = value; }
    }
    

    如果你这样写就可以了:

        public PersonalXml Personal { get ; set ; }
    

    你可以减掉更多的脂肪......

    【讨论】:

    • 我认为sql server 2008中的xml字段对xml查询的优化。或者我也可以使用其他字段,如 varchar、nvarchar 等?
    【解决方案3】:

    我相信你需要添加XML头:

    <?xml version="1.0" encoding="utf-8" ?>
    

    您可以修改您的序列化方法以接受一个可选参数,该参数将导致添加:

    public static string Serialize<T>(T item, bool includeHeader = false)
    {
        MemoryStream memStream = new MemoryStream();
        using (XmlTextWriter textWriter = new XmlTextWriter(memStream, Encoding.Unicode))
        {
            System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(T));
            serializer.Serialize(textWriter, item);
    
            memStream = textWriter.BaseStream as MemoryStream;
        }
        if (memStream != null)
            if (includeHeader)
            {
                return @"<?xml version=""1.0"" encoding=""utf-8"" ?>" + Environment.NewLine + Encoding.Unicode.GetString(memStream.ToArray());
            }
            else
            {
                return Encoding.Unicode.GetString(memStream.ToArray());
            }
        else
            return null;
    }
    

    【讨论】:

    • 我该怎么做? XML 代码是在我序列化对象时生成的。
    • 你应该可以将它添加到序列化方法的输出中。
    猜你喜欢
    • 2011-05-12
    • 2011-06-28
    • 1970-01-01
    • 2010-11-25
    • 1970-01-01
    • 2012-09-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多