2013-07-15 1 views
8

루트 요소가 다른 여러 XML 파일을 가지고 있지만 동일한 유형의 자식 요소가 있고 다른 루트 요소를 보유하는 하나의 클래스를 만들고 싶습니다. 각 하위 요소를 보유합니다. 다음은 XML 파일의 모양을 보여주는 두 가지 예입니다.(De) 하나의 클래스를 사용하여 다른 루트 요소 이름을 직렬화

파일 1 :

<?xml version="1.0" encoding="utf-8" ?> 
<Sandra> 
    <Address> 
    <Street></Street> 
    <Number></Number> 
    </Address> 
</Sandra> 

파일 2 :

나는 모두 직렬화 할 수와 같은 단지 2 클래스를 사용하여이를 직렬화하는
<?xml version="1.0" encoding="utf-8" ?> 
<John> 
    <Address> 
    <Street></Street> 
    <Number></Number> 
    </Address> 
</John> 

:

[Serializable] 
[XmlRoot] 
public class Person 
{ 
    [XmlElement("Address")] 
    public List<Address> Adresses { get; set; } 
} 

[Serializable] 
public class Address 
{ 
    public string Street { get; set; } 

    public string Number { get; set; } 
} 

I 다음을 사용하여 읽으려고했습니다 :

var ser = new XmlSerializer(typeof(Person)); 
    var reader = XmlReader.Create("person1.xml"); 
    var person = (Person)ser.Deserialize(reader); 

디시리얼라이저가 <"Person"> 루트 요소를 필요로하고 <"John"> 또는 <"Paul">이 아니기 때문에 "There is an error in XML document (2, 2)."이 표시됩니다. 내가 [XmlRoot]에서 [XmlRoot("John")]으로 변경하면 문제가 없지만 정확히 여기서 피하려고합니다.

또한 동일한 이상한 XML 구조를 사용하여 다시 직렬화 할 수 있어야하므로 Person 클래스 내에 루트 요소 이름을 저장해야합니다.

필자 만의 (비) 시리얼 라이저를 만들 수는 있지만 기존 방법을 사용하여 구현할 수 있는지 알고 싶습니다.

편집 1 : (롤백 됨).

편집 2 : "편집 1"의 수정본은 필자가 원하는 것을 얻기위한보다 간단한 방법을 찾은 후 롤백되었습니다. 아래 내 대답을 참조하십시오.

답변

8

발견 내 문제를 해결하기 위해 단정하고 빠른 방법! XmlSerializer를 인스턴스화 할 때 XmlRootAttribute를 사용해야했습니다. 이렇게하면 런타임에 루트 요소의 이름을 설정할 수 있습니다.

var personsName = "Sandra"; 
var ser = new XmlSerializer(typeof(Person), 
    new XmlRootAttribute { ElementName = personsName }); 
var reader = XmlReader.Create("person1.xml"); 
var person = (Person)ser.Deserialize(reader); 

물론 직렬화하려는 경우에도 동일한 방식으로 작동합니다.

2

XML 요소 이름으로 사람 이름을 사용하면 다소 불안합니다. 각 요소의 의미는 John 또는 Person입니까?

그렇게처럼 그들을 표현하기 위해, 그 XML 파일의 모양을 제어 할 수 있다면 그것은 더 좋을 수 있습니다

<?xml version="1.0" encoding="utf-8" ?> 
<Person name="Sandra"> 
    <Address> 
    <Street></Street> 
    <Number></Number> 
    </Address> 
</Person> 

을 한 다음에 이름을 저장하는 쉬운 방법이있을 것이다

[Serializable] 
[XmlRoot] 
public class Person 
{ 
    [XmlElement("Address")] 
    public List<Address> Adresses { get; set; } 

    [XmlAttribute("name")] 
    public string Name { get; set;} 
} 
+1

그래, 그것은 참으로, 좀 이상해. 그러나 XML 구조를 변경하는 것이 아닙니다.이 형식을 읽고 읽고 작성해야합니다. –

1

이 클래스에 IXmlSerializable을 구현하고 직렬화 당신이 기능에 원하는 방식으로 수행합니다 :

ReadXml(System.Xml.XmlReader reader) 및를 XML 속성으로 매핑 속성,

예 :

[Serializable] 
public class Threshold : IXmlSerializable 
{ 

public int Type {get;set;} 
public object Value {get;set;} 
public string Name {get;set;} 
public void ReadXml(System.Xml.XmlReader reader) 
{ 


XElement thresholdXML = XElement.Load(reader); 

if (!thresholdXML.HasElements || thresholdXML.IsEmpty) 
return; 

Type = (ThresholdType)int.Parse(thresholdXML.Element("Type").Value); 
Value = Type.Equals(ThresholdType.Complex) ? thresholdXML.Element("Value").Value : (object)Decimal.Parse(thresholdXML.Element("Value").Value); 
Name = thresholdXML.Element("Name").Value; 


} 


public System.Xml.Schema.XmlSchema GetSchema() 
{ 
return null; 
} 

public void WriteXml(System.Xml.XmlWriter writer) 
{ 
XmlSerializerNamespaces xmlnsEmpty = new XmlSerializerNamespaces(); 
xmlnsEmpty.Add("", ""); 


writer.WriteElementString("Type", ((int)Type).ToString("D")); 
writer.WriteElementString("Value", Value.ToString()); 
writer.WriteElementString("Name", Name); 
} 
} 
+0

''IXmlSerializable'을 구현하려고 시도했지만 첫 번째 아카이브를 deserialize하려고 할 때''{ "는 기대하지 않았습니다." classe의 ReadXml() 메서드는 호출되지 않았습니다. –

+0

먼저 [XmlRoot] 또는 [XmlElement] 특성이 필요하지 않습니다. 또한 기존 XML을 삭제하고 새로운 XML을 직렬화하십시오. ReadXML() 및 WriteXML()에 중단 점을 배치하여 호출되는지 확인합니다. debbugger를 따라 예외의 세부 사항과 발생 위치를 알려주십시오. –

+0

deserialize하려고 할 때 나에게했던 것과 같은 오류가 발생 했습니까? "{"{ "는 기대하지 않았습니다." deserializer가 클래스 이름에 루트 요소 ** 또는 **의 이름이 같고''[XmlRoot ("rootname")] 속성이 있기를 기대하기 때문에 ReadXML이 여전히 호출되지 않습니다. –

0

루트 요소를 ArrayOfClassName으로 사용하고 시도하십시오.

<ArrayOfAlarmSummary> 
    <AlarmSummary> 
    <ClientId>1</ClientId> 
    <StationId>2</StationId> 
    <StationName>Station-2</StationName> 
    <DateTime>13/09/15</DateTime> 
    <TagName>AI2_2</TagName> 
    <Description>TR DC Current</Description> 
    <Units>Amps</Units> 
    <NormalOperation>10 to 100</NormalOperation> 
    <AlarmValue>132.48</AlarmValue> 
    <AlarmDescription> 
    </AlarmDescription> 
    </AlarmSummary> 
    <AlarmSummary> 
    <ClientId>1</ClientId> 
    <StationId>2</StationId> 
    <StationName>Station-2</StationName> 
    <DateTime>13/09/15</DateTime> 
    <TagName>AI2_2</TagName> 
    <Description>TR AC Current</Description> 
    <Units>Amps</Units> 
    <NormalOperation>10 to 100</NormalOperation> 
    <AlarmValue>132.48</AlarmValue> 
    <AlarmDescription> 
    </AlarmDescription> 
    </AlarmSummary> 
</ArrayOfAlarmSummary> 

다음은 deserialize 클래스이며 XML 파일을 비 직렬화 할 수 있습니다.

public class SerializeDeserialize<T> 
    { 
     StringBuilder sbData; 
     StringWriter swWriter; 
     XmlDocument xDoc; 
     XmlNodeReader xNodeReader; 
     XmlSerializer xmlSerializer; 
     public SerializeDeserialize() 
     { 
      sbData = new StringBuilder(); 
     } 
     public string SerializeData(T data) 
     { 
      XmlSerializer employeeSerializer = new XmlSerializer(typeof(T)); 
      swWriter = new StringWriter(sbData); 
      employeeSerializer.Serialize(swWriter, data); 
      return sbData.ToString(); 
     } 

     public T DeserializeData(string dataXML) 
     { 
      xDoc = new XmlDocument(); 
      xDoc.LoadXml(dataXML); 
      xNodeReader = new XmlNodeReader(xDoc.DocumentElement); 
      xmlSerializer = new XmlSerializer(typeof(T)); 
      var employeeData = xmlSerializer.Deserialize(xNodeReader); 
      T deserializedEmployee = (T)employeeData; 
      return deserializedEmployee; 
     } 
    } 

전화 클래스

var appDomain = System.IO.Directory.GetCurrentDirectory() + "\\AlarmFiles"; 
      var strPath = Path.Combine(appDomain, 
       "Alarm_" + DateTime.Now.ToString("ddMMyyyy") + Constants.FileType.XmlFile); 
      var fi = new FileInfo(strPath); 
      if (fi.Exists) 
      { 
       try 
       { 
        var xmlString = System.IO.File.ReadAllText(strPath); 
        var serializeAlarmSummary = 
         new SerializeDeserialize<List<AlarmSummary>>(); 
        return serializeAlarmSummary.DeserializeData(xmlString); 
       } 
       catch (Exception ex) 
       { 
        throw ex; 
       } 

      } 
관련 문제