Сопоставление XML значений типа перечисление



Мне нужно разобрать XML-файл, который я получаю от сторонних объектов C#.
Некоторые из XML, которые я получаю, имеют значения перечисления, которые я хочу сохранить в типе enum.



Например, у меня есть следующий xsd 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>


Я хочу сопоставить это с перечислением, и я дошел до этого:



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


Проблема у меня заключается в том, что XML может содержать значение 3, который я не могу показаться, чтобы положить в перечислимый тип. Есть ли какое-либо решение, чтобы поместить это значение в перечисление.



Я также могу получить другие значения с - или / в них и которые я хочу поместить в тип enum.

Предложения Ану приветствуются!

783   4  

4 ответов:

Вы можете проанализировать значение атрибута xml обратно в тип enum с помощью:

var value = Enum.Parse(typeof(Fuel), "B");
Но я не думаю, что вы далеко продвинетесь со своими "особыми" ценностями.(3, a/ и т.д.). Почему бы вам не определить свое перечисление как
enum Fuel
{
    Benzine,
    Diesel,
    // ...
    Three,
    ASlash,
    // ...
}

И написать статический метод для преобразования строки в элемент перечисления?

Одна вещь, которую вы могли бы рассмотреть для реализации такого метода, состояла бы в добавлении пользовательских атрибутов к элементам перечисления, содержащим их строковое представление - если значение не имеет точного аналогично в перечислении найдите элемент с атрибутом.

Создать такой атрибут несложно:

/// <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;
    }
}

И затем вы можете использовать их в своем перечислении:

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

Эти два метода помогут вам разобрать строку на элемент enum по вашему выбору:

    /// <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;
    }

И раз уж я об этом: здесь все наоборот;)

    /// <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;

    }

Украсьте атрибутом 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
}

Почему вы не можете разобрать строку

[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; }
}

Таким образом, вы действительно сериализуете его как строку.

Я создал класс, который обрабатывает это:

    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;
        }
    }

Вы должны сначала прочитать xml-файл и поместить значения в список, вы можете сделать это, например, с объектом XElement.

/ / править: Вот так:

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);

Comments

    Ничего не найдено.