2012-01-04 189 views
11

我想序列化一个对象&将它保存到Sql server 2008 xml字段中。我也有一些反序列化的代码可以重新保存对象。我能够序列化&保存对象到数据库中,但得到“根元素丢失”异常。C#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> 

Serization &反序列化代码:

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); 
      } 
     } 
    } 
} 

回答

11

在你的反串行化代码,你正在创建一个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); 
} 
+1

工作!只是好奇...... TextWriter发生了什么? – Skadoosh 2012-01-04 15:19:06

+2

@KP。由于您不构建任何XML,所以XmlTextWriter对于反序列化不是必需的。在这种情况下,它是通过引用MemoryStream创建的,并指示使用Unicode,但在创建之后未引用它。 我还注意到,序列化代码中的MemoryStream不处理。您应该考虑修改代码以将其包装在使用块中。 – 2012-01-04 16:58:45

0

我相信你需要添加XML头:

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

你库仑d修改您的序列化的方法来接受,将导致此添加一个可选的参数:

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; 
} 
+0

我该怎么做? XML代码是在序列化对象时生成的。 – Skadoosh 2012-01-04 04:56:00

+0

您应该可以将其添加到serialize方法的输出中。 – 2012-01-04 04:58:04

1

看起来你对序列化到XML有一个手柄,所以把我的意见,存储在一个字符串领域的XML(VARCHAR,NVARCHAR,文字,NTEXT),而不是一个专业领域。

如果你做了那么小的开关,你将准备好去...不需要进一步修改。

XML字段需要验证以及一些令人头痛的问题,如果您的应用程序只是该字段的生产者和使用者,那么您也可以采用该快捷方式。 SQL2008(甚至2005)足够强大,可以弥补编译xml字段时可能节省的资源。

但是,我会优化你的代码,看起来像你写的代码比你更多的代码。 例如,您不再需要创建一个私有字段从你的财产存储数据,例如:

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

会工作得很好,如果你这样写:

public PersonalXml Personal { get ; set ; } 

还有更多胖你可以切...

+0

我认为sql server 2008中的xml字段更适合xml查询。或者我也可以使用其他字段,如varchar,nvarchar等? – Skadoosh 2012-01-04 14:58:49