Partage
  • Partager sur Facebook
  • Partager sur Twitter

XML encapsulé dans du XML

    8 janvier 2018 à 16:19:03

    Bonjour à tous,

    J'ai un souci de récupération de données XML.

    En effet, ma base de données (que je ne maîtrise pas) stocke des informations en XML. Les informations sur lesquelles je dois travailler sont "encapsulées" dans ce XML, toujours au format XML.

    J'ai "décode" le XML afin de le rendre consultable et "propre", à savoir que tous les termes non gérés (&lt, &gt ...) ont été "convertis" part la méthode HttpUtility.HtmlDecode().

    Voici mon code : 

    protected void Page_Load(object sender, EventArgs e)
            {
                try
                {
                    SqlCommand cmd = new SqlCommand(query, connection);
                    connection.Open();
    
                    SqlDataReader sdr = cmd.ExecuteReader();
    
                    XmlDocument doc = new XmlDocument();
    
                    if(sdr.HasRows)
                    {
                        while(sdr.Read())
                        {
                            string content = sdr["Content"].ToString();
                            System.Diagnostics.Debug.WriteLine(System.Web.HttpUtility.HtmlDecode(content));
    
                            // Test Decode
                            string contenu = System.Web.HttpUtility.HtmlDecode(content);
    
                            doc.Load(contenu);
    
                            XmlNamespaceManager ns = new XmlNamespaceManager(doc.NameTable);
                            ns.AddNamespace("msbld", "http://schemas.microsoft.com/developer/msbuild/2003");
                            XmlNode FormId;                        
                            FormId = doc.SelectSingleNode("descendant::StorageObject/Properties/Property/Template/Property[attribute::Name='FormId']", ns);
                            System.Diagnostics.Debug.WriteLine(FormId.OuterXml);
                        }
                    }                
                }
                finally
                {
                    connection.Close();
                }            
            }

    Je me teste sur le XPATH, afin de naviguer dans les noeuds, pour apprendre à le maîtriser, mais j'ai un message d'erreur : 

    Je ne sais pas si c'est mon code qui ne va pas ( problème avec le "doc" ?), ou si c'est l'encapsulation qui pose problème.

    Voici l'encapsulation en question (je ne vous mets pa tout le code, car il est très long) : 

    <Root>
      <StorageObject Name="OI-GENOUILLERE ODRA-v2" Id="0108f7ac-7853-4543-8ec4-a04cb755ed46" Type="Adviser.Proteor.Library.TemplateImpl">
        <Properties>
          <Property Name="TimeCreated" Value="27/07/2017 11:14:18" /><Property Name="Enabled" Value="True" /><Property Name="TimePublished" Value="01/01/0001 00:00:00" /><Property Name="TimeLastModified" Value="10/11/2017 09:09:29" /><Property Name="Description" Value="" /><Property Name="ObjectContent" Value=""<Template>
            <Component Type="Adviser.Proteor.Library.TemplateImpl">
              <ExtendedProperty Text="OI" Key="Classification" />
              <ExtendedProperty Text="35176af2-b664-42d6-a7ba-5d06602b0500" Key="ClassificationId" />
              <ExtendedProperty Text="GAO" Key="Activity" />
              <ExtendedProperty Text="58d942ea-8cf7-4089-879c-f8633925473b" Key="ActivityId" />
              <ExtendedProperty Text="OI 36" Key="AnatomicalLevel" />
              <ExtendedProperty Text="76418da5-6830-4a49-aed0-b472c11c67c6" Key="AnatomicalLevelId" />
              <ExtendedProperty Text="ORTHESE INF." Key="Type" />
              <ExtendedProperty Text="13b33a27-57ce-4009-8812-00f8578982fd" Key="TypeId" />
              <Version Version.Major="0" Version.Minor="1" />

    à partir de la balise <Property Name="ObjectConten">, la balise n'est pas fermée après le Value, et ensuite ça repart sur une autre balise (d'où l'encapsulation).

    Need help !!!!




    -
    Edité par ClémentPraudel1 8 janvier 2018 à 16:20:13

    • Partager sur Facebook
    • Partager sur Twitter
      8 janvier 2018 à 16:31:16

      XmlDocument.Load attend un chemin de fichier et toi tu lui donnes le "contenu du fichier" du coup dans ce texte y'a des caractères interdits pour un chemin de fichier et il aime pas ça.

      A priori c'est plutôt XmlDocument.LoadXml qu'il te faudrait

      • Partager sur Facebook
      • Partager sur Twitter
      Censément, quelqu'un de sensé est censé s'exprimer sensément.
        8 janvier 2018 à 16:45:53

        C'est vrai que j'ai vu beaucoup de tuto sur le net, mais qui concernait, en effet, des fichiers XML, et non un contenu en XML.

        Forcément, un bug en amenant un autre, j'ai une autre erreur, mais cette fois sur une valeur hexadécimale : 

        Je ne comprends pas trop car le HtmlDecode est censé rendre tout ça propre, alors comment une ouverture de balise ("<") peut faire bugger ?

        • Partager sur Facebook
        • Partager sur Twitter
          8 janvier 2018 à 17:31:37

          Salut,

          Apparemment (https://www.codeproject.com/Questions/784797/hexadecimal-value-x-C-is-an-invalid-attribute-char) les chevrons sont réservés aux balises, donc interdit d'en avoir dans les attributs.

          Les &lt et &gt n'étaient pas là pour rien j'ai l'impression (voir lien).

          -
          Edité par Stormweaker 8 janvier 2018 à 17:31:57

          • Partager sur Facebook
          • Partager sur Twitter
            9 janvier 2018 à 9:15:36

            Donc, le problème vient de l'encapsulation d'XML dans du XML ? 

            Dans le bout de code XML que j'ai posté plus haut (ligne 4, en fin de ligne), on voit que l'attribut se termine par "", et redémarre par la balise template. D'où l'encapsulation.

            De ce fait, je ne pourrais jamais faire d'XPATH dessus ? Ou faut-il que split le contenu pour ne travailler uniquement QUE que la partie encapsulée ?

            • Partager sur Facebook
            • Partager sur Twitter
              9 janvier 2018 à 10:03:31

              C'est à cause de la ligne suivante que tu dis que c'est du XML dans du XML ?

              <Property Name="ObjectContent" Value=""<Template>

              Je ne suis pas un expert en XML mais pour moi c'est juste une erreur, il manquerait juste /> pour fermer la balise Property.

              Est-ce que tes données sont fiables à 100%? Tu es le seul à l'utiliser ou est-ce que d'autres s'en servent sans soucis?

              • Partager sur Facebook
              • Partager sur Twitter
                9 janvier 2018 à 10:42:29

                La donnée est créée par un logiciel qui est utilisé par l'entreprise ou je fais mon stage à l'heure actuelle.

                C'est un prestataire qui a monté tout ça. Je suis juste là pour essayer de lister des données venant de cette base, en naviguant dans ce xml.

                Avant d'appeler le prestataire pour savoir ce qu'il en est, j'ai réussi à isoler les balises et valeurs contenues entre les deux balises <Template></Template>

                Le HTMLDecode a bien fait son travail sur le contenu de la chaine de caractere.

                Mais je n'arrive pas à afficher les valeurs des attributs dans un gridview par exemple, ou stocker ces valeurs dans des string.

                EDIT : 

                J'ai utilisé XmlDocument pour essayer de récupérer les valeurs d'un attribut, mais rien n'apparaît à l'écran. Mon code : 

                protected void Page_Load(object sender, EventArgs e)
                        {
                            try
                            {
                                string query = "SELECT Content From Template WHERE Id = '0108f7ac-7853-4543-8ec4-a04cb755ed46' AND Deleted = '0'";
                                SqlCommand cmd = new SqlCommand(query, connection);
                                connection.Open();
                                sdr = cmd.ExecuteReader();
                                XmlDocument doc = new XmlDocument();
                
                                if(sdr.HasRows)
                                {
                
                                    DataTable dt = new DataTable();
                                    dt.Columns.Add("test", typeof(XmlNode));
                
                                    while (sdr.Read())
                                    {
                
                                        RecupContenu();
                
                
                
                                        System.Diagnostics.Debug.WriteLine(System.Web.HttpUtility.HtmlDecode(RecupContenu()));
                
                                        // Test Decode
                                        string contenu = System.Web.HttpUtility.HtmlDecode(RecupContenu());
                
                                        doc.LoadXml(contenu);
                
                                        XmlNamespaceManager ns = new XmlNamespaceManager(doc.NameTable);
                                        ns.AddNamespace("msbld", "http://schemas.microsoft.com/developer/msbuild/2003");
                                        XmlElement root = doc.DocumentElement;
                
                                        if(root.HasAttribute("Name"))
                                        {
                                            string FormId = root.GetAttribute("Name");
                                            System.Diagnostics.Debug.WriteLine("[-- TEST --] : " + FormId);
                                            dt.Rows.Add(FormId);
                                            test.DataSource = dt;
                                            test.DataBind();
                                        }
                                        
                                        
                                    }
                                }
                
                                
                            }
                            finally
                            {
                                connection.Close();
                            }            



                -
                Edité par ClémentPraudel1 9 janvier 2018 à 11:00:35

                • Partager sur Facebook
                • Partager sur Twitter
                  9 janvier 2018 à 11:57:35

                  Tu dis que rien n'apparaît, mais où? dans l'application, dans la fenêtre de sortie, autre part?

                  Que dis le debuger? Est-ce que la condition du if est bien remplie?

                  Mais sinon quel est ton but? Comprendre comment sont organisées les données ? Afficher certains éléments?

                  • Partager sur Facebook
                  • Partager sur Twitter
                    9 janvier 2018 à 12:07:12

                    Il y a un attribut Name="FormId" qui comprend une valeur (value), et cette valeur, je souhaite la récupérer pour l'afficher dans une application web.

                    Voici l'une des balises concernées : 

                    <Property Name="FormId" Value="97d86ced-6d8c-4846-bf38-e9e715ac4818" />

                    Il y en a plusieurs dans à sortir à chaque fois.

                    EDIT : 

                    Rien ne s'affiche dans mon gridview, avec le Xpath suivant : 

                    try
                                {
                                    string query = "SELECT Content From Template WHERE Id = '0108f7ac-7853-4543-8ec4-a04cb755ed46' AND Deleted = '0'";
                                    SqlCommand cmd = new SqlCommand(query, connection);
                                    connection.Open();
                                    sdr = cmd.ExecuteReader();
                                    XmlDocument doc = new XmlDocument();
                    
                                    if(sdr.HasRows)
                                    {
                    
                                        DataTable dt = new DataTable();
                                        dt.Columns.Add("test", typeof(string));
                    
                                        while (sdr.Read())
                                        {
                    
                                            RecupContenu();
                    
                    
                    
                                            System.Diagnostics.Debug.WriteLine(System.Web.HttpUtility.HtmlDecode(RecupContenu()));
                    
                                            string contenu = System.Web.HttpUtility.HtmlDecode(RecupContenu());
                    
                                            doc.LoadXml(contenu);
                    
                                            System.Diagnostics.Debug.WriteLine("[-- CONTENU --] --> : " + contenu);
                    
                                            var nodes = doc.SelectNodes("//Template/Component/Properties/Property[@Name='FormId']");
                    
                                            foreach (XmlElement node in nodes)
                                            {
                                                string attributeValue = node.GetAttribute("Value");
                                                System.Diagnostics.Debug.WriteLine("Test : " + attributeValue);
                                                dt.Rows.Add(attributeValue);
                                            }
                    
                                        }
                    
                                        test.DataSource = dt;
                                        test.DataBind();
                                    }
                                    
                    
                                }
                                finally
                                {
                                    connection.Close();
                                }            

                    J'essaie de stocker la valeur de l'attribut dans un string, afin de la réutiliser pour le tableau, mais rien n'y fait.

                    -
                    Edité par ClémentPraudel1 9 janvier 2018 à 14:23:10

                    • Partager sur Facebook
                    • Partager sur Twitter
                      9 janvier 2018 à 14:45:49

                      Et à quel moment ça coince?

                      Le databinding qui passe pas?

                      attributevalue qui est vide?

                      nodes qui ne contient pas les noeuds que tu veux?

                      Ou d'autres endroits ?

                      Pour savoir, utilise le debugger : mets des points d'arrêt aux endroits qui t'intéressent (par exemple ligne 34 de ce que t'as donné) et regarde ce que contiennent tes variables.

                      Si attribtueValue ne contient pas ce que tu veux (après avoir exécuté la ligne évidemment), alors tu remontes pour voir ce que node contient et ainsi de suite jusqu'à trouver la source de l'erreur.

                      -
                      Edité par Stormweaker 9 janvier 2018 à 14:46:35

                      • Partager sur Facebook
                      • Partager sur Twitter
                        9 janvier 2018 à 16:03:21

                        En fait, rien ne s'affichait, mais c'est mon XPATH qui ne fonctionnait pas.

                        je fais des tests sur une seule Id, et ça donne ça pour le moment : 

                        La répétition du nom est normale, car il y a plusieurs valeurs possibles dans la donnée xml pour une seule Id. je fusionnerai les lignes par la suite.

                        En revanche, est-il possible de faire plusieurs "requetes" dans une seule action ?

                        Voici mon code : 

                        var nodesIdTemp = docComplet.SelectNodes("Root/StorageObject[@Name]");
                                                var nodes = doc.SelectNodes("Template//Component/Properties/Property[@Name='FormId']");
                        
                                                foreach (XmlElement nodeT in nodesIdTemp)
                                                {
                                                    string nameTemp = nodeT.GetAttribute("Name");
                                                    foreach (XmlElement node in nodes)
                                                    {
                                                        string attributeValue = node.GetAttribute("Value");
                                                        System.Diagnostics.Debug.WriteLine("Test : " + attributeValue);
                                                        dt.Rows.Add(nameTemp,attributeValue);
                                                    }
                                                }                       
                                            }
                                            test.DataSource = dt;
                                            test.DataBind();

                        J'ai lu qu'il y avait le XQuery qui pourrait faire le taffe, mais j'ai peur qu'avec mon xml encapsulé, ça ne fonctionne pas du tout.

                        • Partager sur Facebook
                        • Partager sur Twitter
                          9 janvier 2018 à 17:11:20

                          Je vois pas ce que tu veux dire par "plusieurs requêtes dans une seule action" et je ne connais pas XQuery mais une fois que ton xml encapsulé est extrait, ça reste du xml donc je ne vois pas pourquoi ça ne fonctionnerait pas.

                          -
                          Edité par Stormweaker 9 janvier 2018 à 17:14:57

                          • Partager sur Facebook
                          • Partager sur Twitter
                            10 janvier 2018 à 11:26:47

                            En fait, j'ai différentes informations à récupérer, comme le nom de la donnée principale (Template), a date de modification, les différentes valeurs que je trouve dans la donnée principale (FormId).

                            Vu que j'utilise des foreach, donc des boucles pour atteindre les informations et les afficher dans le tableau, celà ne fonctionne pas tout le temps : 

                            protected void Page_Load(object sender, EventArgs e)
                                    {
                                        try
                                        {
                                            string query = "SELECT Id, Content From Template WHERE Id = '0108f7ac-7853-4543-8ec4-a04cb755ed46' AND Deleted = '0'";
                                            SqlCommand cmd = new SqlCommand(query, connection);
                                            connection.Open();
                                            sdr = cmd.ExecuteReader();
                                            XmlDocument content = new XmlDocument();
                                            XmlDocument contenu_encapsule = new XmlDocument();
                            
                                            if(sdr.HasRows)
                                            {
                                                DataTable dt = new DataTable();
                                                dt.Columns.Add("Nom_Template", typeof(string));
                                                dt.Columns.Add("Time_Last_Modified", typeof(string));
                                                dt.Columns.Add("FormId", typeof(string));
                            
                                                while (sdr.Read())
                                                {
                                                    string complet = sdr["Content"].ToString();
                                                    content.LoadXml(complet);
                                                    contenu_encapsule.LoadXml(FinalContent());
                            
                                                    var nodesName = content.SelectNodes("Root/StorageObject[@Name]");
                                                    var nodesFormId = contenu_encapsule.SelectNodes("Template//Component/Properties/Property[@Name='FormId']");
                                                    var nodesDateModif = content.SelectNodes("Root/StorageObject/Properties/Property[@Name='TimeLastModified']");
                            
                                                    foreach (XmlElement nodeT in nodesName)
                                                    {
                                                        string nameTemp = nodeT.GetAttribute("Name");
                                                        string time = nodeT.GetAttribute("Value");
                                                        foreach (XmlElement nodeF in nodesFormId)
                                                        {
                                                            string id_Form = nodeF.GetAttribute("Value");
                                                            dt.Rows.Add(nameTemp, time, id_Form);
                                                        }
                                                    }
                            
                                                }
                                                gv.DataSource = dt;
                                                gv.DataBind();
                                            }               
                                        }
                                        finally
                                        {
                                            connection.Close();
                                        }         
                                    }
                            
                                    public String FinalContent()
                                    {
                                        string final;
                            
                                        string content = sdr["Content"].ToString();
                            
                                        XmlDocument doc = new XmlDocument();
                            
                                        doc.LoadXml(content);
                            
                                        final = doc.SelectSingleNode("Root/StorageObject/Properties/Property[@Name='ObjectContent']").Attributes["Value"].Value;
                            
                                        return final;
                                    }
                                }

                            Rien ne s'affiche dans la colonne "date de modification", car la boucle principale est les nodes du nom du template.

                            De ce fait, le Xpath du DateModif ne fonctionne pas, car l'attribut Value n'existe pas pour le noeud du nom du template.

                            Je m'en suis rendu compte en changeant l'attribut "Value" par "Name" et du coup, voilà ce que ça donne : 

                            L'attribut "Name" existant pour le Xpath du "nodesName", celà m'a dupliqué" les valeurs dela ère colonne.

                            (Pour info, j'ai supprimé ma méthode pour "spliter" le contenu avec des chaines de caractères, car à terme, ça n'aurait pas été performant. J'ai donc utilisé le Xpath et les noeuds pour récupérer la valeur de l'attribut du noeud de la donnée encapsulée, comme celà m'avait été indiqué dans un autre topic :D).

                            Du coup, je ne sais pas trop comment récupérer d'autres valeurs en procédant avec le Xpath...

                            EDIT : 

                            J'ai crée une petite méthode, similaire avec celle que j'avais déjà crée ou je récupére la valeur de l'attribut du SelectSingleNode, sous format string.

                            Je l'utilise dans la boucle et ça s'alimente.

                            Code de la méthode : 

                            public String Time_Last_Modified()
                                    {
                                        string timelastmodified;
                            
                                        string content = sdr["Content"].ToString();
                            
                                        XmlDocument doc = new XmlDocument();
                            
                                        doc.LoadXml(content);
                            
                                        timelastmodified = doc.SelectSingleNode("Root/StorageObject/Properties/Property[@Name='TimeLastModified']").Attributes["Value"].Value;
                            
                                        return timelastmodified;
                                    }

                            Le résultat sur l'ensemble de la base : 

                            EDIT 14h54 : 

                            J'essaie de récupérer des informations sur une autre table via les Id que j'ai récupéré dans la colonne FormId en utilisant un DataSet et un SqlDataAdapter, afin de ne pouvoir me connecter (comme j'ai pu le lire) de façon implicite et éviter une double connexion.

                            Mais j'ai l'erreur suivante :

                            Voici le code ma méthode : 

                             public string Name_FormId(string id)
                                    {
                                        string name;
                                        List<string> liste_Nom = new List<string>();
                            
                                        string query_Form = "SELECT Name FROM Form WHERE Id = '" + id + "' AND Deleted = '0'";
                            
                                        SqlDataAdapter adapter = new SqlDataAdapter(query_Form, connection);
                            
                                        DataSet ds = new DataSet();
                                        adapter.Fill(ds, "Name");
                            
                                        foreach (DataRow row in ds.Tables[0].Rows)
                                        {
                                            liste_Nom.Add(row.ItemArray.GetValue(0).ToString());
                                        }
                                        return name = liste_Nom[0];
                                    }





                            -
                            Edité par ClémentPraudel1 10 janvier 2018 à 14:58:00

                            • Partager sur Facebook
                            • Partager sur Twitter
                              11 janvier 2018 à 1:30:20

                              N'évitez pas les "double connexion", utilisez de nouvelles connexions, temporaires, en utilisant l'instruction "using".

                              Le pooling de connexion d'ADO.NET fera son travail d'optimisation.

                              • Partager sur Facebook
                              • Partager sur Twitter
                              Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                                11 janvier 2018 à 10:02:02

                                Merci @bacelar pour les informations.

                                J'avais vu ce mot clef quelque part, mais je n'arrive pas à trouver quelque chose de réellement pertinent à ce sujet.

                                Je viens de trouver ceci sur stackOverflow : 

                                https://stackoverflow.com/questions/4717789/in-a-using-block-is-a-sqlconnection-closed-on-return-or-exception

                                dans l'exemple du site, on recrée une nouvelle connexion pour utiliser une requête ?

                                Mais y a-t-il quelconque danger de faire comme je fais ? à savoir un premier DataReader, puis l'utilisation de DataAdapter.

                                • Partager sur Facebook
                                • Partager sur Twitter
                                  15 janvier 2018 à 8:04:23

                                  >mais je n'arrive pas à trouver quelque chose de réellement pertinent à ce sujet.

                                  https://docs.microsoft.com/fr-fr/dotnet/csharp/language-reference/keywords/using-statement

                                  >on recrée une nouvelle connexion pour utiliser une requête ?

                                  Oui

                                  >Mais y a-t-il quelconque danger de faire comme je fais ?

                                  Ne pas utiliser Using ?

                                  C'est chiant, dangereux, difficilement maintenable, pourri complètement les performances dans la très grande majorité des cas, etc...

                                  >à savoir un premier DataReader, puis l'utilisation de DataAdapter.

                                  C'est pas un danger, c'est impossible avec la même connexion.

                                  DataReader, c'était utile il y a 15 ans, plus vraiment maintenant. (Sauf cas très très particulier)

                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                  Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.

                                  XML encapsulé dans du XML

                                  × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                  × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                  • Editeur
                                  • Markdown