none
XML Dokument schnell einlesen RRS feed

  • Frage

  • Hallo,

    mit welcher Library lese ich so ein XML Dokument optimal ein?

    Danke für Tipps und Grüße Sandra

    <ROOT info="ToDo - Working product">
      <PROCESS_START id="7878554" ori="90°" side="">
        <SIDE1>
          <POSITIONS>
            <POSITION x="1" y="1" />
            <POSITION x="2" y="1" />
            <POSITION x="3" y="1" />
            <POSITION x="4" y="1" />
            <POSITION x="5" y="1" />
            <POSITION x="6" y="1" />
            <POSITION x="7" y="1" />
            <POSITION x="8" y="1" />
            <POSITION x="9" y="1" />
            <POSITION x="10" y="1" />
            <POSITION x="11" y="1" />
            <POSITION x="12" y="1" />
            <POSITION x="13" y="1" />
            <POSITION x="14" y="1" />
            <POSITION x="15" y="1" />
            <POSITION x="16" y="1" />
            <POSITION x="17" y="1" />
          </POSITIONS>
        </SIDE1>
        <SIDE2>
          <POSITIONS>
            <POSITION x="1" y="21" />
            <POSITION x="2" y="31" />
            <POSITION x="3" y="41" />
          </POSITIONS>
        </SIDE2>
      </PROCESS_START>
      <CUSTOM color="0" background="0" />
    </ROOT>

                    //  var positions = XMLTelgramInput.Descendants("SIDE1").ToList();
                     string number;
                    string avtive;
                    POSITION positionMarking;
                    XElement elementSIDE1 = XMLTelgramInput.Descendants().Elements("SIDE1").FirstOrDefault();
                    if (elementSIDE1 != null)
                    {
                        XElement elementPOSITIONS = XMLTelgramInput.Descendants().Elements("POSITIONS").FirstOrDefault();
                        IEnumerable<XElement> positions = elementPOSITIONS.Elements();
                        foreach (var position in positions)
                        {
                            positionMarking = new POSITION();
                            positionMarking.number = Convert.ToInt32(position.Attribute("number").Value);
                            positionMarking.active = Convert.ToInt32(position.Attribute("active").Value);
                            PROC.SIDE1.POSITIONS.ListPOSITION.Add(positionMarking);
                        }
                    }


    • Bearbeitet Sandra Bauer Freitag, 29. April 2016 15:08 Format
    Freitag, 29. April 2016 15:04

Antworten

  • Hallo Sandra,

    die 1,2 ms, die Elmar gemessen hatte, resultieren bestimmt von dem etwas schwächeren Rechner her. Um es vergleichbar zu machen, habe ich mal beide Beispiele verglichen. Da kommt dann statt 1,2 ms 0,4 ms heraus. Im Unterschied dazu ist mein Beispiel also nur etwa 25% schneller.

    Aber mal ehrlich: Ob 0,3ms oder 0,4ms, beides dürften Resultate sein, mit denen du leben kannst. Nimm den Ansatz, der besser in dein Konzept passt.

    Die verwendete Datei "xyz.xml" ist einfach deine Vorgabe von oben mit jeweils 150 Positionen für Side1 und Side2.

    Hier noch mal das komplette Konsolenprojekt (ich sehe gerade nicht, wie ich das anders hochladen kann):

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Xml;
    
    namespace XMLTool {
    	class Program {
    		static void Main(string[] args) {
    			Stopwatch sw = new Stopwatch();
    			sw.Start();
    			for ( int i = 0 ; i < 1000 ; i++ ) {
    				ReadXML(@"d:\xyz.xml");
    			}
    			sw.Stop();
    			Console.WriteLine("Summe-Dauer [h:m:s]: " + sw.Elapsed.ToString());
    			Console.ReadLine();
    		}
    
    		static Prozess ReadXML(string filename) {
    			XmlReaderSettings settings = new XmlReaderSettings() {
    				ConformanceLevel = ConformanceLevel.Fragment,
    				IgnoreComments = true,
    				IgnoreWhitespace = true,
    				CheckCharacters = false
    			};
    
    			Prozess myProzess = new Prozess();
    			using ( XmlReader reader = XmlReader.Create(filename, settings) ) {
    				reader.ReadToFollowing("PROCESS_START");
    				myProzess.ID = reader.GetAttribute("id");
    				myProzess.ori = reader.GetAttribute("ori");
    				myProzess.side = reader.GetAttribute("side");
    
    				reader.ReadToFollowing("POSITIONS");
    				using ( XmlReader sideReader = reader.ReadSubtree() ) {
    					sideReader.Read(); // -> POSITIONS
    					sideReader.Read(); // -> 1te POSITION
    					while ( !sideReader.EOF ) {
    						if ( sideReader.NodeType == XmlNodeType.Element )
    							myProzess.Side1.Add(new Prozess.Position(sideReader.GetAttribute("x"), sideReader.GetAttribute("y")));
    						sideReader.Read();
    					}
    				}
    
    				reader.ReadToFollowing("POSITIONS");
    				using ( XmlReader sideReader = reader.ReadSubtree() ) {
    					sideReader.MoveToElement();
    					sideReader.Read(); // -> POSITIONS
    					sideReader.Read(); // -> 1te POSITION
    					while ( !sideReader.EOF ) {
    						if ( sideReader.NodeType == XmlNodeType.Element )
    							myProzess.Side2.Add(new Prozess.Position(sideReader.GetAttribute("x"), sideReader.GetAttribute("y")));
    						sideReader.Read();
    					}
    				}
    
    				reader.ReadToFollowing("CUSTOM");
    				myProzess.color = reader.GetAttribute("color");
    				myProzess.background = reader.GetAttribute("background");
    			}
    			return myProzess;
    		}
    	}
    
    	public class Prozess {
    		public string ID;
    		public string ori;
    		public string side;
    		public string color;
    		public string background;
    		public List<Position> Side1 = new List<Position>();
    		public List<Position> Side2 = new List<Position>();
    		public class Position {
    			public int x;
    			public int y;
    			public Position(string px, string py) {
    				int.TryParse(px, out x);
    				int.TryParse(py, out y);
    			}
    		}
    	}
    }

    Gruß



    • Bearbeitet K. Pater Sonntag, 1. Mai 2016 16:50
    • Als Antwort markiert Sandra Bauer Dienstag, 3. Mai 2016 17:11
    Sonntag, 1. Mai 2016 16:13
  • Hi Sandra,
    ich habe mal mit Deinen Angaben eine Release-Version getestet und die folgenden Ergebnisse bekommen. Mein Laptop ist mit 7 Jahren schon etwas älter.

    Zeit Deserialisierung: 7,624 ms
    Zeit Serialisierung: 2,856 ms
    Zeit Deserialisierung: 0,082 ms
    Zeit Serialisierung: 0,103 ms
    Zeit Deserialisierung: 0,090 ms
    Zeit Serialisierung: 0,101 ms
    Zeit Deserialisierung: 0,092 ms
    Zeit Serialisierung: 0,117 ms
    Zeit Deserialisierung: 0,085 ms
    Zeit Serialisierung: 0,096 ms
    Zeit Deserialisierung: 0,108 ms
    Zeit Serialisierung: 0,144 ms
    Zeit Deserialisierung: 0,119 ms
    Zeit Serialisierung: 0,107 ms
    Zeit Deserialisierung: 0,084 ms
    Zeit Serialisierung: 0,167 ms
    Zeit Deserialisierung: 0,215 ms
    Zeit Serialisierung: 0,159 ms
    Zeit Deserialisierung: 0,136 ms
    Zeit Serialisierung: 0,160 ms

    Die Test-Konsolenanwendung dazu:

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Xml.Linq;
    using System.Xml.Serialization;
    
    namespace ConsoleApplication1CS
    {
      public class Program20
      {
        static void Main(string[] args)
        {
          Stopwatch sw = new Stopwatch();
          DemoSerialize<ROOT> d = new DemoSerialize<ROOT>();
          string input;
          ROOT output;
          StringBuilder res;
          for (int i = 0; i < 10; i++)
          {
            input = (new StreamReader("Program20XML.xml")).ReadToEnd();
            sw.Restart();
            output = d.Deserialize(input);
            Console.WriteLine($"Zeit Deserialisierung: {sw.Elapsed.TotalMilliseconds:#0.000} ms");
            sw.Restart();
            res = d.Serialize(output);
            Console.WriteLine($"Zeit Serialisierung: {sw.Elapsed.TotalMilliseconds:#0.000} ms");
          }
          Console.ReadKey();
        }
    
        internal class DemoSerialize<T>
        {
          XmlSerializer ser = new XmlSerializer(typeof(T));
          StringBuilder sb = new StringBuilder(100000);
    
          internal StringBuilder Serialize(T obj)
          {
            sb.Clear();
            using (StringWriter wrt = new StringWriter(sb)) ser.Serialize(wrt, obj);
            return sb;
          }
          internal T Deserialize(string str)
          {
            using (StringReader rdr = new StringReader(str)) return (T)ser.Deserialize(rdr);
          }
        }
    
        [Serializable]
        public class ROOT
        {
          // ATTRIBUTES
          [XmlAttribute("info")]
          public string info { get; set; }
    
          // ELEMENTS
          [XmlElement("PROCESS_START_REQ")]
          public PROCESS_START_REQ PROCESS_START_REQ { get; set; } = new PROCESS_START_REQ();
    
          [XmlElement("CUSTOM")]
          public CUSTOM CUSTOM { get; set; } = new CUSTOM();
        }
    
        [Serializable]
        public class PROCESS_START_REQ
        {
          // ATTRIBUTES
          [XmlAttribute("code")]
          public string code { get; set; }
    
          [XmlAttribute("orientation")]
          public string orientation { get; set; }
    
          // ELEMENTS
          [XmlElement("SIDE1")]
          public SIDE1 SIDE1 { get; set; } = new SIDE1();
    
          // ELEMENTS
          [XmlElement("SIDE2")]
          public SIDE2 SIDE2 { get; set; } = new SIDE2();
        }
    
        [Serializable]
        public class SIDE1
        {
          // ELEMENTS
          [XmlElement("POSITIONS")]
          public POSITIONS POSITIONS { get; set; }
        }
    
        [Serializable]
        public class SIDE2
        {
          // ELEMENTS
          [XmlElement("POSITIONS")]
          public POSITIONS POSITIONS { get; set; }
        }
    
        [Serializable]
        public class POSITIONS
        {
          // ELEMENTS
          [XmlElement("POSITION")]
          public List<POSITION> ListPOSITION { get; set; } = new List<POSITION>();
       }
    
    
        [Serializable]
        public class POSITION
        {
          // ATTRIBUTES
          [XmlAttribute("number")]
          public int number { get; set; }
    
          [XmlAttribute("active")]
          public int active { get; set; }
    
          [XmlAttribute("badmark")]
          public int badmark { get; set; }
    
          // ELEMENTS
          [XmlText]
          public string Value { get; set; }
        }
    
        [Serializable]
        public class CUSTOM
        {
          // ELEMENTS
          [XmlText]
          public string Value { get; set; }
    
          [XmlIgnore]
          public Dictionary<string, string> DictCustom;
        }
    
    
        [Serializable]
        public class PropertyCustom
        {
          [XmlAttribute("scannerbeforeinletinfront", DataType = "string")]
          public string Name;
    
          [XmlAttribute("switchtoside1", DataType = "string")]
          public string Value;
        }
    
        [Serializable]
        public class PropertySerializer 
        {
          [XmlArrayItem("CUSTOM")]
          public List<PropertyCustom> Properties { get; set; } = new List<PropertyCustom>();
        }
      }
    }
    


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

    • Als Antwort markiert Sandra Bauer Dienstag, 3. Mai 2016 17:03
    Dienstag, 3. Mai 2016 07:09
  • Hallo Sandra,

    wenn Dich die jeweils längere erste Zeit stört, schau Dir SGEN an:

    XmlSerializer - mit sgen.exe die Performance optimieren (Thomas Bandt)

    Gruß Elmar

    • Als Antwort markiert Sandra Bauer Dienstag, 3. Mai 2016 17:10
    Dienstag, 3. Mai 2016 11:40
    Beantworter

Alle Antworten

  • Hallo Sandra,

    ich würde eine Methode mit dem XmlReader schreiben. Ohne es jetzt bewiesen zu haben, glaube ich, dass das die schnellste Art und Weise ist. Man muss möglicherweise ein paar Zeilen mehr schreiben als beim Serialisieren. Aber schneller ist es glaube ich bestimmt.

    Gruß

    Freitag, 29. April 2016 18:00
  • Hallo zusammen,

    Mit welcher Library lese ich so ein XML Dokument optimal ein?
    1. Muss es zwingend eine Library sein oder geht auch ein in .NET eingebautes Feature...?
    2. Was meinst du mit Optimal? Ich persönlich mag Serialisierung, das ist aber nur schnell wenn man oft darauf zugreift. Auch kann LinQ to XML "optimal" sein wenn du Datenbankquery-Artige Abfragen brauchst. Was willst du also?
    3. Um was für ein Dokument handelt es sich? Um so größer desto effektiver dürfte der XmlReader werden.
    4. Wie oft werden die Daten verarbeitet? Um so öfter desto mehr dürfte sich eine Serialisierung auszahlen da dann alles im RAM liegt.

    Meine Leistungseinschätzung in 3. und 4. bezieht sich jeweils auf die Zugriffsgeschwindigkeit.


    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

    Freitag, 29. April 2016 21:45
    Moderator
  • ich würde eine Methode mit dem XmlReader schreiben.

    Hallo K.Pater,

    kannst Du das kurz aufzeigen, wie Du das mit dem XMLReader machen würdest. Danke vorab.

    Grüße Sandra

    Samstag, 30. April 2016 14:12
    1. Um was für ein Dokument handelt es sich? Um so größer desto effektiver dürfte der XmlReader werden.
    2. Wie oft werden die Daten verarbeitet? Um so öfter desto mehr dürfte sich eine Serialisierung auszahlen da dann alles im RAM liegt.

    Hallo Tom,

    um solche. 10 verschiedene, ähnlich aufgebaut.

    Alle 2 Sekunden wird eines aufgerufen. Es muss in 1, max 3 ms verarbeitet werden können.

    Grüße Sandra

    <ROOT info="ToDo - Working product">
      <PROCESS_START id="7878554" ori="90°" side="">
        <SIDE1>
          <POSITIONS>
            <POSITION x="1" y="1" />
            <POSITION x="2" y="1" />
            <POSITION x="3" y="1" />
            <POSITION x="4" y="1" />
            <POSITION x="5" y="1" />
            <POSITION x="6" y="1" />
            <POSITION x="7" y="1" />
            <POSITION x="8" y="1" />
            <POSITION x="9" y="1" />
            <POSITION x="10" y="1" />
            <POSITION x="11" y="1" />
            <POSITION x="12" y="1" />
            <POSITION x="13" y="1" />
            <POSITION x="14" y="1" />
            <POSITION x="15" y="1" />
            <POSITION x="16" y="1" />
            <POSITION x="17" y="1" />
          </POSITIONS>
        </SIDE1>
        <SIDE2>
          <POSITIONS>
            <POSITION x="1" y="21" />
            <POSITION x="2" y="31" />
            <POSITION x="3" y="41" />
          </POSITIONS>
        </SIDE2>
      </PROCESS_START>
      <CUSTOM color="0" background="0" />
    </ROOT>

    Samstag, 30. April 2016 14:15
  • Hallo Sandra,

    hier mal eine Demo. Es wird vermutlich nicht ganz für dich passen, aber so in der Richtung würde ich das vermutlich angehen. Damit man die Daten einsehen kann, habe ich zwei kleine Hilfsklassen beigefügt, in denen die eingelesenen Daten abgelegt werden.

    Der Reader liest einfach ein Element nach dem anderen ein, es wird geprüft um welches Element es sich handelt und ggf. die Attribute eingelesen. Mal über Index, mal benannt.

    Es ist jetzt so angelegt, dass im ROOT-Node auch mehrere PROCESS_START-Nodes vorkommen können, also auch so was:

    Das kann man alles verfeinern, wenn man Sinn und Zweck der XML-Daten kennt, aber ich hoffe, die Verwendung des XmlReaders wird ersichtlich.

    Der XmlReader hat weitere Navigationsmöglichkeiten (z.B. ReadToFollowing(), ..), hier verwende ich aber durchgängig  nur .Read()

    Als Konsolenprogramm:

    using System; using System.Collections.Generic; using System.Xml; namespace XMLTool { class Program { static void Main(string[] args) { ReadXML(@"d:\test1.xml"); Console.ReadLine(); } static void ReadXML(string filename) { XmlReaderSettings settings = new XmlReaderSettings() { ConformanceLevel = ConformanceLevel.Fragment, IgnoreComments = true, IgnoreWhitespace = true, CheckCharacters = false }; Prozesse myProzesse = new Prozesse(); Prozess myProzess = null; int side = 0; using ( XmlReader reader = XmlReader.Create(filename, settings) ) { reader.Read(); while ( !reader.EOF ) { if ( reader.NodeType == XmlNodeType.Element ) { if ( reader.Name.ToUpper() == "PROCESS_START" ) { myProzess = new Prozess(); while ( reader.MoveToNextAttribute() ) { myProzess.attributes.Add(reader.Name, reader.Value); } } if ( reader.Name.ToUpper() == "SIDE1" ) { side = 1; } if ( reader.Name.ToUpper() == "SIDE2" ) { side = 2; } if ( reader.Name.ToUpper() == "POSITION" ) { if ( side == 1 ) {
    // Attribute über Index... myProzess.Side1.Add(new Prozess.Position(reader.GetAttribute(0), reader.GetAttribute(1))); } if ( side == 2 ) { myProzess.Side2.Add(new Prozess.Position(reader.GetAttribute(0), reader.GetAttribute(1))); } } if ( reader.Name.ToUpper() == "CUSTOM" ) { myProzesse.attributes.Add("color", reader.GetAttribute("color")); myProzesse.attributes.Add("background", reader.GetAttribute("background")); } } if ( reader.NodeType == XmlNodeType.EndElement && reader.Name.ToUpper() == "PROCESS_START" ) { myProzesse.prozesse.Add(myProzess.attributes["id"], myProzess); } reader.Read(); } } return; }
    } public class Prozess { public Dictionary<string, string> attributes = new Dictionary<string, string>(); public List<Position> Side1 = new List<Position>(); public List<Position> Side2 = new List<Position>(); public class Position { public int x; public int y; public Position(string px, string py) { int.TryParse(px, out x); int.TryParse(py, out y); } public Position(int px, int py) { x = px; y = py; } } } public class Prozesse { public Dictionary<string, string> attributes = new Dictionary<string, string>(2048); public Dictionary<string, Prozess> prozesse = new Dictionary<string, Prozess>(2048); public Prozess GetProzess(string id) { if(prozesse.ContainsKey(id)) { return prozesse[id]; } else { return null; } } } }

    Gruß


    Samstag, 30. April 2016 15:25
  • Hallo Sandra,

    ein XmlReader wäre nur notwendig wenn die Dokumente groß (MB) sind, also z. B. sehr viele Prozesse in einem Dokument existieren. Was umgekehrt die Handhabbarkeit allgemein verschlechtern würde - das steht aber auf einem anderen Blatt.

    Sollte dem so sein kann man es auch mit LINQ to Xml in verbindung mit Streaming erledigen, siehe dazu: Vorgehensweise: Ausführen von Streamingtransformationen bei großen XML-Dokumenten (wobei K. Paters Lösung einfließen kann).

    Ansonsten tut es auch ein XDocument. Wobei ich die Daten in Klassen übertragen würde. Beim Konvertieren stellt XLinq bereits die notwendigen Methoden bereit - siehe XAttribute (entprechend XElement):

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Xml.Linq;
    
    namespace ElmarBoye.Samples.Code
    {
        internal class XmlSandraBauerTodo
        {
            internal static Process Load()
            {
                var process = new Process();
                var document = XDocument.Load(@"C:\TEMP\Sandra_Bauer_ToDo.xml");
    
                // Auslagern in eine Methode würde es vereinfachen, 
                // wenn SIDE1, SIDE2 (weitgehend) identisch sind
                XElement processStart = document.Root.Element("PROCESS_START");
                foreach (XElement position in processStart.Element("SIDE1").Element("POSITIONS").Elements("POSITION"))
                {
                    process.Side1.Positions.Add(new Position(
                        (int)position.Attribute("x"),
                        (int)position.Attribute("y")));
                }
                // wie vor nur SIDE2
                foreach (XElement position in processStart.Element("SIDE2").Element("POSITIONS").Elements("POSITION"))
                {
                    process.Side2.Positions.Add(new Position(
                        (int)position.Attribute("x"),
                        (int)position.Attribute("y")));
                }
                return process;
            }
        }
    
        public class Process
        {
            public Process() 
            {            
                Side1 = new Side();
                Side2 = new Side();
            }
    
            public Side Side1 { get; private set; }
            public Side Side2 { get; private set; }
        }
    
        public class Side
        {
            public Side() { Positions = new List<Position>(); }
    
            public IList<Position> Positions { get; private set; }
        }
    
        [DebuggerDisplay("X={X}, Y={Y}")]
        public class Position
        {
            public Position(int x, int y) { X = x; Y = y; }
            public int X { get; set; }
            public int Y { get; set; }
    
            public override string ToString()
            {
                return String.Format("Position x=\"{0}\", y=\"{1}\"");
            }
        }
    }

    Gruß Elmar


    Samstag, 30. April 2016 16:14
    Beantworter
  • Hallo Zusammen,

    könnt Ihr mir noch die Zeiten der Releaseversion posten.

    Die max. Daten liegen bei 150 Positionen, 2 Seiten, also im gesamten 300 Positionen.

    @Elmar,

        es muss nur schnell sein, das muss ich dann wählen und ich muss auf unter 3ms kommen.

    Viele Grüße Sandra

    Samstag, 30. April 2016 16:27
  • Das kann man alles verfeinern, wenn man Sinn und Zweck der XML-Daten kennt, aber ich hoffe, die Verwendung des XmlReaders wird ersichtlich.

    Der XmlReader hat weitere Navigationsmöglichkeiten (z.B. ReadToFollowing(), ..), hier verwende ich aber durchgängig  nur .Read()


    Hallo K. Pater,

    vielen Dank. Wie gesagt es muss schnell sein. Nur das zählt. Verwendung wurde mir ersichtlich. DANKE.

    Serialisierung ist zu langsam. Die XML Inhalte sind immer ähnlich aufgebaut.

    @K.Pater, Elmar

         Deshalb brauche ich die Zeiten.

             Meine Tests  C:\_Prog\ ist immer das LogFile.

    Ich muss auf unter 3ms kommen. C++ schafft es unter 1ms.

    Hintergrund, ich muss ein Projekt von C++ nach C# portieren und es sollte ja nicht langsamer werden.

    • XDocument     bis zu 10 ms (meine Tests)
    • XmlReader
    • Serialisierung    bis zu 30ms

         Grüße Sandra und Danke vorab


    Samstag, 30. April 2016 16:44
  • Hallo Sandra,

    da es vermutlich doch nur 1 PROCESS_START - Node gibt, habe ich jetzt mal die "Prozesse" Auflistung rausgenommen und nur die "Prozess"-Klasse befüllt.Mit StopWatch wird mir da 1ms (jeweils 150 Positionen unter SIDE1 bzw. SIDE2) angezeigt:

    static void ReadXML(string filename) { XmlReaderSettings settings = new XmlReaderSettings() { ConformanceLevel = ConformanceLevel.Fragment, IgnoreComments = true, IgnoreWhitespace = true, CheckCharacters = false }; Prozess myProzess = null; int side = 0; Stopwatch sw = new Stopwatch(); sw.Start(); using ( XmlReader reader = XmlReader.Create(filename, settings) ) { reader.Read(); while ( !reader.EOF ) { if ( reader.NodeType == XmlNodeType.Element ) { if ( reader.Name.ToUpper() == "PROCESS_START" ) { myProzess = new Prozess(); myProzess.ID = reader.GetAttribute("id"); myProzess.ori = reader.GetAttribute("ori"); myProzess.side = reader.GetAttribute("side"); } if ( reader.Name.ToUpper() == "SIDE1" ) { side = 1; } if ( reader.Name.ToUpper() == "SIDE2" ) { side = 2; } if ( reader.Name.ToUpper() == "POSITION" ) { if ( side == 1 ) myProzess.Side1.Add(new Prozess.Position(reader.GetAttribute("x"), reader.GetAttribute("y"))); if ( side == 2 ) myProzess.Side2.Add(new Prozess.Position(reader.GetAttribute("x"), reader.GetAttribute("y"))); } if ( reader.Name.ToUpper() == "CUSTOM" ) { myProzess.color= reader.GetAttribute("color"); myProzess.background = reader.GetAttribute("background"); } } reader.Read(); } } sw.Stop(); Console.WriteLine("Dauer [ms]: " + sw.ElapsedMilliseconds.ToString()); return; } public class Prozess { public string ID; public string ori; public string side; public string color; public string background; public List<Position> Side1 = new List<Position>(); public List<Position> Side2 = new List<Position>();

    public class Position { public int x; public int y; public Position(string px, string py) { int.TryParse(px, out x); int.TryParse(py, out y); } public Position(int px, int py) { x = px; y = py; } } }

    Das ist halt eine schlichte Lösung die mit einem Minimum an Technologie funktioniert.

    Ich glaube auch nicht, dass der XmlReader bei kleineren Dateien gegenüber anderen Ansätzen nachteilig wäre. Falls ich mich nicht irre, ist dies mit der schlankeste Ansatz.

    Gruß

    Nachtrag, noch mal etwas optimiert:-)

    static void ReadXML1(string filename) {
      XmlReaderSettings settings = new XmlReaderSettings() {
        ConformanceLevel = ConformanceLevel.Fragment,
        IgnoreComments = true,
        IgnoreWhitespace = true,
        CheckCharacters = false
      };
    
      Prozess myProzess = new Prozess();
      using ( XmlReader reader = XmlReader.Create(filename, settings) ) {
        reader.ReadToFollowing("PROCESS_START");
        myProzess.ID = reader.GetAttribute("id");
        myProzess.ori = reader.GetAttribute("ori");
        myProzess.side = reader.GetAttribute("side");
    
        reader.ReadToFollowing("POSITIONS");
        using ( XmlReader sideReader = reader.ReadSubtree() ) {
         sideReader.Read(); // -> POSITIONS
          sideReader.Read(); // -> 1te POSITION
          while (!sideReader.EOF) {
            if (sideReader.NodeType == XmlNodeType.Element)
               myProzess.Side1.Add(new Prozess.Position(sideReader.GetAttribute("x"), sideReader.GetAttribute("y")));
            sideReader.Read();
          }
        }

        reader.ReadToFollowing("POSITIONS");
        using ( XmlReader sideReader = reader.ReadSubtree() ) {
         sideReader.Read(); // -> POSITIONS
          sideReader.Read(); // -> 1te POSITION
          while ( !sideReader.EOF ) {
          if ( sideReader.NodeType == XmlNodeType.Element )
             myProzess.Side2.Add(new Prozess.Position(sideReader.GetAttribute("x"), sideReader.GetAttribute("y")));
            sideReader.Read();
          }
        } reader.ReadToFollowing("CUSTOM"); myProzess.color = reader.GetAttribute("color"); myProzess.background = reader.GetAttribute("background"); } return; }

    Hier liefert die Zeitmessung bei 1000 Durchläufen 00:00:00.298 , also ungefähr 0,3 ms für einen Durchlauf (wenn ich mich jetzt nicht mit der Einheit vertue)...

    Gruß




    • Bearbeitet K. Pater Sonntag, 1. Mai 2016 08:03 Korrektur
    Samstag, 30. April 2016 17:55
  • Hallo Sandra,

    sorry, da passt bei Deiner Hardware etwas nicht. Mein Code und obiges Xml auf 500 Zeilen via Positionen aufgeblasen, ergibt bei drei Durchläufen via Stopwatch.Elapsed:

    00:00:00.0096515 ms
    00:00:00.0010772 ms
    00:00:00.0012852 ms

    der erste Durchlauf braucht naturgemäß länger, da die Bibliotheken geladen und gejittet werden müssen. Release wird nicht wirklich schneller:

    00:00:00.0040283 ms
    00:00:00.0012811 ms
    00:00:00.0012533 ms

    (ausgeführt auf einem sechs Jahre alten Rechner - also nicht gerade aktuell ;)

    Gruß Elmar

    Samstag, 30. April 2016 19:33
    Beantworter
  • Hallo,

    könnt Ihr mal mein Beispiel testen oder Euer Beispiel hochladen.

    XMLReader 0.3 ms

    XDocument 1.2 ms

    wenn ich es richtig interpretiere. Danke.

    Grüße Sandra


    Sonntag, 1. Mai 2016 12:02
  • Hallo Sandra,

    mein Beispiel stehen oben, Du brauchst den Aufruf nur noch über eine Stopwatch messen:

    Die Zeiten scheinen mir reichlich hoch. Bitte führe den Aufruf mindestens drei Mal aus - anfangs kommen häufig Ladezeiten für Assemblies hinzu; die Zeiten kann man vermeiden, in dem man die Instanz mehrmalig nutzt:

      var watch = Stopwatch.StartNew();
      XmlSandraBauerTodo.Load();
      Console.WriteLine("{0} ms", watch.Elapsed);

    Gruß Elmar

    Sonntag, 1. Mai 2016 14:59
    Beantworter
  • Hallo Sandra,

    die 1,2 ms, die Elmar gemessen hatte, resultieren bestimmt von dem etwas schwächeren Rechner her. Um es vergleichbar zu machen, habe ich mal beide Beispiele verglichen. Da kommt dann statt 1,2 ms 0,4 ms heraus. Im Unterschied dazu ist mein Beispiel also nur etwa 25% schneller.

    Aber mal ehrlich: Ob 0,3ms oder 0,4ms, beides dürften Resultate sein, mit denen du leben kannst. Nimm den Ansatz, der besser in dein Konzept passt.

    Die verwendete Datei "xyz.xml" ist einfach deine Vorgabe von oben mit jeweils 150 Positionen für Side1 und Side2.

    Hier noch mal das komplette Konsolenprojekt (ich sehe gerade nicht, wie ich das anders hochladen kann):

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Xml;
    
    namespace XMLTool {
    	class Program {
    		static void Main(string[] args) {
    			Stopwatch sw = new Stopwatch();
    			sw.Start();
    			for ( int i = 0 ; i < 1000 ; i++ ) {
    				ReadXML(@"d:\xyz.xml");
    			}
    			sw.Stop();
    			Console.WriteLine("Summe-Dauer [h:m:s]: " + sw.Elapsed.ToString());
    			Console.ReadLine();
    		}
    
    		static Prozess ReadXML(string filename) {
    			XmlReaderSettings settings = new XmlReaderSettings() {
    				ConformanceLevel = ConformanceLevel.Fragment,
    				IgnoreComments = true,
    				IgnoreWhitespace = true,
    				CheckCharacters = false
    			};
    
    			Prozess myProzess = new Prozess();
    			using ( XmlReader reader = XmlReader.Create(filename, settings) ) {
    				reader.ReadToFollowing("PROCESS_START");
    				myProzess.ID = reader.GetAttribute("id");
    				myProzess.ori = reader.GetAttribute("ori");
    				myProzess.side = reader.GetAttribute("side");
    
    				reader.ReadToFollowing("POSITIONS");
    				using ( XmlReader sideReader = reader.ReadSubtree() ) {
    					sideReader.Read(); // -> POSITIONS
    					sideReader.Read(); // -> 1te POSITION
    					while ( !sideReader.EOF ) {
    						if ( sideReader.NodeType == XmlNodeType.Element )
    							myProzess.Side1.Add(new Prozess.Position(sideReader.GetAttribute("x"), sideReader.GetAttribute("y")));
    						sideReader.Read();
    					}
    				}
    
    				reader.ReadToFollowing("POSITIONS");
    				using ( XmlReader sideReader = reader.ReadSubtree() ) {
    					sideReader.MoveToElement();
    					sideReader.Read(); // -> POSITIONS
    					sideReader.Read(); // -> 1te POSITION
    					while ( !sideReader.EOF ) {
    						if ( sideReader.NodeType == XmlNodeType.Element )
    							myProzess.Side2.Add(new Prozess.Position(sideReader.GetAttribute("x"), sideReader.GetAttribute("y")));
    						sideReader.Read();
    					}
    				}
    
    				reader.ReadToFollowing("CUSTOM");
    				myProzess.color = reader.GetAttribute("color");
    				myProzess.background = reader.GetAttribute("background");
    			}
    			return myProzess;
    		}
    	}
    
    	public class Prozess {
    		public string ID;
    		public string ori;
    		public string side;
    		public string color;
    		public string background;
    		public List<Position> Side1 = new List<Position>();
    		public List<Position> Side2 = new List<Position>();
    		public class Position {
    			public int x;
    			public int y;
    			public Position(string px, string py) {
    				int.TryParse(px, out x);
    				int.TryParse(py, out y);
    			}
    		}
    	}
    }

    Gruß



    • Bearbeitet K. Pater Sonntag, 1. Mai 2016 16:50
    • Als Antwort markiert Sandra Bauer Dienstag, 3. Mai 2016 17:11
    Sonntag, 1. Mai 2016 16:13
  • Hallo,
    ich bedanke mich.
    Es wäre schön, wie das Verhalten bei Euch ist.
    Beim Starten benötige ich länger. Erklärbar JIT Compiler.

    Aber auch sonst, kann es vorkommen, dass es länger benötigt.
      Hat jemand hierfür eine Erklärung?

    Sonst können wir diesen Thread sicher schließen.

    Viele Grüße Sandra

    //02-05-2016 18:17:09:2555 -->    START - XDocument
    //02-05-2016 18:17:09:2955 -->    ENDE - XDocument
    //02-05-2016 18:17:11:4946 -->    START - XDocument
    //02-05-2016 18:17:11:4956 -->    ENDE - XDocument
    //02-05-2016 18:17:12:3587 -->    START - XDocument
    //02-05-2016 18:17:12:3587 -->    ENDE - XDocument
    //02-05-2016 18:17:12:9107 -->    START - XDocument
    //02-05-2016 18:17:12:9127 -->    ENDE - XDocument
    //02-05-2016 18:17:13:4947 -->    START - XDocument
    //02-05-2016 18:17:13:4947 -->    ENDE - XDocument
    
    
    //02-05-2016 18:17:15:0708 -->    START - XMLReader
    //02-05-2016 18:17:15:0728 -->    ENDE - XMLReader
    //02-05-2016 18:17:16:1029 -->    START - XMLReader
    //02-05-2016 18:17:16:1029 -->    ENDE - XMLReader
    //02-05-2016 18:17:16:8469 -->    START - XMLReader
    //02-05-2016 18:17:16:8469 -->    ENDE - XMLReader
    //02-05-2016 18:17:17:4950 -->    START - XMLReader
    //02-05-2016 18:17:17:4950 -->    ENDE - XMLReader
    //02-05-2016 18:17:18:4940 -->    START - XMLReader
    //02-05-2016 18:17:18:4950 -->    ENDE - XMLReader
    //02-05-2016 18:17:19:2231 -->    START - XMLReader
    //02-05-2016 18:17:19:2231 -->    ENDE - XMLReader

       
    Montag, 2. Mai 2016 16:41
  • Hallo Sandra,

    die Unterschiede bei den Zeitmessungen können verschiedenen Ursachen haben. Verwendest du denn, wie gezeigt, die StopWatch? Mit der StopWatch kann ich nicht glauben, dass du sooo oft praktisch keine Zeit ermittelst.

    Nun, wie auch immer, es mag natürlich auch mit deiner Hardware zusammenhängen. Wenn dir andere kostenintensive Prozesse die Ressourcen wegfressen, wirst du immer irgendwie Schwankungen bekommen. Ich fürchte, damit muss man leben (oder eben leistungsfähigere Hardware beschaffen).

    Ansonsten glaube ich, ist mit den gegebenen Mitteln das Ende der Fahnenstange erreicht. Letztendlich solltest du vielleicht die Performance aber auch auf dem Produktivsystem testen und nicht auf deinem Entwicklungsrechner.

    Gruß

    Montag, 2. Mai 2016 17:55
  • Hallo Sandra,

    das Datum lässt die starke Vermutung aufkommen, Du hast mit System.DateTime gemessen. Das ist aber chronisch ungenau, deswegen immer mit der Stopwatch Klasse messen. Nur die kann präzise Ergebnisse liefern (wenn HighPrecision wahr ist).

    Gruß Elmar

    Montag, 2. Mai 2016 18:12
    Beantworter
  • Hi Sandra,
    ich habe mal mit Deinen Angaben eine Release-Version getestet und die folgenden Ergebnisse bekommen. Mein Laptop ist mit 7 Jahren schon etwas älter.

    Zeit Deserialisierung: 7,624 ms
    Zeit Serialisierung: 2,856 ms
    Zeit Deserialisierung: 0,082 ms
    Zeit Serialisierung: 0,103 ms
    Zeit Deserialisierung: 0,090 ms
    Zeit Serialisierung: 0,101 ms
    Zeit Deserialisierung: 0,092 ms
    Zeit Serialisierung: 0,117 ms
    Zeit Deserialisierung: 0,085 ms
    Zeit Serialisierung: 0,096 ms
    Zeit Deserialisierung: 0,108 ms
    Zeit Serialisierung: 0,144 ms
    Zeit Deserialisierung: 0,119 ms
    Zeit Serialisierung: 0,107 ms
    Zeit Deserialisierung: 0,084 ms
    Zeit Serialisierung: 0,167 ms
    Zeit Deserialisierung: 0,215 ms
    Zeit Serialisierung: 0,159 ms
    Zeit Deserialisierung: 0,136 ms
    Zeit Serialisierung: 0,160 ms

    Die Test-Konsolenanwendung dazu:

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Xml.Linq;
    using System.Xml.Serialization;
    
    namespace ConsoleApplication1CS
    {
      public class Program20
      {
        static void Main(string[] args)
        {
          Stopwatch sw = new Stopwatch();
          DemoSerialize<ROOT> d = new DemoSerialize<ROOT>();
          string input;
          ROOT output;
          StringBuilder res;
          for (int i = 0; i < 10; i++)
          {
            input = (new StreamReader("Program20XML.xml")).ReadToEnd();
            sw.Restart();
            output = d.Deserialize(input);
            Console.WriteLine($"Zeit Deserialisierung: {sw.Elapsed.TotalMilliseconds:#0.000} ms");
            sw.Restart();
            res = d.Serialize(output);
            Console.WriteLine($"Zeit Serialisierung: {sw.Elapsed.TotalMilliseconds:#0.000} ms");
          }
          Console.ReadKey();
        }
    
        internal class DemoSerialize<T>
        {
          XmlSerializer ser = new XmlSerializer(typeof(T));
          StringBuilder sb = new StringBuilder(100000);
    
          internal StringBuilder Serialize(T obj)
          {
            sb.Clear();
            using (StringWriter wrt = new StringWriter(sb)) ser.Serialize(wrt, obj);
            return sb;
          }
          internal T Deserialize(string str)
          {
            using (StringReader rdr = new StringReader(str)) return (T)ser.Deserialize(rdr);
          }
        }
    
        [Serializable]
        public class ROOT
        {
          // ATTRIBUTES
          [XmlAttribute("info")]
          public string info { get; set; }
    
          // ELEMENTS
          [XmlElement("PROCESS_START_REQ")]
          public PROCESS_START_REQ PROCESS_START_REQ { get; set; } = new PROCESS_START_REQ();
    
          [XmlElement("CUSTOM")]
          public CUSTOM CUSTOM { get; set; } = new CUSTOM();
        }
    
        [Serializable]
        public class PROCESS_START_REQ
        {
          // ATTRIBUTES
          [XmlAttribute("code")]
          public string code { get; set; }
    
          [XmlAttribute("orientation")]
          public string orientation { get; set; }
    
          // ELEMENTS
          [XmlElement("SIDE1")]
          public SIDE1 SIDE1 { get; set; } = new SIDE1();
    
          // ELEMENTS
          [XmlElement("SIDE2")]
          public SIDE2 SIDE2 { get; set; } = new SIDE2();
        }
    
        [Serializable]
        public class SIDE1
        {
          // ELEMENTS
          [XmlElement("POSITIONS")]
          public POSITIONS POSITIONS { get; set; }
        }
    
        [Serializable]
        public class SIDE2
        {
          // ELEMENTS
          [XmlElement("POSITIONS")]
          public POSITIONS POSITIONS { get; set; }
        }
    
        [Serializable]
        public class POSITIONS
        {
          // ELEMENTS
          [XmlElement("POSITION")]
          public List<POSITION> ListPOSITION { get; set; } = new List<POSITION>();
       }
    
    
        [Serializable]
        public class POSITION
        {
          // ATTRIBUTES
          [XmlAttribute("number")]
          public int number { get; set; }
    
          [XmlAttribute("active")]
          public int active { get; set; }
    
          [XmlAttribute("badmark")]
          public int badmark { get; set; }
    
          // ELEMENTS
          [XmlText]
          public string Value { get; set; }
        }
    
        [Serializable]
        public class CUSTOM
        {
          // ELEMENTS
          [XmlText]
          public string Value { get; set; }
    
          [XmlIgnore]
          public Dictionary<string, string> DictCustom;
        }
    
    
        [Serializable]
        public class PropertyCustom
        {
          [XmlAttribute("scannerbeforeinletinfront", DataType = "string")]
          public string Name;
    
          [XmlAttribute("switchtoside1", DataType = "string")]
          public string Value;
        }
    
        [Serializable]
        public class PropertySerializer 
        {
          [XmlArrayItem("CUSTOM")]
          public List<PropertyCustom> Properties { get; set; } = new List<PropertyCustom>();
        }
      }
    }
    


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

    • Als Antwort markiert Sandra Bauer Dienstag, 3. Mai 2016 17:03
    Dienstag, 3. Mai 2016 07:09
  • Hallo Sandra,

    wenn Dich die jeweils längere erste Zeit stört, schau Dir SGEN an:

    XmlSerializer - mit sgen.exe die Performance optimieren (Thomas Bandt)

    Gruß Elmar

    • Als Antwort markiert Sandra Bauer Dienstag, 3. Mai 2016 17:10
    Dienstag, 3. Mai 2016 11:40
    Beantworter
  • Hallo!

    Danke an Alle für Eure Unterstützung.

    Ich komme jetzt auf die Zeiten von Peter.

    Grüße Sandra

    Dienstag, 3. Mai 2016 17:13