IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Dotnet Discussion :

XSD / XML : string vers XmlEnumAttribute


Sujet :

Dotnet

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Modérateur

    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Avril 2007
    Messages
    1 996
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Chef de projet NTIC
    Secteur : Service public

    Informations forums :
    Inscription : Avril 2007
    Messages : 1 996
    Par défaut XSD / XML : string vers XmlEnumAttribute
    Bonjour à tous,

    Je suis bloqué sur un problème que je ne parviens pas à résoudre. Je fais donc appel à vous :

    J'ai généré un classe à partir d'une XSD via xsd.exe.
    La XSD contient des listes transformées en énumérations de ce type :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Xml", "4.6.1087.0")]
        [System.SerializableAttribute()]
        public enum BlocsListe
        {
            /// <remarks/>
            [System.Xml.Serialization.XmlEnumAttribute("2 blocs")]
            Item2blocs,
            /// <remarks/>
            [System.Xml.Serialization.XmlEnumAttribute("4 blocs")]
            Item4blocs,
            /// <remarks/>
            ND,
        }
    La property qui utilise cette énumération :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    private BlocsListe _typeBlocs;
    [System.Xml.Serialization.XmlElementAttribute(Form = System.Xml.Schema.XmlSchemaForm.Unqualified)]
            public BlocsListe TypeBlocs
            {
                get
                {
                    return this._typeBlocs;
                }
                set
                {
                    this._typeBlocs = value;
                }
            }
    J'extraie des éléments de ma base de données via un DataReader et j'essaye ensuite d'affecter la valeur contenue en base de données à la propriété TypeBlocs de mon objet.

    Et c'est là que je suis bloqué.
    En base de données, c'est le contenu du XmlEnumAttribute qui est stocké.
    J'ai donc des cas où je n'ai pas de valeurs en base de données, d'autre où j'ai bien une valeur correspondant à un item de l'énumération et des cas où la valeur stockée dans la base ne correspond à aucun item de l'énumération.

    Je cherche à parser le contenu de mon DataReader pour trouver la correspondance avec un des XmlEnumAttribute pour ensuite affecter ma propriété.
    Et je bloque sur ce point.

    Pour simplifier la chose, certaines autres énumérations ne contiennent pas de XmlEnumAttribute (cf. le "ND" de l'énumération ci-dessus).

    Si vous avez des conseils, je suis preneur.

    Merci d'avance

  2. #2
    Expert confirmé

    Avatar de François DORIN
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Juillet 2016
    Messages
    2 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2016
    Messages : 2 761
    Billets dans le blog
    21
    Par défaut
    Bonjour,

    Voici l'approche que je suivrais :
    1. Créer un Dictionary<string, BlocsList> permettant de faire le mapping entre les valeurs stockées en BD et l'énumération ;
    2. Utiliser le mapping


    Pour créer le mapping, il faut utiliser la réflexion :
    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
    Dictionary<string, BlocsList> mapping = new Dictionary<string, BlocsList>;
    Type type = typeof(BlocsList);
     
    foreach(BlocsList b in Enum.GetValues(typeof(BlocsList)))
    {
       MemberInfo[] memberInfo = type.GetMember(b.ToString());
       object[] attributes = memberInfo [0].GetCustomAttributes(typeof(System.Xml.Serialization.XmlEnumAttribute), false);
     
       if (attributes.Length == 1) 
       {
          System.Xml.Serialization.XmlEnumAttribute attribute = attributes[0] as System.Xml.Serialization.XmlEnumAttribute;
          mapping.Add(attribute.Name, b);
       }
       else 
       {
          mapping.Add(b.ToString(), b);
       }
     
    }

    Via un foreach, on parcourt l'ensemble des valeurs de l'énumération. Pour chaque valeur, on essaie, via la réflexion, d'accéder à l'attribut XmlEnumAttribute. S'il existe, on utilise la valeur de cette attribut pour ajouter une clé dans le dictionnaire de mapping. Sinon, on utilise la valeur de l'énum.

    PS : code pas testé, donc potentiellement avec des coquilles

  3. #3
    Modérateur

    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Avril 2007
    Messages
    1 996
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Chef de projet NTIC
    Secteur : Service public

    Informations forums :
    Inscription : Avril 2007
    Messages : 1 996
    Par défaut
    François,
    merci pour cette réponse.

    En adaptant le code pour le factoriser et le rendre utilisable avec toutes mes Enum, en effet, cela fait quasiment ce dont j'ai besoin :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    public static Dictionary<string,T> CheckEnumValue<T>(string value)
            {
                Dictionary<string,T> DicEnum = new Dictionary<string, T>();
                if (!string.IsNullOrEmpty(value))
                {
                    Type type = typeof(T);
                    MemberInfo[] memberInfo;
     
                    foreach (T b in Enum.GetValues(typeof(T)))
                    {
                        memberInfo = type.GetMember(b.ToString());
                        object[] attributes = memberInfo[0].GetCustomAttributes(typeof(System.Xml.Serialization.XmlEnumAttribute), false);
     
                        if (attributes.Length == 1)
                        {
                            XmlEnumAttribute attribute = attributes[0] as System.Xml.Serialization.XmlEnumAttribute;
                            if (attribute != null && !string.IsNullOrEmpty(attribute.Name) && attribute.Name.Equals(value))
                                DicEnum.Add(attribute.Name, b);                            
                        }
                        else
                        {
                            if (b.ToString().Equals(value))
                                DicEnum.Add(b.ToString(), b);
                        }
                    }
                    return DicEnum;
                }
                return null;
            }
    Maintenant, il va falloir gérer l'appel sur la totalité des Enums concernées... Galère en perspective, il y en a plus de 200.

    Et désormais, je galère sur la factorisation de l'appel.
    Il faut que je fasse ceci, pour les 200 Enums :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
                         Dictionary<string, BlocsListe> dicEnum = CheckEnumValue<BlocsListe>(rd["BLOC"].ToString());
                                    if (dicEnum != null && dicEnum.Count() > 0)
                                    {
                                        monObjet.TypeBloc = dicEnum[rd["BLOC"].ToString()];
                                        monObjet.TypeBlocSpecified = true;
                                    }
                                    else
                                        monObjet.TypeBlocSpecified = false;
    J'aimerais factoriser le tout dans une méthode qui ferait cette opération en prenant en paramètres la valeur du DataReader et les propriétés à assigner.
    Ca me paraît un peu compliqué cette histoire.

  4. #4
    Modérateur

    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Avril 2007
    Messages
    1 996
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Chef de projet NTIC
    Secteur : Service public

    Informations forums :
    Inscription : Avril 2007
    Messages : 1 996
    Par défaut
    Je m'auto-répond avec une solution qui ne me convient qu'à moitié :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public static void SetEnumField<E,T>(string drValue, T target, string outExpr, string outExprSpecified)
            {
                Dictionary<string, E> dicEnum = CheckEnumValue<E>(drValue);
     
                if (dicEnum != null && dicEnum.Count() > 0)
                {
                    var prop = target.GetType().GetProperty(outExpr);
                    prop.SetValue(target, dicEnum[drValue], null);
     
                    prop = target.GetType().GetProperty(outExprSpecified);
                    prop.SetValue(target, true, null);
                }
                else
                {
                    if (outExprSpecified != null)
                    {
                        var prop = target.GetType().GetProperty(outExprSpecified);
                        prop.SetValue(target, false, null);
                    }
                }
            }
    et l'appel :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SetEnumField<BlocsListe, monObjet>(rd["BLOC"].ToString(), monObjet, "TypeBloc", "TypeBlocSpecified");
    via la Reflection, je parviens à affecter les propriétés de mon objet.
    Seulement, ça m'embête de les passer à ma méthode SetEnumField via le nom de la propriété sous forme de string car en cas de changement du nom de la propriété, je devrais la changer manuellement.

    Si vous avez une solution plus adaptée, je suis vraiment preneur.

  5. #5
    Expert confirmé

    Avatar de François DORIN
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Juillet 2016
    Messages
    2 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2016
    Messages : 2 761
    Billets dans le blog
    21
    Par défaut
    Citation Envoyé par calagan99 Voir le message
    Seulement, ça m'embête de les passer à ma méthode SetEnumField via le nom de la propriété sous forme de string car en cas de changement du nom de la propriété, je devrais la changer manuellement.

    Si vous avez une solution plus adaptée, je suis vraiment preneur.
    Oui ! l'opérateur nameof est justement fait pour ça

    Code C# : Sélectionner tout - Visualiser dans une fenêtre à part
    SetEnumField<BlocsListe, monObjet>(rd["BLOC"].ToString(), monObjet, nameof(monObjet.TypeBloc), nameof(monObjet.TypeBlocSpecified));

    Ensuite, il y a une possibilité d'amélioration. Ici, le dictionnaire est créé à chaque fois lors d'un appel à CheckEnumValue. On peut éventuellement penser à faire une mise en cache (par exemple, CheckEnumValue étant statique, elle peut être définie dans une classe statique avec un constructeur statique s'occupant d'initialiser les dictionnaires pour toutes les énumérations). Ce n'est pas une obligation, mais si tu rencontres des problèmes de performance, tu peux déjà agir là-dessus. La réflexion est connue pour ne pas être très rapide...

  6. #6
    Modérateur

    Homme Profil pro
    Chef de projet NTIC
    Inscrit en
    Avril 2007
    Messages
    1 996
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Chef de projet NTIC
    Secteur : Service public

    Informations forums :
    Inscription : Avril 2007
    Messages : 1 996
    Par défaut
    Effectivement, un simple nameof.
    Je n'y avais pas pensé.
    Merci.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [Débutant] convertir .xls vers .xsd/xml 2013
    Par grisan29 dans le forum VB.NET
    Réponses: 7
    Dernier message: 25/08/2015, 12h56
  2. String vers un xml
    Par nadou114 dans le forum Android
    Réponses: 1
    Dernier message: 11/04/2011, 14h39
  3. Valider un XML string avec XSD
    Par ForumsGalaxy dans le forum Général Dotnet
    Réponses: 1
    Dernier message: 26/10/2010, 13h54
  4. [XSD] XML Schema
    Par sleepy2002 dans le forum Valider
    Réponses: 3
    Dernier message: 15/09/2003, 09h33

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo