I get multiple XSDs from various clients and I need to give them the data in XML format conforming to the XSD that they have provided. I already have written a code to dynamically create and compile a class from XSD using codedom, System.Reflection and codeprovider. Now my plan is to get data from database through multiple queries and map the fields to the properties of the dynamic class created and serialize it. I am looking for a generic way of mapping these fields, which can be used for any type of xsd and by just mapping the fields it will serialize and gives XML file. As for the queries I am putting them in the config file. Is a generic solution do-able? Any ideas or pointers on how to go about it?
2 に答える
私はこれを解決することができました。使用した手順は次のとおりです。最初に、シリアル化可能な属性を持つリフレクションとcodedom.compilerを使用して、xsdからメモリ内ランタイムアセンブリを作成しました。リフレクションを使用して、そのアセンブリにクラスのインスタンスを作成し、データベースから取得したデータからプロパティを割り当てました。私がシリアル化する別のメソッドに転送したこのクラスは、オブジェクトを取得してxmlにシリアル化します。
マッピングに関しては、データベースの列名がxml属性名と一致する必要があることを確認し、それを使用してマッピングして呼び出すことができました。
スニペットは次のとおりです。
object fxClass = myAssembly.CreateInstance(cls.FullName);
Type t = fxClass.GetType();
var arrRates = Array.CreateInstance(t, tab.Rows.Count);
int i =0;
foreach (DataRow dr in tab.Rows)
{
fxClass = myAssembly.CreateInstance(cls.FullName);
PropertyInfo[] fxRateProperties = t.GetProperties();
foreach (PropertyInfo prop in fxRateProperties)
{
string rowVal = dr[prop.Name].ToString();
if (prop.PropertyType == typeof(DateTime))
{
prop.SetValue(fxClass, util.convertToDate(rowVal), null);
}
else if (prop.PropertyType == typeof(bool))
{
prop.SetValue(fxClass, util.convertToBoolean(rowVal), null);
}
else if (prop.PropertyType == typeof(decimal))
{
prop.SetValue(fxClass, util.convertToDecimal(rowVal), null);
}
else prop.SetValue(fxClass, rowVal, null);
}
arrRates.SetValue(fxClass,i);
i++;
}
myClass.GetType().GetProperty("ForexRates").SetValue(myClass, arrRates, null);
次に、myClassオブジェクトを渡して、オブジェクトタイプを受け入れるシリアル化メソッドを実行します。これで完了です。
public void serializeXML(object portfolio, string xmlPath)
{
XmlSerializer serial = new XmlSerializer(portfolio.GetType());
XmlSerializerNamespaces ns = new XmlSerializerNamespaces();
ns.Add("", "");
try
{
using (FileStream fs = new FileStream(xmlPath, FileMode.Create, FileAccess.Write))
{
using (XmlTextWriter tw = new XmlTextWriter(fs, Encoding.UTF8))
{
tw.Formatting = Formatting.Indented;
serial.Serialize(tw, portfolio, ns);
}
}
}
}
このために、「ForexRates」などのマッピングがデータベースに保存され、任意のxsdタイプで開かれるUIピースを追加することを計画しています。
ご回答ありがとうございます。
オンザフライで作成されたクラスをシリアライズすることはできません。少なくとも、通常の方法ではできません。属性をアタッチする方法が見つかったとしても、Serializable
何の効果もありません。シリアル化アセンブリは生成されません。
理論的には、まったく新しいクラスを発行し、実行時にそれを sgen することもできますが、それは絶対的な苦痛です。その場合は、.NET Framework の既定の IL エミッターよりも Mono.Cecil をお勧めします。