我收到了 4 个 XSD 架构文件(一个是根,一个用于标题/尾部,一个用于基础,一个用于元素类型)
将根传递给 xsd.exe,根据 XSD 成功生成具有适当结构的类,
我们现在可以为这些类的对象赋值并填充它们,问题是我们如何将它们序列化为保持原始结构的 XML 输出?
完整代码:
using System;
using System.IO;
using System.Xml;
using System.Xml.Schema;
using System.Diagnostics;
using System.Xml.Serialization;
using System.Data;
using System.Data.SqlClient;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;
using GenericNamespace;
namespace ECDS
{
class Program
{
static void Main(string[] args)
{
try
{
String WorkingDir = @"C:\cdsxml\XML";
String FileName = "C:\\Program Files (x86)\\Microsoft SDKs\\Windows\\v10.0A\\bin\\NETFX 4.8 Tools\\xsd.exe";
String ECDSConection = "you can use some dummy string data";
//Generate class at runtime from xsd
var p = new Process{StartInfo = {FileName = FileName, WorkingDirectory = WorkingDir, Arguments = "CDS-XML_Message_Root-V6-2-3.xsd /c /n:GenericNamespace"}};
p.Start();
p.WaitForExit();
DataTable dataTable = new DataTable();
using (SqlConnection connection = new SqlConnection(ECDSConection))
{
connection.Open();
using (SqlCommand command = new SqlCommand("SELECT top (1) " + "[AmbulanceCallIdentifier]" + ",[NHSNumber]" + "FROM [dbo].[ecdsDummy]", connection))
{
{
SqlDataAdapter adapter = new SqlDataAdapter(command);
adapter.Fill(dataTable);
}
}
object obj = null;
// Create a list to store all the objects
List<object> objects = new List<object>();
// Loop through all the classes in the namespace GeneratedClasses
foreach (DataRow row in dataTable.Rows)
{
foreach (Type generatedclasses in Assembly.GetExecutingAssembly().GetTypes())
{
if (generatedclasses.Namespace == "GenericNamespace" && generatedclasses.IsClass)
{
// Check if the generated class has any public properties with a data type other than XmlElement or XmlDocument
bool hasNonXmlProperties = generatedclasses.GetProperties().Any(p => p.PropertyType != typeof(XmlElement) && p.PropertyType != typeof(XmlDocument));
if (!hasNonXmlProperties)
{
continue;
}
// Check if an object with the same type and values already exists in the list
if ((objects.Any(o => o.GetType() == typeof(CDSXMLInterchange) && generatedclasses.Name == "CDSXMLInterchange" && CompareObjectValues(o, row))))
)
{
continue;
}
// Get the data from the dataTable and assign it to the generated class
obj = Activator.CreateInstance(generatedclasses);
try
{
foreach (PropertyInfo property in generatedclasses.GetProperties())
{
if (row.Table.Columns.Contains(property.Name))
{
object value = row[property.Name];
property.SetValue(obj, value);
}
}
{
objects.Add(obj);
}
}
catch (Exception ex)
{
ex.Message.ToString();
}
// }
}
}
}
// Get all types in the GeneratedClasses namespace
Type[] generatedTypes = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.Namespace == "GenericNamespace").ToArray();
// Define the list of expected types
List<Type> expectedTypes = new List<Type>();
foreach (Type type in generatedTypes)
{
expectedTypes.Add(type);
}
// Create the XmlSerializer with the expected types
XmlSerializer serializer = new XmlSerializer(typeof(object), expectedTypes.ToArray());
//XmlSerializer serializer = new XmlSerializer(typeof(object), new XmlRootAttribute("CDSXMLInterchange"));
// Create the XmlSerializerNamespaces object with an empty namespace prefix and URI
XmlSerializerNamespaces serializerNamespaces = new XmlSerializerNamespaces();
serializerNamespaces.Add("", "");
//Serialize the objects to XML
XmlWriterSettings settings = new XmlWriterSettings();
settings.ConformanceLevel = ConformanceLevel.Fragment;
using (XmlWriter writer = XmlWriter.Create("C:\\cdsxml\\XMLTest.xml", settings))
{
foreach (object obj1 in objects)
{
Type objType = obj1.GetType();
string objTypeName = objType.Name;
string objNamespace = null;
XmlRootAttribute xmlRoot = objType.GetCustomAttribute<XmlRootAttribute>();
if (xmlRoot != null)
{
//RootElemet
objNamespace = objType.Namespace;
writer.WriteStartElement(objTypeName, "http://www.nhsia.nhs.uk/DataStandards/XMLschema/CDS/ns");
serializer.Serialize(writer, obj1, serializerNamespaces);
}
else
{
objNamespace = objType.Namespace;
writer.WriteStartElement(objTypeName, "http://www.nhsia.nhs.uk/DataStandards/XMLschema/CDS/ns");
//writer.WriteStartElement("ns", objTypeName, "http://www.nhsia.nhs.uk/DataStandards/XMLschema/CDS/ns");
//// Serialize objects to XML
serializer.Serialize(writer, obj1, serializerNamespaces);
// Write the end element
writer.WriteEndElement();
}
}
writer.WriteEndElement();
}
}
}
catch (Exception ex)
{
ex.Message.ToString();
}
}
// Helper method to compare the values of two objects
public static bool CompareObjectValues(object obj, DataRow row)
{
foreach (PropertyInfo property in obj.GetType().GetProperties())
{
if (property.PropertyType.Namespace == "System")
{
if (row.Table.Columns.Contains(property.Name))
{
object value = row[property.Name];
if (value is DBNull)
{
value = null;
}
else if (property.PropertyType == typeof(string[]))
{
value = ((string)value).Split(',');
}
else if (property.PropertyType == typeof(decimal))
{
decimal decimalValue;
if (!decimal.TryParse((string)value, out decimalValue))
{
Console.WriteLine("Unable to convert " + value + " to decimal.");
continue;
}
value = decimalValue;
}
else if (property.PropertyType == typeof(object) && (value is XmlElement || value is XmlDocument))
{
// Skip setting the property for <anyType> elements
continue;
}
if (!object.Equals(property.GetValue(obj), value))
{
return false;
}
}
}
}
return true;
}
}
}
问题是,是否有任何直接的方法可以将对象序列化为 XML 而无需循环遍历它们并将开始元素/结束元素手动插入到输出 XML 中?这样做是在改变 XML 结构。