2011-06-09 14 views
9

Potrzebuję parsować plik XML, który otrzymuję od strony trzeciej do obiektów C#. Niektóre z otrzymywanych XML mają wartości wyliczeniowe, które chcę przechowywać w typie wyliczeniowym.Mapowanie wartości xml do typu wyliczeniowego

Na przykład, mam następujące XSD pliku XML:

<xsd:simpleType name="brandstof"> 
    <xsd:restriction base="xsd:string"> 
    <!-- Benzine --> 
    <xsd:enumeration value="B" /> 
    <!-- Diesel --> 
    <xsd:enumeration value="D" /> 
    <!-- LPG/Gas --> 
    <xsd:enumeration value="L" /> 
    <!-- LPG G3 --> 
    <xsd:enumeration value="3" /> 
    <!-- Elektrisch --> 
    <xsd:enumeration value="E" /> 
    <!-- Hybride --> 
    <xsd:enumeration value="H" /> 
    <!-- Cryogeen --> 
    <xsd:enumeration value="C" /> 
    <!-- Overig --> 
    <xsd:enumeration value="O" /> 
    </xsd:restriction> 
</xsd:simpleType> 

chcę map to do wyliczenia i mam tak daleko:

public enum Fuel 
{ 
    B, 
    D, 
    L, 
    E, 
    H, 
    C, 
    O 
} 

Problem jest to, że xml może zawierać wartość 3, której nie mogę wstawić do typu wyliczeniowego. Czy istnieje jakieś rozwiązanie, aby umieścić tę wartość w wyliczeniu.

Też mogę uzyskać inne wartości z - lub / w nich i które chcę umieścić w rodzaju wyliczenia.
Sugestie Anu są mile widziane!

+0

ja poniższy link i uważam, że warto. [W języku C#, deserializacja wartości liczb całkowitych.] (Http://stackoverflow.com/questions/9944421/c-sharp-deserializing-enums-from-integers/33387055#33387055) –

Odpowiedz

15

Można analizować wartość atrybutu xml z powrotem do typu enum z:

var value = Enum.Parse(typeof(Fuel), "B"); 

Ale nie sądzę, będzie można dostać naprawdę daleko ze swoimi „specjalnych” wartości (3, a/ itd.). Dlaczego nie można zdefiniować enum jako

enum Fuel 
{ 
    Benzine, 
    Diesel, 
    // ... 
    Three, 
    ASlash, 
    // ... 
} 

i napisać statycznej metody konwersji ciąg do elementu enum?

Jedną z rzeczy, które można rozważyć przy wdrażaniu takiej metody, byłoby dodanie niestandardowych atrybutów do elementów wyliczających zawierających ich reprezentację ciągów - jeśli wartość nie ma dokładnego odpowiednika w wyliczeniu, poszukaj członka z atrybut.

Stworzenie takiego atrybutu jest proste:

/// <summary> 
/// Simple attribute class for storing String Values 
/// </summary> 
public class StringValueAttribute : Attribute 
{ 
    public string Value { get; private set; } 

    public StringValueAttribute(string value) 
    { 
     Value = value; 
    } 
} 

a następnie można wykorzystać je w swojej ENUM:

enum Fuel 
{ 
    [StringValue("B")]   
    Benzine, 
    [StringValue("D")] 
    Diesel, 
    // ... 
    [StringValue("3")] 
    Three, 
    [StringValue("/")] 
    Slash, 
    // ... 
} 

Te dwie metody pomogą Ci analizować ciąg na członka enum twojego wybór:

/// <summary> 
    /// Parses the supplied enum and string value to find an associated enum value (case sensitive). 
    /// </summary> 
    public static object Parse(Type type, string stringValue) 
    { 
     return Parse(type, stringValue, false); 
    } 

    /// <summary> 
    /// Parses the supplied enum and string value to find an associated enum value. 
    /// </summary> 
    public static object Parse(Type type, string stringValue, bool ignoreCase) 
    { 
     object output = null; 
     string enumStringValue = null; 

     if (!type.IsEnum) 
     { 
      throw new ArgumentException(String.Format("Supplied type must be an Enum. Type was {0}", type)); 
     } 

     //Look for our string value associated with fields in this enum 
     foreach (FieldInfo fi in type.GetFields()) 
     { 
      //Check for our custom attribute 
      var attrs = fi.GetCustomAttributes(typeof (StringValueAttribute), false) as StringValueAttribute[]; 
      if (attrs != null && attrs.Length > 0) 
      { 
       enumStringValue = attrs[0].Value; 
      }      

      //Check for equality then select actual enum value. 
      if (string.Compare(enumStringValue, stringValue, ignoreCase) == 0) 
      { 
       output = Enum.Parse(type, fi.Name); 
       break; 
      } 
     } 

     return output; 
    } 

A gdy jestem w nim: tutaj jest na odwrót;)

/// <summary> 
    /// Gets a string value for a particular enum value. 
    /// </summary> 
    public static string GetStringValue(Enum value) 
    { 
     string output = null; 
     Type type = value.GetType(); 

     if (StringValues.ContainsKey(value)) 
     { 
      output = ((StringValueAttribute) StringValues[value]).Value; 
     } 
     else 
     { 
      //Look for our 'StringValueAttribute' in the field's custom attributes 
      FieldInfo fi = type.GetField(value.ToString()); 
      var attributes = fi.GetCustomAttributes(typeof(StringValueAttribute), false); 
      if (attributes.Length > 0) 
      { 
       var attribute = (StringValueAttribute) attributes[0]; 
       StringValues.Add(value, attribute); 
       output = attribute.Value; 
      } 

     } 
     return output; 

    } 
+2

Problem polega na odwzorowywaniu niestandardowych wartości wyliczeniowych (jak "3"). –

+0

Dzięki za odpowiedź. Wypróbuję to i skontaktuję się z Tobą! – Gerard

+1

Zadziałało, dziękuję za dokładną odpowiedź! – Gerard

0

stworzyłem klasę, która obsługuje to:

class EnumCreator 
    { 
     public static Type CreateEnum(List<string> AValues) 
     { 
      // Get the current application domain for the current thread. 
      AppDomain currentDomain = AppDomain.CurrentDomain; 

      // Create a dynamic assembly in the current application domain, 
      // and allow it to be executed and saved to disk. 
      AssemblyName aName = new AssemblyName("TempAssembly"); 
      AssemblyBuilder ab = currentDomain.DefineDynamicAssembly(
       aName, AssemblyBuilderAccess.RunAndSave); 

      // Define a dynamic module in "TempAssembly" assembly. For a single- 
      // module assembly, the module has the same name as the assembly. 
      ModuleBuilder mb = ab.DefineDynamicModule(aName.Name, aName.Name + ".dll");  

      // Define a public enumeration with the name "Elevation" and an 
      // underlying type of Integer. 
      EnumBuilder eb = mb.DefineEnum("EnumValues", TypeAttributes.Public, typeof(int)); 

      // Define two members, "High" and "Low". 
      foreach (string v in AValues) 
      { 
       eb.DefineLiteral(v, AValues.IndexOf(v)); 
      } 

      // Create the type and save the assembly. 
      Type finished = eb.CreateType(); 

      return finished; 
     } 
    } 

Trzeba najpierw do odczytu pliku XML i umieścić wartości na liście, można to zrobić z obiektem Xelement na przykład.

// Edit: Jak to:

XElement xml = XElement.parse("file.xml"); 
List<string> enumItems = new List<string>(); 

foreach(XElement row in xml.Element("xsd:simpleType").Element("xsd:restriction").Elements()) 
{ 
    enumItems.Add(row.Attribute("value").Value); 
} 

Type Fuel = EnumCreator.CreatEnum(enumItems); 
+0

czekaj, to nie był problem. Nie działa @? jak @ 3, @/itd. wiem, że działa ze słowami kluczowymi, takimi jak int i double. – hcb

3

Dlaczego nie można analizować ciąg

[XmlAttribute("brandstof")] 
public string FuelTypeString 
{ 
    get { return fuel.ToString(); } 
    set 
    { 
     fuel = (Fuel)System.Enum.Parse(typeof(Fuel), value); 
    } 
} 
[XmlIgnore()] 
public Fuel FuelType 
{ 
    get { return fuel; } 
    set { fuel = value; } 
} 

Więc naprawdę szeregować je jako ciąg znaków.

11

Udekoruj z atrybutem XmlEnum: http://msdn.microsoft.com/en-us/library/system.xml.serialization.xmlenumattribute.aspx

public enum Fuel 
{ 
    [XmlEnum("B")] 
    Benzine, 
    [XmlEnum("D")] 
    Diesel, 
    [XmlEnum("L")] 
    LpgGas, 
    [XmlEnum("3")] 
    LpgG3, 
    [XmlEnum("E")] 
    Elektrisch, 
    [XmlEnum("H")] 
    Hybride, 
    [XmlEnum("C")] 
    Cryogeen, 
    [XmlEnum("O")] 
    Overig 
} 
+2

Rozdzieram głowę, aby zrozumieć, dlaczego nie mogłem oznaczyć pól zajęć jako [XmlEnum] w końcu znalazłem twoją odpowiedź i uratowałem sobie resztę moich włosów. wszystkie inne alternatywy są "brudne", jeśli mnie pytasz –

Powiązane problemy