none
XmlDocument, XMLReader, Einlesung von mehreren gleichen Felder, Elemente RRS feed

  • Frage


  • Hallo Zusammen,
    wie liest man so ein File geschickt ein?
    <FILE mode="1" delimiter="§">
     <FILENAME timeformat="%Y-%m-%d">
      <FIELD keyword="timestamp" />
      <FIELD keyword="FraeseModell" />
      <FIELD keyword="CycleTime" />
      <FIELD program="name" />
      <FIELD source="keyword/interrupted" good="" bad="Error" />
      <FIELD value=".temp" />
     </FILENAME>
     <Content timeformat="%Y-%m-%d">
      <FIELD keyword="timestamp" />
      <FIELD keyword="name" />
      <FIELD source="keyword/interrupted" good="" bad="Error" />
     </Content>

    Reihenfolge der Felder ist wichtig. Ein angedachte Einlesung über Serialisierung schlug fehl.
    XMLReader, Problem habe ich mit den FIELD und gleichen Namen, wie keyword.

    Viele Grüße Ulrich
    Dienstag, 31. Mai 2016 17:44

Antworten

  • Hallo Peter,
    zu a)
    ich meine die ConfigurationCustomer.XML ist größer.
    D.h.
     Root.Machine.Configuration.Fraese.FraeseIPAdress
     Root.Machine.Configuration.Barcodescanner.Port
     ....
     Irgendwann kommt mal Root.Trace.CUSTOMER
     
    Kurzum, Config laden und sofort nach dem Element selektieren udn auslesen. Einfach eine prägnante Lösung, Weg.
    Welche Variante wäre am besten. So wie ich es herausgefunden habe?
    zu b)
    ok
    zu c) Dictionary mein mein Chef, sei schneller.
          Die Daten zu schreiben, nice to have, sollte den Prozess nicht verlangsamen.
      
    zu d) sicher, hier fehlen mir Musterbeispiele, um ein Gefühl der Machbarkeiten zu bekommen.
    neu e)
      Für den Anfang,
    <CUSTOMER>
     <CONTENT timeformat="%Y-%m-%d %H:%M:%S">
        <SETTING
          variable1="$Timestamp"
          variable2="$STATE"
       />
        <CONDITIONS>
          <CONDITION name="STATE" condition1="FAIL" condition2="PASS" condition3="UNKNOWN" />
          <CONDITION name="BADMARK" condition1="FAIL" condition2="PASS" />
        </CONDITIONS>
      </CONTENT>
    </CUSTOMER>  


    Würde es nach Deinem Konzept versuchen einzulesen.
    2 Dictionaries
       a) für SETTING
       b) für CONDITIONS
               key = name, value = Structure oder Klasse
        
    Könnte man das irgendwie über LinQ direkt in ein Dictionary bringen?
    Grüße Ulrich
    Freitag, 3. Juni 2016 15:16

Alle Antworten

  • Hi Ulrich,
    wenn die Daten XML-konform sind und nur der Root-Knoten fehlt, kann man die Daten in einen Root-Knoten einbetten und dann als XElement serialisieren, z.B. so;

    using System;
    using System.IO;
    using System.Text;
    using System.Xml.Linq;
    
    namespace ConsoleApplication1CS
    {
      class Program21
      {
        static void Main(string[] args)
        {
          StringBuilder sb = new StringBuilder();
          sb.Append("<root>");
          using (StreamReader sr = new StreamReader("Program21Txt.txt")) sb.Append(sr.ReadToEnd()); 
          sb.Append("</root>");
          Console.WriteLine(sb.ToString());
          XElement xe0 = XElement.Parse(sb.ToString());
          ShowData(xe0,0);
          Console.ReadKey();
        }
    
        private static void ShowData(XNode xe1, int level)
        {
          var xe2 = xe1 as XElement;
          Console.Write(new string(' ', level));
          Console.WriteLine(xe2.Name);
          foreach (var att2 in xe2.Attributes())
          {
            Console.Write(new string(' ', level+2));
            Console.WriteLine($"{att2.Name} - {att2.Value}");
          }
          foreach (var xe3 in xe2.Nodes()) ShowData(xe3, level+1);
        }
      }
    }


    --
    Viele Grüsse
    Peter Fleischer (MVP, Partner)
    Meine Homepage mit Tipps und Tricks
    Kommas richtig setzen!
    Schüler sagen, Lehrer haben es gut.
    Schüler, sagen Lehrer, haben es gut

    Dienstag, 31. Mai 2016 18:42
  • Hallo Peter,

    Danke.

    Problem.

    <FIELD keyword="timestamp" />
      <FIELD keyword="FraeseModell" />
      <FIELD keyword="CycleTime" />
      <FIELD program="name" />
    

    Ich sollte es mit XmlDocument, XmlReader lösen, u.a. weil der Dateiname dann wie folgt aufgebaut wird.

        2016-05-31-FraeseModell20ControllUnit.txt.

    D.h. da gibt mir die Reihenfolge vor, zur Laufzeit werden dann die Variablen befüllt.

    Noch einen Tipp.......?

    Viele Grüße Ulrich

    Dienstag, 31. Mai 2016 20:08
  • Hallo Ulrich,

    Ich sollte es mit XmlDocument, XmlReader lösen, u.a. weil der Dateiname dann wie folgt aufgebaut wird.

    Was hat das eine mit dem anderen zu tun? Du kannst auch ein XmlDocument oder XmlReader aus einem String erzeugen. Genauso kannst du bei allen Möglichkeiten den Dateinamen annähernd beliebig festlegen.

    Die Reihenfolge beim lesen wird auch von allen 3 genannten eingehalten sodass das kein Problem ist. Auch eine richtige Serialisierung in ein Klassenkonstrukt sollte kein Problem darstellen, sofern das Klassenkonstrukt ähnlich zum XML aufgebaut ist.

    Wenn du keine Serialisierung in Klassen nutzen willst, würde ich aufgrund der einfachen Nutzung zu Linq to XML, also zu XDocument usw. greifen.


    Tom Lambert - .NET (C#) MVP
    Wozu Antworten markieren und für Beiträge abstimmen? Klicke hier.
    Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter | Account bestätigen (Verify Your Account)
    Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets

    Dienstag, 31. Mai 2016 20:41
    Moderator
  • Hi Ulrich,
    warum willst Du es komplizierter machen?

    Den Dateinamen musst Du in jedem Fall bilden, um auf die richtige Datei zuzugreifen. Das ist unabhängig von der genutzten Technologie.

    Bei der Deserialisierung in ein XElement werden alle Knoten auch in der Reihenfolge des Auftretens im Ausgangstext in die Auflistungen eingefügt. Das sollte aus der Abarbeitung meines Codebeispiels eigentlich ersichtlich sein. Die rekursiv aufgerufene ShowData-Methode stellt die Reihenfolge genau wie in der Ausgangsdatei dar.

    Dein im ersten Beitrag geposteter Auszug ist nicht XML-konform, weshalb alle Techniken, die intern einen Parser nutzen, früher oder später in einen Fehler laufen. Ich habe deshalb der erforderlichen Root-Knoten per Programm ergänzt, außerdem auch das schließende "FILE".


    --
    Viele Grüsse
    Peter Fleischer (MVP, Partner)
    Meine Homepage mit Tipps und Tricks
    Kommas richtig setzen!
    Schüler sagen, Lehrer haben es gut.
    Schüler, sagen Lehrer, haben es gut

    Mittwoch, 1. Juni 2016 04:22
  • Hallo Peter,

    das Deserialisieren schlug fehl, weil bei FIELD das Keyword mehrfach vorkommt, ich dann eine Liste gewählt habe, da war dann die Reihenfolge anders. Prüfe es. Würde es mit dem XMLReader ähnlich gehen?

    Grüße Ulrich

    Mittwoch, 1. Juni 2016 04:44
  • Hi Ulrich,
    wenn die Daten nicht XML-konform sind (z.B. mehrere Attribute mit gleichem Namen), dann funktioniert keine der XML-Parser-Techniken. Da musst Du Dir selbst einen Parser schreiben, was bestimmt einige Tage oder Wochen in Anspruch nehmen wird.

    --
    Viele Grüsse
    Peter Fleischer (MVP, Partner)
    Meine Homepage mit Tipps und Tricks
    Kommas richtig setzen!
    Schüler sagen, Lehrer haben es gut.
    Schüler, sagen Lehrer, haben es gut

    Mittwoch, 1. Juni 2016 14:46
  • Da musst Du Dir selbst einen Parser schreiben, was bestimmt einige Tage oder Wochen in Anspruch nehmen wird.

    Hallo Peter,
    was heißt XML konform. Ich konnte es jetzt auslesen, fragte nach, ob
    die Community bessere Lösungen weiß.
    Ich würde Variante 2 vorziehen, lt. Chef geht es nicht, vom Kunden vorgegeben.

    1
    <CONTENT timeformat="%Y-%m-%d">
    	<FIELD keyword="timestamp" />
    	<FIELD keyword="name" />
    	<FIELD keyword="panelcode" />
    	<FIELD unique="Fraese" />
    	<FIELD unique="CustomerTrace1" />
    	<FIELD keyword="name" />   // kann sein, dass der Name nochmals vorkommt.
    	<FIELD unique="CustomerTrace2" />
    	<FIELD multiple="CustomerTrace3" content1="NIO", content2=IO"/>
    </CONTENT>
    
    2
    <CONTENT timeformat="%Y-%m-%d">
    	<FIELD key1="$timestamp" />
    	<FIELD key2="$name" />
    	<FIELD key3="$panelcode" />
    	<FIELD key4="Fraese" />
    	<FIELD key5="CustomerTrace" />
    	<FIELD key6="$$CustomerTrace3" content1="NIO", content2=IO"/>
    </CONTENT>
    
    3
    <CONTENT timeformat="%Y-%m-%d">
    	<FIELD key="$timestamp" />
    	<FIELD key="$name" />
    	<FIELD key="$panelcode" />
    	<FIELD key="Fraese" />
    	<FIELD key="$name" />    // kann sein, dass der Name nochmals vorkommt.
    	<FIELD key="CustomerTrace" />
    	<FIELD key="$$CustomerTrace3" content1="NIO", content2=IO"/>
    </CONTENT>

      switch (fieldReaderFile.NodeType)
    {
     case XmlNodeType.Element:
      if (fieldReaderFile.Name == "FIELD")
      {
       index++;
       if (fieldReaderFile.MoveToFirstAttribute())
       {
        type = fieldReaderFile.Name;
        definition = fieldReaderFile.Value;
        ...
         while (fieldReaderFile.MoveToNextAttribute())
         {
          listValue.Add(fieldReaderFile.Value);
         }    


    Grüße Ulrich

    Mittwoch, 1. Juni 2016 16:32
  • Hi Ulrich,
    ich empfehle Dir, sich mal mit XML zu beschäftigen.

    Übrigens, die von mir gepostete Lösung funktioniert mit allen Deinen 3 Versionen. Scheinbar hast Du Dir meine Lösung überhaupt nicht angeschaut. Für mich ist der Thread damit beendet.


    --
    Viele Grüsse
    Peter Fleischer (MVP, Partner)
    Meine Homepage mit Tipps und Tricks
    Kommas richtig setzen!
    Schüler sagen, Lehrer haben es gut.
    Schüler, sagen Lehrer, haben es gut

    Mittwoch, 1. Juni 2016 16:44
  • Hallo Peter,

    ich hab's angeschaut und es funktionierte nicht so wie ich es benötige, da ich die FIELD in ein Dictionary einlesen muss.

    Wäre das XML zulässig? Kannst ja noch kurz antworten. DANKE.

    	<FIELD key="$name" />
    	<FIELD key="$panelcode" />
    	<FIELD key="Fraese" />
    	<FIELD key="$name" /
    Grüße Ulrich

    Mittwoch, 1. Juni 2016 17:09
  • Hallo Ulrich,

    das Problem dürfte weniger beim Einlesen der XML-Daten liegen, da wurde dir ja auch ein gut funktionierender Weg gezeigt.

    Ob XML "zulässig" ist, wie du fragst, kann dir einer der vielen XML-Validatoren zeigen (Google hilft...), z.B. hier: XML-Validator. Dort findest du auch einige Hintergrundinformationen zu XML.

    Du sagst, du musst "FIELD" in ein Dictionary einlesen. Was genau meinst du damit? Ein Dictionary ist eine Key/Value Auflistung und der Key muss immer einmalig sein.

    Du hast hier mehrere ELEMENTE (benannt als FIELD) die selbst keine Werte beherbergen, aber mit ATTRIBUTEN dekoriert sind. Die Attribute heißen "key" und die haben einen Wert, z.B. "$name", ... und aus Sicht von XML ist das absolut in Ordnung. Also nochmal, in deinem Beispiel:

    Die ELEMENTE heißen "FIELD", die ATTRIBUTE heißen "key" und diese haben Werte ("$name", "$panelcode", ..., "$name")

    Nichts davon kannst du aber direkt als KEY in einem Dictionary verwenden mangels EINDEUTIGKEIT, eine Voraussetzung der Nutzbarkeit eines Dictionarys.

    Prüf noch mal dein Konzept. Du hast Datenmaterial als XML-Datei und musst dieses zunächst einmal in einer internen Datenstruktur abbilden. Kann es sein, dass es da etwas klemmt?

    Gruß


    • Bearbeitet K. Pater Mittwoch, 1. Juni 2016 17:56
    Mittwoch, 1. Juni 2016 17:55
  • Die ELEMENTE heißen "FIELD", die ATTRIBUTE heißen "key" und diese haben Werte ("$name", "$panelcode", ..., "$name")

    Nichts davon kannst du aber direkt als KEY in einem Dictionary verwenden mangels EINDEUTIGKEIT, eine Voraussetzung der Nutzbarkeit eines Dictionarys.

    Prüf noch mal dein Konzept. Du hast Datenmaterial als XML-Datei und musst dieses zunächst einmal in einer internen Datenstruktur abbilden. Kann es sein, dass es da etwas klemmt?


    Hallo K.Pater,

    ja sicher klemmt es da etwas.

    Ich dachte einfach, ich lese FIELD key="XXXXX", wenn $name ist das der key des Dictionary

    Wenn mehrfach vorkommend, dann eben name1, name2, name3, etc.

    Ohne $ ist der der static1, static2 und der Value bereits der key Wert vom XML.

    Somit weiß ich welche ich austauschen muss. Peter ist etwas beleidigt, wenn Du noch einen Tipp hast. DANKE.

    Grüße Ulrich

    Mittwoch, 1. Juni 2016 18:46
  • Hallo Ulrich,

    ich finde die XML-Daten ziemlich verwirrend und unstrukturiert. Das sind doch Daten, die du selbst machst, oder bekommst du die so angeliefert?

    Wie auch immer, wenn du das Problem lösen willst, musst du zuerst wissen, wie deine XML-Daten aufgebaut sind; hier tauchen von dir und von Beispiel zu Beispiel neue Elemente und/oder Attribute auf.

    Falls du die XML-Datei selbst erzeugst (für den Kunden), würde ich zuerst bei den XML-Daten ansetzen und ein vernünftiges Format erstellen. Wenn du dabei Hilfe brauchst, sag was.

    XML in dieser Art fände ich (als Beispiel) einleuchtender:

    <?xml version="1.0" encoding="utf-8" ?>
    <FILE mode="1" delimiter="§">
      <CONTENT
        timeformat="%Y-%m-%d"
        timestamp="2016-06-02"
        fraesemodell="FraeseModell20"
        und="irgend" 
        so="etwas" 
        weiter="anderes" />
    </FILE>
    Allerdings kann man Attribute auch nicht überall sinnvoll verwenden, Elemente bieten manchmal mehr Spielräume. Ganz gut wird das verständlich, wenn du dir in deinem Beispiel die etwas merkwürdig aussehende "CustomerTrace"-Konstruktionen ansiehst.

    Gruß

    Mittwoch, 1. Juni 2016 23:58
  • Hallo K.Pater,

    ist seitens Kunde vorgegeben. Evtl. kann ich noch was bewegen.

    Element - Attribute ist aus meiner Sicht besser.

    <FIELD key="$$CustomerTrace3" content1="NIO", content2=IO"/>

    Wie könnte man dann eine Fallunterscheidung noch abbilden?

    Grüße Ulrich

    Donnerstag, 2. Juni 2016 04:53
  • Hallo,

    dein letztes Beispiel würde ich prinzipiell in etwa so umsetzen:

    // --------------------------------------------------------------
    // <FIELD key = "$$CustomerTrace3" content1="NIO", content2=IO"/>
    // --------------------------------------------------------------
    /// <summary>
    /// Mögliche Basisklasse, serialisierbar.
    /// </summary>
    [Serializable]
    public class FIELD {
    	[XmlAttribute(AttributeName = "key")]
    	public string key { get; set; }
    
    	[XmlAttribute(AttributeName = "content1")]
    	public string content1 { get; set; }
    
    	[XmlAttribute(AttributeName = "content2")]
    	public string content2 { get; set; }
    }

    Wenn du einen oder mehrere "CustomerTraces" verarbeiten willst, würde ich die XML-Daten vielleicht auch so aufbauen:

    <FIELD type="CustomerTraces"> <CUSTOMERTRACE content1="daten" content2="daten" /> <CUSTOMERTRACE content1="daten" content2="daten" /> <CUSTOMERTRACE content1="daten" content2="daten" /> </FIELD>

    <!-- oder noch besser gleich so -->

    <CustomerTraces>
        <CUSTOMERTRACE content1="?" content2="?" />
        <CUSTOMERTRACE content1="?" content2="?" />
        <CUSTOMERTRACE content1="?" content2="?" />
    </CustomerTraces>

    Um auf ein früheres Beispiel zurückzukommen:

    <FIELD key="$name" />
    <FIELD key="$panelcode" />
    <FIELD key="Fraese" />
    <FIELD key="$name" />

    Was beschreibt das eigentlich? Sind "$name", "$panelcode", ... Nutzdaten?

    Gruß

    Donnerstag, 2. Juni 2016 07:18
  • Hi Klaus,
    ich würde Deinen Vorschlag nicht realisieren. Er setzt voraus, dass alles endgültig vereinbart und festgelegt ist. Das Leben ist aber leider recht dynamisch und der Aufwand für die Projektierung einer Anwendungslösung ist nicht vernachlässigbar. Die konfusen Beiträge von Ulrich bestätigen dies leider.

    Ich würde die Anwendungslösung auf Basis einer Spezifikation unabhängig vom konkreten Format der gelieferten Daten realisieren. Das bedeutet, dass Eingangsschnittstellen auf Basis der zu verarbeitenden Daten abgestimmt auf die Anwendungslösung erstellt werden (eine Art Top-Down-Entwicklung). Eine Model-Schicht liest dann diese Daten ein und stellt sie in Puffern der Geschäftslogik zur Verfügung. Um dann auf konkrete Schemata der gelieferten Daten zu reagieren, ist nur noch ein Konverter erforderlich, der die gelieferten Daten prüft und in das von der Anwendung geforderte Schema transferiert. Das ist recht einfach mit XSLT möglich. Erst, wenn eine neue Version der Verarbeitungslogik zu implementieren ist, kann es passieren, dass am Eingang der Anwendungslösung ein verändertes Schema der zu verarbeitenden Daten erforderlich wird und dann die genutzten Konverter anzupassen sind. Bei solch einer Arbeitsweise ist die Herangehensweise mit serialisierbaren Klassen im Anwendungsprogramm eine gute Lösung und das Anwendungsprogramm kann lange Zeit stabil ohne Anpassungen genutzt werden. Anzupassen sind lediglich die Konverter, wenn sich die Lieferanten andere Darstellungen der einfallen lassen.


    --
    Viele Grüsse
    Peter Fleischer (MVP, Partner)
    Meine Homepage mit Tipps und Tricks
    Kommas richtig setzen!
    Schüler sagen, Lehrer haben es gut.
    Schüler, sagen Lehrer, haben es gut

    Donnerstag, 2. Juni 2016 08:09
  • Hallo Peter,

    Klare Fragen, klare Antworten. An den klaren Fragen mangelt es manchmal, aus welchen Gründen auch immer... :-)

    Wenn du die erste Frage "wie liest man so ein File geschickt ein?" erinnerst, hast du in deinem Verständnis dazu dargestellt, wie man die Datei einlesen kann. Dann stellt sich aber heraus, dass das scheinbar gar nicht gemeint war. Ulrich hat scheinbar eher gemeint, wie man die eingelesenen Daten geschickt auf eine interne Datenstruktur abbildet (einliest), da er mit dem von ihm angedachten Dictionary auf Probleme gestoßen war.

    Den exmplarischen (Teil)Vorschlag, wie auch immer, nicht zu realisieren weil eventuell noch nicht alles vereinbart ist, finde ich nun aber etwas seltsam. Egal welchem Entwicklungsmuster/Dogma man folgt,  man muss zumindest in der Ebene, in der man gerade arbeitet, sehr wohl exakte Spezifikationen haben. Worüber redet man denn sonst?

    Die vorgeschlagenen Konverter sind bestimmt hilfreich, wenn sich das Datenaustauschformat ändern kann. Ob dann eine CSV, wohlgeformte oder schlechtgeformte XML-Datei vorliegt, kann man einfach über einen Konverter ausgleichen.

    Ich habe ja die Vermutung, dass möglicherweise das zugrundeliegende Datenmodell noch nicht ganz geklärt ist.

    "Ich würde die Anwendungslösung auf Basis einer Spezifikation unabhängig vom konkreten Format der gelieferten Daten realisieren."

    Dem kann man nur zustimmen...

    Also: @Ulrich: Hast du ein vollständiges Datenmodell?

    Gruß, Klaus

    Donnerstag, 2. Juni 2016 12:29
  • Hi Klaus,
    meine Erfahrung ist, dass das darzustellende Ergebnis und die grobe Bedientechnologie dazu sehr früh spezifiziert ist, meist durch Führungs- und Leistungskräfte. Auch wird eine zügige und effektive Bearbeitung gefordert. Darauf aufbauend kann man fast immer eine Anwendungslösung konzipieren, vielleicht nur als Muster bzw. Prototyp und mit eingeschränktem Funktionsumfang, welche unabhängig ist von noch nicht genau festgelegten Strukturen der Primärdaten. Dieser Prototyp kann dann im nächsten Meilenstein mit detaillierteren Spezifikation überarbeitet werden. Parallel und unabhängig dazu können Abstimmungen zu den externen Schnittstellen geführt werden, wenn man von Anfang an Konverter vorsieht.

    --
    Viele Grüsse
    Peter Fleischer (MVP, Partner)
    Meine Homepage mit Tipps und Tricks
    Kommas richtig setzen!
    Schüler sagen, Lehrer haben es gut.
    Schüler, sagen Lehrer, haben es gut

    Donnerstag, 2. Juni 2016 17:51
  • Also: @Ulrich: Hast du ein vollständiges Datenmodell?


    Hallo K.Pater,
     <FIELD key="$name" />  
     <FIELD key="$panelcode" /> 
     <FIELD key="Fraese" /> 
     <FIELD key="$name" /> 


    $ bedeutet zur Laufzeit, d.h. ich muss diese Variablen befüllen.
    Ohne $ ist statisch, wie angegeben.

    Audi-0815-Fraese-Audi.txt
    VW-0816Fraese-VW.txt
    Opel-0816-Fraese-Opel.txt

    So könnte das aussehen. Für den Inhalt der Datei gilt dasselbe.
    Oder wenn so deklariert.
    Audi-0815-Fraese-Audi-IO.txt
    VW-0816Fraese-VW-NIO.txt
    Opel-0816-Fraese-Opel-IO.txt
    -----------------------------------------------------------
    D.h. mein erstes Posting ist vom Kunden, von meinem Chef.
    Jetzt zeigen sich Probleme und man sucht nach Lösungen, da die Erfahrung
    fehlt, fragte ich hier nach.
    Kommende Woche möchte ich meinem Chef/Kunden diese Lösung vorstellen.
    <CUSTOMER>
     <CONTENT timeformat="%Y-%m-%d %H:%M:%S">
        <SETTING
          variable1="$Timestamp"
          variable2="$STATE"
          variable3="Fraese"
          variable4="$Panelcode"
          variable5="$Posnr"
       />
        <CONDITIONS>
          <CONDITION name="STATE" condition1="FAIL" condition2="PASS" condition3="UNKNOWN" />
          <CONDITION name="BADMARK" condition1="FAIL" condition2="PASS" />
        </CONDITIONS>
      </CONTENT>
    </CUSTOMER>  
      20160602 18:33:33 PASS Fraese 0815 1
      20160602 18:33:34 PASS Fraese 0815 2
      20160602 18:33:35 PASS Fraese 0815 3
      20160602 18:33:36 FAIL Fraese 0815 4
       


      D.h. Dein Vorschlag gefällt mir.
      Wie würde ich das dann geschickt einlesen?

      a) Die XML Datei ist größer, also muss ich auf das Element CUSTOMER selektieren.
      b) Timeformat einlesen, umwandeln in C# Norm, evtl. kann ich dem Kunden die C# Norm beibringen.
      c) Dictionary Key sind jetzt die Variablen
      d) Bleiben die Conditions, eigene Klasse? Eigene Struktur?

      Wäre supernett, wenn Ihr zweit mir noch helfen wollt. Danke im Voraus.
    Grüße Ulrich

    Donnerstag, 2. Juni 2016 18:06
  • Hallo Peter,
    das XML ist größer, deshalb fehlte das root.
    Ich kenne mich mit XDocument nicht so aus und wußte nicht, wie ich am besten ein Element selektiere.
    Ich habe jetzt 2 Möglichkeiten gefunden, wenn Du noch bessere weißt, wäre es schön,
    wenn Du diese mitteilst. Somit ging es anfangs nicht.
    Kurzum, ja Dein Beispiel geht und ist doch verständlich, hattest wieder mal recht;-)
    Grüße Ulrich
    XDocument xDoc = XDocument.Load("config.XML");
    //var eleList = xDoc.Element("FILENAME").XPathSelectElements(xPath).ToList();
    //foreach (var xElement in eleList)
    //{
    //    Console.WriteLine(xElement);
    //}
    
    
    foreach (XElement element in xDoc.Descendants("FILENAME"))
    {
     Console.WriteLine(element);
     ShowData(element, 0);
    }
    
    
    foreach (XElement element in xDoc.Descendants("CONTENT"))
    {
     Console.WriteLine(element);
     ShowData(element, 0);
    }
    
    
    XElement el = xDoc.XPathSelectElement("/ROOT/CUSTOMERCONFIG/TRACE/FILENAME");
    ShowData(el, 0);

    Donnerstag, 2. Juni 2016 18:07
  • Hi Ulrich,
    ich finde diese Herangehensweise äußerst uneffektiv. In der Projektentwicklung gibt es üblicherweise darzustellende Ergebnisse und Primärdaten und u.U. noch Verarbeitungsvorschriften. Entwicklungskapazität dafür aufzuwenden, den Lieferanten der Daten zu einem Schema zu zwingen, führt nach meiner Erfahrung meist zum Scheitern des Projektes. Besser ist es, die Kraft dafür aufzuwenden, fehlende Primärdaten zu ermitteln, die für die Darstellung der Ergebnisse benötigt werden.

    zu a) Wenn Du unter Element CUSTOMER den Knoten mit dem Namen CUSTOMER meinst, so kann man diesen mit LinQ2XML aus eine geladenen XElement schnell herausholen.

    zu b) Zum Datums-/Zeitformat in XML gibt es Regeln, die eingehalten werden sollten. Wenn das nicht gemacht wird, dann empfehle ich einen Konverter, der aus einem nichtkonformen XML ein konformes XML macht.

    zu c) das sture Festhalten an Dictionaries engt die Sicht auf bessere Lösungen ein. Bei der Bindung eines Dictionaries an Oberflächen-Elemente können Probleme auftreten, die bei richtig konzipierten typisierten Listen nicht auftreten.

    zu d) Sichten mit Listen von Klassen für die Daten ist eine gute Lösung, die ein Datenmodell für die Anwendungslösung voraussetzt. Damit die konkreten gelieferten Daten dazu passen, kann ein vorgeschalteter Konverter genutzt werden. 


    --
    Viele Grüsse
    Peter Fleischer (MVP, Partner)
    Meine Homepage mit Tipps und Tricks
    Kommas richtig setzen!
    Schüler sagen, Lehrer haben es gut.
    Schüler, sagen Lehrer, haben es gut

    Donnerstag, 2. Juni 2016 18:34
  • Hallo Ulrich,

    ich würde zunächst ein Datenmodell erstellen. Das sagt sich immer so einfach, also hier Schritt für Schritt, wie ich es wahrscheinlich machen würde. Das Folgende nimmt genau dein Beispiel als Grundlage.

    Schritt 1: Für jedes ELEMENT eine Klasse erstellen:

      public class CUSTOMER {  }
    
      public class CONTENT { }
    
      public class SETTING { }
      
      public class CONDITIONS { }
    
      public class CONDITION { }

    Das sind die ELEMENTE in deinem Beispiel. Als nächstes würde ich die Eigenschaften implementieren. Jedes Attribut erhält eine einfache String-Property, Elemente werden nach ihrem Typ definiert:

     public class CUSTOMER {
        public CONTENT content = new CONTENT();
      }
    
      public class CONTENT {
        public SETTING setting = new SETTING();
        public CONDITIONS conditions = new CONDITIONS();
      }
    
      public class SETTING {
        public string variable1 { get; set; }
        public string variable2 { get; set; }
        public string variable3 { get; set; }
        public string variable4 { get; set; }
        public string variable5 { get; set; }
    
      }
      public class CONDITIONS {
        public List<CONDITION> condition = new List<CONDITION>();
      }
    
      public class CONDITION {
        public string name { get; set; }
        public string condition1 { get; set; }
        public string condition2 { get; set; }
        public string condition3 { get; set; }
      }

    Und hier habe ich für Elemente, die öfters vorkommen können, eine List<T> verwendet. Genau genommen kannst du auch für alle Elemente eine List<T> nehmen, falls doch mal mehrere kommen sollten. In deinem Beispiel hat nur CONDITIONS mehrere CONDITION, also habe ich hier auch eine Liste verwendet. Attribute sind immer einfach.

    Im vorletzten Schritt nun muss man die Eigenschaften und Klassen mit NET-Attributen dekorieren, damit der Serialiser eine Ahnung bekommt, wie und was er machen soll. Das sähe dann so aus:

      [Serializable]
      public class CUSTOMER {
        [XmlElement("CONTENT")]
        public CONTENT content = new CONTENT();
      }
    
      [Serializable]
      public class CONTENT {
        [XmlElement("SETTING")]
        public SETTING setting = new SETTING();
        [XmlElement("CONDITIONS")]
        public CONDITIONS conditions = new CONDITIONS();
      }
    
      [Serializable]
      public class SETTING {
        [XmlAttribute("variable1")]
        public string variable1 { get; set; }
        [XmlAttribute("variable2")]
        public string variable2 { get; set; }
        [XmlAttribute("variable3")]
        public string variable3 { get; set; }
        [XmlAttribute("variable4")]
        public string variable4 { get; set; }
        [XmlAttribute("variable5")]
        public string variable5 { get; set; }
    
      }
    
      [Serializable]
      public class CONDITIONS {
        [XmlElement("CONDITION")]
        public List<CONDITION> condition = new List<CONDITION>();
      }
    
      [Serializable]
      public class CONDITION {
        [XmlAttribute("name")]
        public string name { get; set; }
        [XmlAttribute("condition1")]
        public string condition1 { get; set; }
        [XmlAttribute("condition2")]
        public string condition2 { get; set; }
        [XmlAttribute("condition3")]
        public string condition3 { get; set; }
      }


    Die Klassen bekommen [Serializable].

    Die Elemente werden mir [XmlElement("Name des Elements")] und die Attribute mit [XmlAttribute("Name des Attributs")] verschönert.

    Damit wäre jetzt mal ein einfaches Datenmodell fertig.

    Wenn ich dein Beispiel nun als XML-Datei deserialisiere, sieht das im Debugger so aus:

    Da kannst du recht gut sehen, wie die XML-Struktur abgebildet wird.

    Nun noch die Frage, wie bekommst du die Daten in den Modell? Eventuell so:

    class Program {
      static void Main(string[] args) {
        string xmlDateiName = @"D:\test.xml";
        XMLWorker xmlworker = new XMLWorker();
        CUSTOMER customer = xmlworker.Einlesen(xmlDateiName);
     }
    }

    public class XMLWorker { public CUSTOMER Einlesen(string xmlDateiName) { XmlSerializer ser = new XmlSerializer(typeof(CUSTOMER)); using (var rdr = File.Open(xmlDateiName, FileMode.Open, FileAccess.Read) ) { return (CUSTOMER)ser.Deserialize(rdr); } } }

    zu b.) Ein Datum umzuwandeln solltest du auch ohne erzieherische Maßnahmen für deinen Kunden hinbekommen, oder?

    zu c.) Vergiss die Dictionarys.

    zu d.) Siehe obiges Beispiel.

    Vielleicht hilft dir das ja jetzt weiter.

    Ach ja. Falls die angelieferten Daten nicht ganz einer validen XML-Datei entsprechen, kommen die Konverter von Peter ins Spiel.

    Gruß

    Freitag, 3. Juni 2016 15:09
  • Hallo Peter,
    zu a)
    ich meine die ConfigurationCustomer.XML ist größer.
    D.h.
     Root.Machine.Configuration.Fraese.FraeseIPAdress
     Root.Machine.Configuration.Barcodescanner.Port
     ....
     Irgendwann kommt mal Root.Trace.CUSTOMER
     
    Kurzum, Config laden und sofort nach dem Element selektieren udn auslesen. Einfach eine prägnante Lösung, Weg.
    Welche Variante wäre am besten. So wie ich es herausgefunden habe?
    zu b)
    ok
    zu c) Dictionary mein mein Chef, sei schneller.
          Die Daten zu schreiben, nice to have, sollte den Prozess nicht verlangsamen.
      
    zu d) sicher, hier fehlen mir Musterbeispiele, um ein Gefühl der Machbarkeiten zu bekommen.
    neu e)
      Für den Anfang,
    <CUSTOMER>
     <CONTENT timeformat="%Y-%m-%d %H:%M:%S">
        <SETTING
          variable1="$Timestamp"
          variable2="$STATE"
       />
        <CONDITIONS>
          <CONDITION name="STATE" condition1="FAIL" condition2="PASS" condition3="UNKNOWN" />
          <CONDITION name="BADMARK" condition1="FAIL" condition2="PASS" />
        </CONDITIONS>
      </CONTENT>
    </CUSTOMER>  


    Würde es nach Deinem Konzept versuchen einzulesen.
    2 Dictionaries
       a) für SETTING
       b) für CONDITIONS
               key = name, value = Structure oder Klasse
        
    Könnte man das irgendwie über LinQ direkt in ein Dictionary bringen?
    Grüße Ulrich
    Freitag, 3. Juni 2016 15:16
  • Hallo Klaus,

    >ich würde zunächst ein Datenmodell erstellen. Das sagt sich immer so einfach,
    >also hier Schritt für Schritt, wie ich es wahrscheinlich machen würde. Das
    >Folgende nimmt genau dein Beispiel als Grundlage.

    Du sagst es, das richtige Konzept zu finden ist nicht immer einfach.
    Dein Vorschlag passt und Danke. Hoffe meinem Chef und dem Kunde gefällt es auch.
    Siehe noch neuer Thread, Konzeptfrage.

    Viele Grüße Ulrich

    Montag, 6. Juni 2016 16:29