admin管理员组文章数量:1377579
This demo code showcases how the XSerializer 0.1.28 works but it's deprecated and new libraries do not allow Serializing an Array as a Sequence of Elements for multiple lists with the same serialized name in the same class or an inherited class (see )
See error at the bottom of the code.
Note this is a small demo to showcase the requirement. In the real use case inheritance is 10 levels deep with 100 fields so automated serialization would be preferred.
The solution would be a library that has the same behavior as the deprecated XSerializer, an XML Attribute or manual building of the XML -- not preferred due to the amount of classes and fields.
// app.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<!-- <PackageReference Include="RockLib.Serialization" Version="2.0.0" />
<PackageReference Include="RockLib.Serialization.XSerializer" Version="1.0.5" /> -->
<PackageReference Include="ExtendedXmlSerializer" Version="3.8.0" />
<PackageReference Include="XSerializer" Version="0.1.28" />
</ItemGroup>
</Project>
// Program.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
using System.Xml;
using ExtendedXmlSerializer;
// old version works
using XSerializer;
// new version does not work
// using RockLib.Serialization;
// using RockLib.Serialization.XSerializer;
public class Board
{
[XmlElement(IsNullable = true)]
public virtual string Name { get; set; }
}
public class InputBoard : Board
{
[XmlElement(IsNullable = true)]
public override string Name { get; set; }
}
public class ExpansionBoard : Board
{
[XmlElement(IsNullable = true)]
public override string Name { get; set; }
[XmlElement(ElementName = "BoardInput")] // THIS SAME NAME CAUSES ERROR
public List<InputBoard> Inputs { get; set; }
}
public class MotherBoard : ExpansionBoard
{
[XmlElement(IsNullable = true)]
public override string Name { get; set; }
[XmlElement(ElementName = "ExpansionBoard")]
public List<ExpansionBoard> ExpansionBoards { get; set; }
[XmlElement(ElementName = "BoardInput")] // THIS NAME CAUSES ERROR
public List<InputBoard> USBInputs { get; set; }
[XmlElement(ElementName = "BoardInput")] // THIS SAME NAME CAUSES ERROR
public List<InputBoard> SerialInputs { get; set; }
}
public class MyXSerializer<T> where T : class
{
public static string Serialize(T obj)
{
XSerializer.XmlSerializer<T> serializer = new XSerializer.XmlSerializer<T>();
string xml = serializer.Serialize(obj);
return xml;
}
}
public class MyPrettyXSerializer<T> where T : class
{
public static string Serialize(T obj)
{
XSerializer.XmlSerializer<T> serializer = new XSerializer.XmlSerializer<T>();
string xml = serializer.Serialize(obj);
// Load the XML string into an XmlDocument
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xml);
// Create an XmlWriterSettings object to specify formatting options
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.IndentChars = "\t";
settings.NewLineChars = Environment.NewLine;
settings.NewLineHandling = NewLineHandling.Replace;
// Use the XmlWriterSettings object to write the XML to a string
using (var sw = new StringWriter())
{
using (var writer = XmlWriter.Create(sw, settings))
{
xmlDoc.WriteTo(writer);
}
return sw.ToString();
}
}
}
// public class MyRockXSerializer<T> where T : class
// {
// public static string Serialize(T obj)
// {
// var xml = obj.ToXml();
// return xml;
// }
// }
public class MySerializer<T> where T : class
{
public static string Serialize(T obj)
{
System.Xml.Serialization.XmlSerializer xsSubmit = new System.Xml.Serialization.XmlSerializer(typeof(T));
using (var sww = new StringWriter())
{
using (XmlTextWriter writer = new XmlTextWriter(sww) { Formatting = Formatting.Indented })
{
xsSubmit.Serialize(writer, obj);
return sww.ToString();
}
}
}
}
public class MyExtendedXmlSerializer<T>where T : class
{
public static string Serialize(T obj)
{
ExtendedXmlSerializer.IExtendedXmlSerializer serializer = new ExtendedXmlSerializer.Configuration.ConfigurationContainer()
.UseAutoFormatting()
.UseOptimizedNamespaces()
.EnableImplicitTyping(typeof(T))
.Create();
var xml = serializer.Serialize(new XmlWriterSettings { Indent = true }, obj);
return xml.ToString();
}
}
public class MyExtended2XmlSerializer<T>where T : class
{
public static string Serialize(T obj)
{
ExtendedXmlSerializer.Configuration.IConfigurationContainer configuration = new ExtendedXmlSerializer.Configuration.ConfigurationContainer();
var serializer = configuration.Create();
using (var stringWriter = new StringWriter())
{
var xml = serializer.Serialize(obj);
return xml;
}
}
}
public class Program
{
public static void Main()
{
InputBoard ib1 = new InputBoard{Name = "NVidia 850i"};
InputBoard ib2 = new InputBoard{Name = "NVidia M8"};
InputBoard ib3 = new InputBoard{Name = "NVidia M5"};
InputBoard usb1 = new InputBoard{Name = "USB KB"};
InputBoard usb2 = new InputBoard{Name = "USB MU"};
InputBoard usb3 = new InputBoard{Name = "USB AU"};
InputBoard ser1 = new InputBoard{Name = "SER 1"};
InputBoard ser2 = new InputBoard{Name = "SER 2"};
InputBoard ser3 = new InputBoard{Name = "SER 3"};
ExpansionBoard eb = new ExpansionBoard{ Name = "Nvidia Expander BRD", Inputs = new List<InputBoard>{ib1, ib2, ib3}};
MotherBoard mb = new MotherBoard{Name = "MST 3000 MB", ExpansionBoards = new List<ExpansionBoard>{eb}, USBInputs = new List<InputBoard>{usb1, usb2, usb3}, SerialInputs = new List<InputBoard>{ser1, ser2, ser3}};
string xml;
// xml = MyXSerializer<MotherBoard>.Serialize(mb);
// Console.WriteLine(xml);
// same but pretty
xml = MyPrettyXSerializer<MotherBoard>.Serialize(mb);
Console.WriteLine(xml);
// xml = MyRockXSerializer<MotherBoard>.Serialize(mb);
// Console.WriteLine(xml);
// xml = MySerializer<MotherBoard>.Serialize(mb);
// Console.WriteLine(xml);
// xml = MyExtendedXmlSerializer<MotherBoard>.Serialize(mb);
// Console.WriteLine(xml);
// xml = MyExtended2XmlSerializer<MotherBoard>.Serialize(mb);
// Console.WriteLine(xml);
}
}
The error with newer libraries
Unhandled exception. System.InvalidOperationException: There was an error reflecting type 'MotherBoard'.
---> System.InvalidOperationException: There was an error reflecting property 'USBInputs'.
---> System.InvalidOperationException: The XML element 'BoardInput' from namespace '' is already present in the current scope. Use XML attributes to specify another XML name or namespace for the element.
at System.Xml.Serialization.XmlReflectionImporter.AddUniqueAccessor(INameScope scope, Accessor accessor)
at System.Xml.Serialization.XmlReflectionImporter.AddUniqueAccessor(MemberMapping member, INameScope elements, INameScope attributes, Boolean isSequence)
at System.Xml.Serialization.XmlReflectionImporter.InitializeStructMembers(StructMapping mapping, StructModel model, Boolean openModel, String typeName, RecursionLimiter limiter)
--- End of inner exception stack trace ---
at System.Xml.Serialization.XmlReflectionImporter.InitializeStructMembers(StructMapping mapping, StructModel model, Boolean openModel, String typeName, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.ImportStructLikeMapping(StructModel model, String ns, Boolean openModel, XmlAttributes a, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, XmlAttributes a, Boolean repeats, Boolean openModel, RecursionLimiter limiter)
--- End of inner exception stack trace ---
at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, XmlAttributes a, Boolean repeats, Boolean openModel, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.ImportElement(TypeModel model, XmlRootAttribute root, String defaultNamespace, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(Type type, XmlRootAttribute root, String defaultNamespace)
at System.Xml.Serialization.XmlSerializer..ctor(Type type, String defaultNamespace)
at RockLib.Serialization.DefaultXmlSerializer.SerializeToString(Object item, Type type) in /_/RockLib.Serialization/DefaultXmlSerializer.cs:line 123
at RockLib.Serialization.Serializer.ToXml(Object item, Type type, String name) in /_/RockLib.Serialization/Serializer.cs:line 124
at RockLib.Serialization.Serializer.ToXml[T](T item, String name) in /_/RockLib.Serialization/Serializer.cs:line 114
at MyRockXSerializer`1.Serialize(T obj) in C:\code\xml3\app\Program.cs:line 91
at Program.Main() in C:\code\xml3\app\Program.cs:line 169
This demo code showcases how the XSerializer 0.1.28 works but it's deprecated and new libraries do not allow Serializing an Array as a Sequence of Elements for multiple lists with the same serialized name in the same class or an inherited class (see https://learn.microsoft/en-us/dotnet/standard/serialization/controlling-xml-serialization-using-attributes )
See error at the bottom of the code.
Note this is a small demo to showcase the requirement. In the real use case inheritance is 10 levels deep with 100 fields so automated serialization would be preferred.
The solution would be a library that has the same behavior as the deprecated XSerializer, an XML Attribute or manual building of the XML -- not preferred due to the amount of classes and fields.
// app.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<!-- <PackageReference Include="RockLib.Serialization" Version="2.0.0" />
<PackageReference Include="RockLib.Serialization.XSerializer" Version="1.0.5" /> -->
<PackageReference Include="ExtendedXmlSerializer" Version="3.8.0" />
<PackageReference Include="XSerializer" Version="0.1.28" />
</ItemGroup>
</Project>
// Program.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml.Serialization;
using System.Xml;
using ExtendedXmlSerializer;
// old version works
using XSerializer;
// new version does not work
// using RockLib.Serialization;
// using RockLib.Serialization.XSerializer;
public class Board
{
[XmlElement(IsNullable = true)]
public virtual string Name { get; set; }
}
public class InputBoard : Board
{
[XmlElement(IsNullable = true)]
public override string Name { get; set; }
}
public class ExpansionBoard : Board
{
[XmlElement(IsNullable = true)]
public override string Name { get; set; }
[XmlElement(ElementName = "BoardInput")] // THIS SAME NAME CAUSES ERROR
public List<InputBoard> Inputs { get; set; }
}
public class MotherBoard : ExpansionBoard
{
[XmlElement(IsNullable = true)]
public override string Name { get; set; }
[XmlElement(ElementName = "ExpansionBoard")]
public List<ExpansionBoard> ExpansionBoards { get; set; }
[XmlElement(ElementName = "BoardInput")] // THIS NAME CAUSES ERROR
public List<InputBoard> USBInputs { get; set; }
[XmlElement(ElementName = "BoardInput")] // THIS SAME NAME CAUSES ERROR
public List<InputBoard> SerialInputs { get; set; }
}
public class MyXSerializer<T> where T : class
{
public static string Serialize(T obj)
{
XSerializer.XmlSerializer<T> serializer = new XSerializer.XmlSerializer<T>();
string xml = serializer.Serialize(obj);
return xml;
}
}
public class MyPrettyXSerializer<T> where T : class
{
public static string Serialize(T obj)
{
XSerializer.XmlSerializer<T> serializer = new XSerializer.XmlSerializer<T>();
string xml = serializer.Serialize(obj);
// Load the XML string into an XmlDocument
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xml);
// Create an XmlWriterSettings object to specify formatting options
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.IndentChars = "\t";
settings.NewLineChars = Environment.NewLine;
settings.NewLineHandling = NewLineHandling.Replace;
// Use the XmlWriterSettings object to write the XML to a string
using (var sw = new StringWriter())
{
using (var writer = XmlWriter.Create(sw, settings))
{
xmlDoc.WriteTo(writer);
}
return sw.ToString();
}
}
}
// public class MyRockXSerializer<T> where T : class
// {
// public static string Serialize(T obj)
// {
// var xml = obj.ToXml();
// return xml;
// }
// }
public class MySerializer<T> where T : class
{
public static string Serialize(T obj)
{
System.Xml.Serialization.XmlSerializer xsSubmit = new System.Xml.Serialization.XmlSerializer(typeof(T));
using (var sww = new StringWriter())
{
using (XmlTextWriter writer = new XmlTextWriter(sww) { Formatting = Formatting.Indented })
{
xsSubmit.Serialize(writer, obj);
return sww.ToString();
}
}
}
}
public class MyExtendedXmlSerializer<T>where T : class
{
public static string Serialize(T obj)
{
ExtendedXmlSerializer.IExtendedXmlSerializer serializer = new ExtendedXmlSerializer.Configuration.ConfigurationContainer()
.UseAutoFormatting()
.UseOptimizedNamespaces()
.EnableImplicitTyping(typeof(T))
.Create();
var xml = serializer.Serialize(new XmlWriterSettings { Indent = true }, obj);
return xml.ToString();
}
}
public class MyExtended2XmlSerializer<T>where T : class
{
public static string Serialize(T obj)
{
ExtendedXmlSerializer.Configuration.IConfigurationContainer configuration = new ExtendedXmlSerializer.Configuration.ConfigurationContainer();
var serializer = configuration.Create();
using (var stringWriter = new StringWriter())
{
var xml = serializer.Serialize(obj);
return xml;
}
}
}
public class Program
{
public static void Main()
{
InputBoard ib1 = new InputBoard{Name = "NVidia 850i"};
InputBoard ib2 = new InputBoard{Name = "NVidia M8"};
InputBoard ib3 = new InputBoard{Name = "NVidia M5"};
InputBoard usb1 = new InputBoard{Name = "USB KB"};
InputBoard usb2 = new InputBoard{Name = "USB MU"};
InputBoard usb3 = new InputBoard{Name = "USB AU"};
InputBoard ser1 = new InputBoard{Name = "SER 1"};
InputBoard ser2 = new InputBoard{Name = "SER 2"};
InputBoard ser3 = new InputBoard{Name = "SER 3"};
ExpansionBoard eb = new ExpansionBoard{ Name = "Nvidia Expander BRD", Inputs = new List<InputBoard>{ib1, ib2, ib3}};
MotherBoard mb = new MotherBoard{Name = "MST 3000 MB", ExpansionBoards = new List<ExpansionBoard>{eb}, USBInputs = new List<InputBoard>{usb1, usb2, usb3}, SerialInputs = new List<InputBoard>{ser1, ser2, ser3}};
string xml;
// xml = MyXSerializer<MotherBoard>.Serialize(mb);
// Console.WriteLine(xml);
// same but pretty
xml = MyPrettyXSerializer<MotherBoard>.Serialize(mb);
Console.WriteLine(xml);
// xml = MyRockXSerializer<MotherBoard>.Serialize(mb);
// Console.WriteLine(xml);
// xml = MySerializer<MotherBoard>.Serialize(mb);
// Console.WriteLine(xml);
// xml = MyExtendedXmlSerializer<MotherBoard>.Serialize(mb);
// Console.WriteLine(xml);
// xml = MyExtended2XmlSerializer<MotherBoard>.Serialize(mb);
// Console.WriteLine(xml);
}
}
The error with newer libraries
Unhandled exception. System.InvalidOperationException: There was an error reflecting type 'MotherBoard'.
---> System.InvalidOperationException: There was an error reflecting property 'USBInputs'.
---> System.InvalidOperationException: The XML element 'BoardInput' from namespace '' is already present in the current scope. Use XML attributes to specify another XML name or namespace for the element.
at System.Xml.Serialization.XmlReflectionImporter.AddUniqueAccessor(INameScope scope, Accessor accessor)
at System.Xml.Serialization.XmlReflectionImporter.AddUniqueAccessor(MemberMapping member, INameScope elements, INameScope attributes, Boolean isSequence)
at System.Xml.Serialization.XmlReflectionImporter.InitializeStructMembers(StructMapping mapping, StructModel model, Boolean openModel, String typeName, RecursionLimiter limiter)
--- End of inner exception stack trace ---
at System.Xml.Serialization.XmlReflectionImporter.InitializeStructMembers(StructMapping mapping, StructModel model, Boolean openModel, String typeName, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.ImportStructLikeMapping(StructModel model, String ns, Boolean openModel, XmlAttributes a, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, XmlAttributes a, Boolean repeats, Boolean openModel, RecursionLimiter limiter)
--- End of inner exception stack trace ---
at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(TypeModel model, String ns, ImportContext context, String dataType, XmlAttributes a, Boolean repeats, Boolean openModel, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.ImportElement(TypeModel model, XmlRootAttribute root, String defaultNamespace, RecursionLimiter limiter)
at System.Xml.Serialization.XmlReflectionImporter.ImportTypeMapping(Type type, XmlRootAttribute root, String defaultNamespace)
at System.Xml.Serialization.XmlSerializer..ctor(Type type, String defaultNamespace)
at RockLib.Serialization.DefaultXmlSerializer.SerializeToString(Object item, Type type) in /_/RockLib.Serialization/DefaultXmlSerializer.cs:line 123
at RockLib.Serialization.Serializer.ToXml(Object item, Type type, String name) in /_/RockLib.Serialization/Serializer.cs:line 124
at RockLib.Serialization.Serializer.ToXml[T](T item, String name) in /_/RockLib.Serialization/Serializer.cs:line 114
at MyRockXSerializer`1.Serialize(T obj) in C:\code\xml3\app\Program.cs:line 91
at Program.Main() in C:\code\xml3\app\Program.cs:line 169
Share
Improve this question
asked Mar 20 at 18:22
Adam MendozaAdam Mendoza
5,9152 gold badges27 silver badges32 bronze badges
1 Answer
Reset to default 2I could use the default System.Xml.Serialization.XmlSerializer to serialize your XML. The "fix" is to add the Order-attribute on all fields.
By not setting the Order the serializer finds element BoardInput and has no idea to which object it has to connect it to.
I updated your code to this and that gave me a working console-application:
public class Board
{
[XmlElement(IsNullable = true, Order =1)]
public virtual string Name { get; set; }
}
public class InputBoard : Board
{
[XmlElement(IsNullable = true, Order=1)]
public override string Name { get; set; }
}
public class ExpansionBoard : Board
{
[XmlElement(IsNullable = true, Order =1)]
public override string Name { get; set; }
[XmlElement(ElementName = "BoardInput", Order=2)] // THIS SAME NAME CAUSES ERROR
public List<InputBoard> Inputs { get; set; }
}
public class MotherBoard : ExpansionBoard
{
[XmlElement(IsNullable = true, Order =1)]
public override string Name { get; set; }
[XmlElement(ElementName = "ExpansionBoard", Order =2)]
public List<ExpansionBoard> ExpansionBoards { get; set; }
[XmlElement(ElementName = "BoardInput", Order=3)] // THIS NAME CAUSES ERROR
public List<InputBoard> USBInputs { get; set; }
[XmlElement(ElementName = "BoardInput", Order=4)] // THIS SAME NAME CAUSES ERROR
public List<InputBoard> SerialInputs { get; set; }
}
public class MyPrettyXSerializer<T> where T : class
{
public static string Serialize(T obj)
{
var serializer = new System.Xml.Serialization.XmlSerializer(typeof(T));
var xml = string.Empty;
using (var memoryStream = new MemoryStream())
{
serializer.Serialize(memoryStream, obj);
memoryStream.Position = 0;
var streamReader = new StreamReader(memoryStream);
xml = streamReader.ReadToEnd();
streamReader.Close();
}
// Load the XML string into an XmlDocument
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xml);
// Create an XmlWriterSettings object to specify formatting options
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
settings.IndentChars = "\t";
settings.NewLineChars = Environment.NewLine;
settings.NewLineHandling = NewLineHandling.Replace;
// Use the XmlWriterSettings object to write the XML to a string
using (var sw = new StringWriter())
{
using (var writer = XmlWriter.Create(sw, settings))
{
xmlDoc.WriteTo(writer);
}
return sw.ToString();
}
}
}
本文标签:
版权声明:本文标题:.net - I need a dotnet C# XML Serializer like XSerializer 0.1.28 for List<T> A and List<T> B element 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1744390451a2603956.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论