2010-07-16 2 views
1

문제가 발생하여 해결 방법이 간단한 지 궁금합니다.리스트 <string>을 직렬화하고 각 문자열을 xml 노드로 사용하십시오.

여기 몇 가지 속성과 값을 정의하는 XML 템플릿이 있습니다. 나는이 내용을 알 수 없기 때문에

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

같은

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

모든

은 모든 값이 부착과 함께, 새로운 XML 파일을 생성 템플릿에 정의 된 속성/하위 속성을 추출하는 것입니다 내가 뭔가 템플릿을 디자인 타임에로드하려고 시도하고 LINQ를 사용하는 List 클래스를 만들었지 만 직접 직렬화 할 때 위 결과를 얻을 수 없습니다. 따라서 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) 

         ); 

몇 resouces은 다음과 같습니다

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