2010-07-16 1 views
1

Я столкнулся с проблемой и задался вопросом, есть ли простой способ ее решения.Сериализовать список <string> и использовать каждую строку как xml Узел

Здесь у меня есть XML-шаблон, определяющий некоторые свойства и их значения.

<Properties> 
    <Property name="ID">10000</Property> 
    <Property name="Name"> 
    <SubProperty name="FirstName">Foo</SubProperty> 
    <SubProperty name="LastName">Bar</SubProperty > 
    </Property> 
</Properties> 

Все, что я что извлечь свойства/субсвойство, определенное в шаблоне, чтобы создать новый файл XML, с подсоединенными всеми значениями, что-то вроде

<Items> 
    <ID>10000</ID> 
    <Name> 
    <FirstName>Foo</FirstName> 
    <LastName>Bar</LastName> 
    </Name> 
</Items> 

Поскольку я не знаю, содержания шаблона во время разработки, я попытался загрузить его и создал класс List, использующий LINQ, но не могу получить результат выше, когда его сериализуют напрямую. Поэтому вместо создания класса List я создал динамический объект, используя Reflection.Emit, а затем сериализую объект в XML.


private static readonly XDocument doc = XDocument.Load("Template.xml"); 

static void Main(string[] args) { 
    var newType = CreateDynamicType(); 
    var newObject = Activator.CreateInstance(newType); 
    var properties = newType.GetProperties(); 
    foreach (var property in properties) { 
     // assign values 
    } 
    SerializeToXml(newObject); 
} 

private static Type CreateDynamicType() { 

    AssemblyName assemblyName = new AssemblyName() { Name = "DynamicTypeAdapter" }; 
    AssemblyBuilder assembly = 
     Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); 
    ModuleBuilder module = 
     assembly.DefineDynamicModule(assembly.GetName().Name, false); 
    TypeBuilder type = module.DefineType("Items", TypeAttributes.Public | TypeAttributes.Class); 

    foreach (var p in doc.Descendants("Property")) { 
     string pName = p.Attribute("name").Value; 
     TypeBuilder subType = module.DefineType(pName, TypeAttributes.Public | TypeAttributes.Class); 
     foreach (var sp in p.Descendants("SubProperty")) { 
      CreateDynamicProperty(subType, sp.Attribute("name").Value, typeof(string)); 
     } 
     var propertyType = subType.CreateType(); 
     CreateDynamicProperty(type, pName, propertyType); 
    } 

    return type.CreateType(); 
} 

private static void CreateDynamicProperty(TypeBuilder typeBuilder, string propertyName, Type propertyType) { 
    PropertyBuilder property = typeBuilder.DefineProperty(propertyName, 
    PropertyAttributes.None, propertyType, new Type[] { typeof(string) }); 

    FieldBuilder field = typeBuilder.DefineField("_" + propertyName, propertyType, FieldAttributes.Private); 

    MethodAttributes GetSetAttributes = MethodAttributes.Public | MethodAttributes.HideBySig; 

    MethodBuilder getMethod = 
     typeBuilder.DefineMethod("get_value", GetSetAttributes, propertyType, Type.EmptyTypes); 

    ILGenerator getIL = getMethod.GetILGenerator(); 
    getIL.Emit(OpCodes.Ldarg_0); 
    getIL.Emit(OpCodes.Ldfld, field); 
    getIL.Emit(OpCodes.Ret); 

    MethodBuilder setMethod = 
      typeBuilder.DefineMethod("set_value", GetSetAttributes, null, new Type[] { typeof(string) }); 

    ILGenerator setIL = setMethod.GetILGenerator(); 
    setIL.Emit(OpCodes.Ldarg_0); 
    setIL.Emit(OpCodes.Ldarg_1); 
    setIL.Emit(OpCodes.Stfld, field); 
    setIL.Emit(OpCodes.Ret); 

    property.SetGetMethod(getMethod); 
    property.SetSetMethod(setMethod); 
} 

Он отлично работает, но есть ли простой способ сделать это? Любые комментарии приветствуются. Спасибо

+0

Вы представили проблему, и некоторые примеры XM L, но мне все еще трудно понять, что делает ваш код. Не могли бы вы разместить пример кода, который у вас есть? – jrista

+0

Спасибо за ваш комментарий. Я изменил содержание, извините за грязный код. – Gnavvy

ответ

2

Если все, что вы хотите изменить (преобразовать) один формат XML в другой формат XML, я думаю, что подход, который вы принимаете, не является наиболее подходящим. В инфраструктуре есть другие API-интерфейсы, поддерживающие такую ​​функциональность. В вашем случае требование кажется довольно простым, поэтому я бы выбрал опцию Linq To Xml. Ниже приведен краткий пример, который дает желаемый результат.

XDocument doc = XDocument.Parse(@"<Properties> 
       <Property name='ID'>10000</Property> 
       <Property name='Name'> 
        <SubProperty name='FirstName'>Foo</SubProperty> 
        <SubProperty name='LastName'>Bar</SubProperty> 
       </Property> 
      </Properties>"); 

XElement items = new XElement("Items", 
           from property in doc.Descendants("Property") 
           select new XElement((string)property.Attribute("name"), 
                // If there are no child elements (SubPropety) 
                // get the property value 
                property.HasElements ? null : (string)property, 
                // Another way for checking if there are any child elements 
                // You could also use property.HasElements like the previous statement 
                property.Elements("SubProperty").Any() ? 
                from subproperty in property.Elements("SubProperty") 
                select new XElement((string)subproperty.Attribute("name"), 
                     (string)subproperty) : null) 

         ); 

Несколько ресы, которые могут быть полезны, включают:

http://msdn.microsoft.com/en-us/library/bb387098.aspx

http://msdn.microsoft.com/en-us/library/bb308960.aspx

http://iqueryable.com/2007/08/03/TransformingXMLWithLINQToXML.aspx

http://www.codeproject.com/KB/linq/LINQtoXML.aspx

+0

Большое спасибо за решение. – Gnavvy

1

Основываясь на том, что у вас есть, что-то простое, как это должно работать.

var root = XElement.Parse(xml); 
var result = new XElement("Items"); 
foreach (var p in root.Descendants("Property")) 
{ 
var subs = p.Descendants("SubProperty").Select(sp => Transpose(sp)); 

    // The trick is here - XElement constructor uses params object[], 
    // so we can pass an arbitrary number of arguments to build the XElement 
var item = new XElement(p.Attribute("name").Value, subs, subs.Any() : null ? p.Value); 

    result.Add(item); 
} 

// Transpose method 
XElement Transpose(XElement xe) 
{ 
return new XElement(xe.Attribute("name").Value, xe.Value); 
} 


// result 
<Items> 
    <ID>10000</ID> 
    <Name> 
    <FirstName>Foo</FirstName> 
    <LastName>Bar</LastName> 
    </Name> 
</Items> 

ПРИМЕЧАНИЕ: Если у вас есть несколько уровней вложенности, или нужно, чтобы иметь возможность различать несколько Item узлов в шаблоне, вы должны думать об этом еще.

+0

Спасибо Winston, отличная помощь – Gnavvy

 Смежные вопросы

  • Нет связанных вопросов^_^