#c# #xml #xml-deserialization
#c# #xml #xml-десериализация
Вопрос:
У меня есть XML-файл, который я пытаюсь десериализовать. Я реализую интерфейс IXmlSerializable для сериализации и десериализации. Я не вижу никаких проблем с сериализацией. Но с десериализацией у меня мало проблем. 1). Я использую ReadToFollowing для чтения элементов в xml Reader. При таком подходе я должен считывать значения в порядке элементов. Если есть какое-либо несоответствие в порядке, я не могу прочитать оставшиеся значения. 2). Согласно моему требованию, я должен обеспечить обратную совместимость при десериализации xml. Из-за этого, когда я загружаю некоторые XML-файлы старой версии (которые могут содержать не все элементы, как в последней версии xml), ‘ReadToFollowing’ выдает исключения.
Последняя версия Xml
<LEFTSECTION>
<DATA />
<FONTNAME>Arial</FONTNAME>
<FONTSTYLE>Regular</FONTSTYLE>
<FONTSIZE>10</FONTSIZE>
<TEXTCOLOR>-16777216</TEXTCOLOR>
<STRIKEOUT>0</STRIKEOUT>
<UNDERLINE>0</UNDERLINE>
<BORDER>0</BORDER>
<IMAGE>0</IMAGE>
<IMAGENAME />
<ALIGNMENT>4</ALIGNMENT>
<SECTIONHEIGHT>0.5454546</SECTIONHEIGHT>
<SECTIONWIDTH>0.33</SECTIONWIDTH>
</LEFTSECTION>
Старая версия Xml
<LEFTSECTION>
<DATA>asas#APP_OEM_NAME#</DATA>
<FONTNAME>Arial Unicode MS</FONTNAME>
<FONTSTYLE>Regular</FONTSTYLE>
<FONTSIZE>10</FONTSIZE>
<TEXTCOLOR>-16777216</TEXTCOLOR>
<STRIKEOUT>0</STRIKEOUT>
<UNDERLINE>0</UNDERLINE>
<BORDER>0</BORDER>
<IMAGE>0</IMAGE>
<IMAGENAME>
</IMAGENAME>
</LEFTSECTION>
Пожалуйста, помогите мне в этом.
Комментарии:
1. Хм, ни один из ваших примеров не является XML-кодом.
2. Вам нужно записать или просто прочитать эти XML-данные?
3. @Chris: Просто нужно прочитать данные
Ответ №1:
Хорошо. У меня была игра, и это то, что я придумал:
Сериализуемый класс:
[Serializable]
[XmlRoot("LEFTSECTION")]
public class NewClass
{
[XmlElement("DATA")]
[System.ComponentModel.DefaultValueAttribute("")]
public string Data;
[XmlElement("FONTNAME")]
public string FontName;
[XmlElement("FONTSTYLE")]
public string FontStyle;
[XmlElement("FONTSIZE")]
public int FontSize;
[XmlElement("TEXTCOLOR")]
public int TextColor;
[XmlElement("STRIKEOUT")]
public int Strikeout;
[XmlElement("UNDERLINE")]
public int Underline;
[XmlElement("BORDER")]
public int Border;
[XmlElement("IMAGE")]
public int Image;
[XmlElement("IMAGENAME")]
public string ImageName;
[System.ComponentModel.DefaultValue(0)]
[XmlElement("ALIGNMENT")]
public int Alignment;
[XmlElement("SECTIONHEIGHT")]
public double SectionHeight;
[XmlElement("SECTIONWIDTH")]
public double SectionWidth;
}
Затем кодируйте в моей тестовой программе:
NewClass test = new NewClass();
XmlSerializer serializer = new XmlSerializer(typeof(NewClass));
FileStream file = new FileStream("input.xml", FileMode.Open);
test = (NewClass) serializer.Deserialize(file);
file.Close();
file = new FileStream("old.xml", FileMode.Open);
test = (NewClass)serializer.Deserialize(file);
file.Close();
Содержимое input.xml:
<?xml version="1.0" encoding="utf-8" ?>
<LEFTSECTION>
<DATA />
<FONTNAME>Arial</FONTNAME>
<FONTSTYLE>Regular</FONTSTYLE>
<FONTSIZE>10</FONTSIZE>
<TEXTCOLOR>-16777216</TEXTCOLOR>
<STRIKEOUT>0</STRIKEOUT>
<UNDERLINE>0</UNDERLINE>
<BORDER>0</BORDER>
<IMAGE>0</IMAGE>
<IMAGENAME />
<ALIGNMENT>4</ALIGNMENT>
<SECTIONHEIGHT>0.5454546</SECTIONHEIGHT>
<SECTIONWIDTH>0.33</SECTIONWIDTH>
</LEFTSECTION>
Содержимое old.xml:
<LEFTSECTION>
<DATA>asas#APP_OEM_NAME#</DATA>
<FONTNAME>Arial Unicode MS</FONTNAME>
<FONTSTYLE>Regular</FONTSTYLE>
<FONTSIZE>10</FONTSIZE>
<TEXTCOLOR>-16777216</TEXTCOLOR>
<STRIKEOUT>0</STRIKEOUT>
<UNDERLINE>0</UNDERLINE>
<BORDER>0</BORDER>
<IMAGE>0</IMAGE>
<IMAGENAME>
</IMAGENAME>
</LEFTSECTION>
Это правильно заполняет мой класс. Обратите внимание, что для Data
и Alignment
свойств моего класса я устанавливаю значения по умолчанию, если они не существуют. Также все они переименованы из того, что находится в файле.
Я надеюсь, что это поможет.
Редактировать
Ах, я вижу, вы застряли с методами IXmlSerializable для своих классов.
Попробуйте это, это не красиво, но, похоже, работает:
Вот мой класс IXmlSerializable:
public class XmlSerializableNewClass : IXmlSerializable
{
public string Data;
public string FontName;
public string FontStyle;
public int FontSize;
public int TextColor;
public int Strikeout;
public int Underline;
public int Border;
public int Image;
public string ImageName;
public int Alignment;
public double SectionHeight;
public double SectionWidth;
public string[]elementNames={"DATA", "FONTNAME", "FONTSTYLE","FONTSIZE","TEXTCOLOR","STRIKEOUT", "UNDERLINE", "BORDER", "IMAGE", "IMAGENAME", "ALIGNMENT", "SECTIONHEIGHT", "SECTIONWIDTH"};
#region IXmlSerializable Members
public System.Xml.Schema.XmlSchema GetSchema()
{
return null;
}
public void ReadXml(System.Xml.XmlReader reader)
{
//set default values
Data=string.Empty;
FontName = string.Empty;
FontStyle = string.Empty;
FontSize = 0;
TextColor = 0;
Strikeout = 0;
Underline = 0;
Border = 0;
Image = 0;
ImageName = string.Empty;
Alignment = 0;
SectionHeight = 0.0;
SectionWidth = 0.0;
reader.MoveToContent();
Boolean isEmptyElement= false;
isEmptyElement = reader.IsEmptyElement;
reader.ReadStartElement();
for (int i=0; i< elementNames.Length; i )
{
isEmptyElement = reader.IsEmptyElement;
string s = reader.Name;
switch (s)
{
case "DATA":
if (!isEmptyElement)
{
Data = reader.ReadElementString("DATA");
}
else
{
Data = string.Empty;
reader.ReadStartElement();
}
break;
case "FONTNAME":
if (!isEmptyElement)
{
FontName = reader.ReadElementString("FONTNAME");
}
else
{
FontName = string.Empty;
reader.ReadStartElement();
}
break;
case "FONTSTYLE":
if (!isEmptyElement)
{
FontStyle = reader.ReadElementString("FONTSTYLE");
}
else
{
FontStyle = string.Empty;
reader.ReadStartElement();
}
break;
case "FONTSIZE":
if (!isEmptyElement)
{
FontSize = reader.ReadElementContentAsInt();
}
else
{
FontSize = 0;
reader.ReadEndElement();
}
break;
case "TEXTCOLOR":
if (!isEmptyElement)
{
TextColor = reader.ReadElementContentAsInt();
}
else
{
TextColor = 0;
reader.ReadStartElement();
}
break;
case "STRIKEOUT":
if (!isEmptyElement)
{
Strikeout = reader.ReadElementContentAsInt();
}
else
{
Strikeout = 0;
reader.ReadStartElement();
}
break;
case "UNDERLINE":
if (!isEmptyElement)
{
Underline = reader.ReadElementContentAsInt();
}
else
{
Underline = 0;
reader.ReadStartElement();
}
break;
case "BORDER":
if (!isEmptyElement)
{
Border = reader.ReadElementContentAsInt();
}
else
{
Border = 0;
reader.ReadStartElement();
}
break;
case "IMAGE":
if (!isEmptyElement)
{
Image = reader.ReadElementContentAsInt();
}
else
{
Image = 0;
reader.ReadStartElement();
}
break;
case "IMAGENAME":
if (!isEmptyElement)
{
ImageName = reader.ReadElementString("IMAGENAME");
}
else
{
ImageName = string.Empty;
reader.ReadStartElement();
}
break;
case "ALIGNMENT":
if (!isEmptyElement)
{
Alignment = reader.ReadElementContentAsInt();
}
else
{
Alignment = 0;
reader.ReadStartElement();
}
break;
case "SECTIONHEIGHT":
if (!isEmptyElement)
{
SectionHeight = reader.ReadElementContentAsDouble();
}
else
{
SectionHeight = 0;
reader.ReadStartElement();
}
break;
case "SECTIONWIDTH":
if (!isEmptyElement)
{
SectionWidth = reader.ReadElementContentAsDouble();
}
else
{
SectionWidth = 0;
reader.ReadEndElement();
}
break;
}
}
reader.ReadEndElement();
}
public void WriteXml(System.Xml.XmlWriter writer)
{
throw new NotImplementedException();
}
#endregion
}
Я немного перестарался с обработкой пустых элементов.
Вот вызывающий код, все остальное то же самое:
XmlSerializableNewClass test2 = new XmlSerializableNewClass();
System.Xml.XmlReaderSettings settings = new System.Xml.XmlReaderSettings();
settings.ConformanceLevel = System.Xml.ConformanceLevel.Fragment;
settings.IgnoreWhitespace = true;
settings.IgnoreComments = true;
System.Xml.XmlReader reader = System.Xml.XmlReader.Create("input.xml", settings);
test2.ReadXml(reader);
reader = System.Xml.XmlReader.Create("old.xml", settings);
test2.ReadXml(reader);
Комментарии:
1. Спасибо за ответ, Крис. Но я использую интерфейс IXmlSerializable для сериализации и десериализации. Я должен прочитать значения в методах ‘ReadXml’.
2. Взгляните на отредактированный ответ. Код не очень красивый, но, похоже, работает.