Laden...

XML Elemente auslesen und weiterverarbeiten

Erstellt von c#atriga vor 5 Jahren Letzter Beitrag vor 5 Jahren 4.324 Views
C
c#atriga Themenstarter:in
34 Beiträge seit 2018
vor 5 Jahren
XML Elemente auslesen und weiterverarbeiten

Ich habe eine xml Datei, welche ich gern einlesen würde.
Einzelne Werte kann ich via folgendem Code schon einlesen:

XmlReader reader = XmlReader.Create(@"C:\Users\User\Desktop\textdaten.xml");

while (reader.Read())
{
	if (reader.NodeType == XmlNodeType.Element && reader.Name == "beschreibung")
	{
		string tmp = reader.ReadElementContentAsString();
		Console.WriteLine(tmp);
	}
}

Console.ReadKey();

Folgende Fragen hätte ich jetzt:

  1. Es sind über 40 Elemente vorhanden. Müsste ich für jedes Element den obigen (abgewandelten) Code nutzen, oder geht es einfacher? Ich möchte mit den einzelnen Elementen am Ende arbeiten können.
  2. Ist XML Reader überhaupt der richtige Einstiegspunkt? LINQ gibt es ja auch noch, oder?

Dies gehört vielleicht nicht in dieses Forum, aber vlt. kann doch wer helfen.
3. Kennt jemand ein gutes Tutorial welches das ganze XML einlesen und schreiben richtig gut erklärt. Gern auch eine Buchempfehlung

1.029 Beiträge seit 2010
vor 5 Jahren

Hi,

naja - ob jetzt der XmlReader oder Linq2Xml oder sogar Serialisierung/Deserialisierung das richtige ist hängt stark von den Daten und der Art der Verwendung ab.

Grundlegend klingt deine Beschreibung danach, als ob du entweder Linq2Xml oder sogar Deserialisierung einsetzen solltest.

Bei der Deserialisierung versucht man z.B. das komplette XML-Dokument in Instanzen von Klassen zu laden - siehe auch:

Bei Linq2Xml ist es so, dass man mit Linq auf Xml-Basis arbeiten kann und dort dann ggf. Klassen instanziiert.

Grundlegend einlesen könntest du dich unter:
http://openbook.rheinwerk-verlag.de/visual_csharp_2010/visual_csharp_2010_16_001.htm

LG

B
153 Beiträge seit 2014
vor 5 Jahren

Spontan würde mir das Stichwort DeSerializierung einfallen.
Letztendlich baust du eine Klasse welche alle Knoten als Property enthält die auch in der XML vorhanden sind. Knoten mit Kind Elementen sind dann einfach weitere Klassen die da drin sind.

Das DeSerializieren und Serialisieren ist dann mit ein paar zeilen erledigt.

EDIT: zu langsam

[Space Opera Blog](http://bradley-software.blogspot.com/)
[Space Opera Forum](http://forum.bradley-labs.de/)
C
c#atriga Themenstarter:in
34 Beiträge seit 2018
vor 5 Jahren

So sehen die xml Dateien aus, sind eigentlich gpx Dateien.

<gpx xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="1.0" creator="GSAK"
xsi:schemaLocation="http://www.topografix.com/GPX/1/0 http://www.topografix.com/GPX/1/0/gpx.xsd http://www.groundspeak.com/cache/1/0/1 http://www.groundspeak.com/cache/1/0/1/cache.xsd"
xmlns="http://www.topografix.com/GPX/1/0">
 <desc>Geocache file generated by GSAK</desc>
 <author>GSAK</author>
 <email>support@gsak.net</email>
 <time>2018-09-11T10:08:56Z</time>
 <keywords>cache, geocache, groundspeak</keywords>
 <bounds minlat="51.592861" minlon="9.36191" maxlat="51.592861" maxlon="9.36191"/>
 <wpt lat="51.592861" lon="9.36191">
  <time>2017-12-28T08:00:00Z</time>
  <name>GC7GE5J</name>
  <desc>Ranzenplatz by ManrodeCacher (1,5/2) Ranzenplatzc</desc>
  <url>http://www.geocaching.com/seek/cache_details.aspx?guid=643f622e-1811-4501-b37c-53deed88e1c1</url>
  <urlname>Ranzenplatz by ManrodeCacher</urlname>
  <sym>Geocache</sym>
  <type>Geocache|Traditional Cache</type>
  <groundspeak:cache id="6543810" available="True" archived="False" xmlns:groundspeak="http://www.groundspeak.com/cache/1/0/1">
   <groundspeak:name>Ranzenplatz</groundspeak:name>
   <groundspeak:placed_by>ManrodeCacher</groundspeak:placed_by>
   <groundspeak:owner id="21439226">ManrodeCacher</groundspeak:owner>
   <groundspeak:type>Traditional Cache</groundspeak:type>
   <groundspeak:container>Micro</groundspeak:container>
   <groundspeak:attributes>
     <groundspeak:attribute id="1" inc="1">Dogs</groundspeak:attribute>
     <groundspeak:attribute id="7" inc="1">Takes less than an hour</groundspeak:attribute>
     <groundspeak:attribute id="8" inc="1">Scenic view</groundspeak:attribute>
     <groundspeak:attribute id="13" inc="1">Available at all times</groundspeak:attribute>
     <groundspeak:attribute id="15" inc="1">Available during winter</groundspeak:attribute>
     <groundspeak:attribute id="32" inc="1">Bicycles</groundspeak:attribute>
     <groundspeak:attribute id="37" inc="1">Horses</groundspeak:attribute>
   </groundspeak:attributes>
   <groundspeak:difficulty>1.5</groundspeak:difficulty>
   <groundspeak:terrain>2</groundspeak:terrain>
   <groundspeak:country>Germany</groundspeak:country>
   <groundspeak:state>Nordrhein-Westfalen</groundspeak:state>
   <groundspeak:short_description html="True"> </groundspeak:short_description>
   <groundspeak:long_description html="True">&lt;p&gt;Dieser Cache führt zum Ranzenplatz bei Manrode. Von hier aus hat man einen guten Ausblick bis zum Reinhardswald. &lt;/p&gt;

&lt;p&gt;Bitte einen Stift mitbringen!&lt;/p&gt;

&lt;p&gt;Viel Spaß beim Suchen&lt;img alt="smiley" src="https://www.geocaching.com/static/js/CKEditor/4.4.0/plugins/smiley/images/regular_smile.png" style="height:23px; width:23px" title="smiley" /&gt;?!&lt;/p&gt;</groundspeak:long_description>
    <groundspeak:encoded_hints>Ich liege an der Bank in einem PETling.</groundspeak:encoded_hints>
   <groundspeak:logs>
  </groundspeak:logs>
   <groundspeak:travelbugs>
   </groundspeak:travelbugs>
</groundspeak:cache>
</wpt>
</gpx>

1.029 Beiträge seit 2010
vor 5 Jahren

Da würde ich persönlich wahrscheinlich Linq2Xml verwenden.

LG

3.003 Beiträge seit 2006
vor 5 Jahren

Ist eigentlich eine Fleißarbeit. Und weil VS dir Arbeit abnehmen möchte, kannst du folgendes machen:

  • kopier dein Beispiel-XML (ab damit in die Zwischenablage)
  • Visual Studio: Shift+Alt+C (neue Klasse hinzufügen (Name egal))
  • Menü: Bearbeiten -> Inhalte einfügen -> XML als Klassen einfügen
  • Nach Bedarf umbenennen / refaktorieren (sind mit Resharper einige wenige Klicks)

Bei mir hiess die Root-Klasse (hat das XmlRootAttribute) "gpx"

Bleiben zwei Zeilen Code, die du wirklich selbst schreiben musst:


public gpx DeserializeStream(Stream stream)
{
    var serializer = new XmlSerializer(typeof(gpx));
    return (gpx)serializer.Deserialize(stream);
}

Viel Spaß.

LaTino
(EDIT: ich würde bei vorgegebenen, standardisierten XML-Formaten unter keinen Umständen Linq2Xml verwenden. Man hat hier einen ganz Strauß an Tools, die man verwenden kann und die gut mikteinander funktionieren, vom Schema-Validator bis zum Serialisierer. Linq2Xml kann nichts davon. Bei eigenen kleine XML-Formaten hat es dafür die Nase vorn.)

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

C
c#atriga Themenstarter:in
34 Beiträge seit 2018
vor 5 Jahren

@LaTino

Ich weis auch nicht wie ich nun auf die einzelnen Elemente zugreifen kann.
Wie würde ich vorgehen wenn ich die xml aber importieren will, wenn das Programm Lauffähig ist?

Außerdem verstehe ich nicht was genau da gemacht wird, daher wäre es super wenn mir vlt. Lektüre dafür empfehlen kannst bzw. Stichworte wo ich selbst suchen kann.

PS: Ist das ganze mit meinem Anfänger Grundwissen überhaupt machbar bzw. welche Basics sollte ich schon beherrschen?

3.003 Beiträge seit 2006
vor 5 Jahren

Okay, vielleicht war ich ein bisschen schnell. Wenn man es ein paarmal gemacht hat, ist es wirklich trivial. Vorher sieht es schwierig aus, das vergisst man gern mal.

Kopier ein Beispiel-XML mit Strg-C, schieb den Text also in deine Zwischenablage. Visual Studio kann nun aus deiner Zwischenablage die Klassen generieren, die du brauchst, um dieses XML lesen zu können. Das passiert (in Visual Studio), in dem du im Quellcode über das Menü "Bearbeiten" den Punkt "Inhalte ausfügen" und dort "Xml als Klassen einfügen" wählst. Visual Studio nimmt dir dann die ganze Tipparbeit ab und erzeugt alle Klassen, die du brauchst. Danach kannst du diesen erzeugten Code, der sicher nicht optimal ist, noch etwas von Hand verbessern und deinem Codestil anpassen, wenn du willst.

Nach diesem Schritt hast du Klassen, die den Inhalt der XML-Dateien modellieren. Wenn du jetzt eine solche XML-Datei im Code öffnest:


using(var file = File.OpenRead(@"c:\temp\beispiel.xml"))

...dann kannst du diese geöffnete Datei dem XmlSerializer geben, dem du vorher gesagt hast, wie deine erzeugten Klassen heissen:


var serializer = new XmlSerializer(typeof(Gpx)); //bei mir heisst die erzeugte Klasse "Gpx"

...und dann macht der Serializer die ganze Arbeit:


var ergebnis = (Gpx)serializer.Deserialize(file);

Jetzt stehen in der Variable "ergebnis" alle Werte, die in der XML-Datei standen, und du kannst in deinem Code damit weiterarbeiten.

Weil ich neugierig war und schauen wollte, wie brauchbar der von VS erzeugte Code ist und wie lange ich brauche, den noch einmal aufzuhübschen, hab ich ein fertiges Ergebnis, es hängt unten an. (mit zwei Regex-Ersetzungen und ein bisschen Resharper-Magie: 6 Minuten übrigens^^)

Tu dir einen Gefallen und google mal nach "XmlSerializer Tutorial C#" und übernimm nicht einfach den untenstehenden Code. Bringt dir mehr als abkupfern.

LaTino


using System;
using System.Xml.Serialization;

public static class Namespaces
{
    public const string Gpx = "http://www.topografix.com/GPX/1/0";
    public const string GroundspeakCache = "http://www.groundspeak.com/cache/1/0/1";
}

[XmlType(AnonymousType = true, Namespace = Namespaces.Gpx)]
[XmlRoot("gpx", Namespace = Namespaces.Gpx, IsNullable = false)]
public class Gpx
{
    [XmlElement("desc")] public string Desc { get; set; }
    [XmlElement("author")] public string Author { get; set; }
    [XmlElement("email")] public string Email { get; set; }
    [XmlElement("time")] public DateTime Time { get; set; }
    [XmlElement("keywords")] public string Keywords { get; set; }
    [XmlElement("bounds")] public GpxBounds Bounds { get; set; }
    [XmlElement("wpt")] public GpxWpt Wpt { get; set; }
    [XmlAttribute("version")] public decimal Version { get; set; }
    [XmlAttribute("creator")] public string Creator { get; set; }
}


[XmlType(AnonymousType = true, Namespace = Namespaces.Gpx)]
public class GpxBounds
{
    [XmlAttribute("minlat")] public decimal Minlat { get; set; }
    [XmlAttribute("minlon")] public decimal Minlon { get; set; }
    [XmlAttribute("maxlat")] public decimal Maxlat { get; set; }
    [XmlAttribute("maxlon")] public decimal Maxlon { get; set; }
}

[XmlType(AnonymousType = true, Namespace = Namespaces.Gpx)]
public class GpxWpt
{
    [XmlElement("time")] public DateTime Time { get; set; }
    [XmlElement("name")] public string Name { get; set; }
    [XmlElement("desc")] public string Desc { get; set; }
    [XmlElement("url")] public string Url { get; set; }
    [XmlElement("urlname")] public string Urlname { get; set; }
    [XmlElement("sym")] public string Sym { get; set; }
    [XmlElement("type")] public string Type { get; set; }
    [XmlElement("cache", Namespace = Namespaces.GroundspeakCache)] public Cache Cache { get; set; }
    [XmlAttribute("lat")] public decimal Lat { get; set; }
    [XmlAttribute("lon")] public decimal Lon { get; set; }
}



[XmlType(AnonymousType = true, Namespace = Namespaces.GroundspeakCache)]
[XmlRoot(Namespace = Namespaces.GroundspeakCache, IsNullable = false)]
public class Cache
{
    [XmlElement("name")] public string Name { get; set; }
    [XmlElement("placed_by")] public string PlacedBy { get; set; }
    [XmlElement("owner")] public CacheOwner Owner { get; set; }
    [XmlElement("type")] public string Type { get; set; }
    [XmlElement("container")] public string Container { get; set; }
    [XmlArrayItem("attribute", IsNullable = false)]
    public CacheAttribute[] Attributes { get; set; }
    [XmlElement("difficulty")] public decimal Difficulty { get; set; }
    [XmlElement("terrain")] public byte Terrain { get; set; }
    [XmlElement("country")] public string Country { get; set; }
    [XmlElement("state")] public string State { get; set; }
    [XmlElement("short_description")] public CacheShortDescription ShortDescription { get; set; }
    [XmlElement("long_description")] public CacheLongDescription LongDescription { get; set; }
    [XmlElement("encoded_hints")] public string EncodedHints { get; set; }
    [XmlElement("logs")] public object Logs { get; set; }
    [XmlElement("travelbugs")] public object Travelbugs { get; set; }
    [XmlAttribute("id")] public uint Id { get; set; }
    [XmlAttribute("available")] public string Available { get; set; }
    [XmlAttribute("archived")] public string Archived { get; set; }
}

[XmlType(AnonymousType = true, Namespace = Namespaces.GroundspeakCache)]
public class CacheOwner
{
    [XmlAttribute("id")] public uint Id { get; set; }
    [XmlText] public string Value { get; set; }
}


[XmlType(AnonymousType = true, Namespace = Namespaces.GroundspeakCache)]
public class CacheAttribute
{
    [XmlAttribute("id")] public byte Id { get; set; }
    [XmlAttribute("inc")] public byte Inc { get; set; }
    [XmlText] public string Value { get; set; }
}


[XmlType(AnonymousType = true, Namespace = Namespaces.GroundspeakCache)]
public class CacheShortDescription
{
    [XmlAttribute("html")] public string Html { get; set; }
}


[XmlType(AnonymousType = true, Namespace = Namespaces.GroundspeakCache)]
public class CacheLongDescription
{
    [XmlAttribute("html")] public string Html { get; set; }
    [XmlText] public string Value { get; set; }
}

Anwendung:


class Program
{
    public static async Task Main()
    {
        var file = File.OpenRead(@"c:\temp\example.xml");
        var gpx = Deserialize<Gpx>(file);

        Console.WriteLine(gpx.Wpt.Cache.Owner.Value);
    }

    static T Deserialize<T>(Stream stream)
    {
        var serializer = new XmlSerializer(typeof(T));
        using (stream) return (T) serializer.Deserialize(stream);
    }
}

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

C
c#atriga Themenstarter:in
34 Beiträge seit 2018
vor 5 Jahren

Uff.... das ganze ist doch schwieriger als ich anfangs dachte, aber muss ich jetzt durch.
Werde mich mal durch google versuchen weiter zu bilden.

Empfehlungen mit direkten Links für Programieranfänger nehme ich trotzdem noch gern entgegen.

3.003 Beiträge seit 2006
vor 5 Jahren

Serialisierung ist ein Thema, das sehr einfach ist und sehr komplex werden kann. Dein XML mit mehreren verwendeten Namespaces ist so auf halbem Wege dahin, wo es dann wirklich abartig wird 😉.

Dein Startpunkt könnte so aussehen: erstell ein neues Consolen-Projekt.


public class Program
{
    public static void Main()
    {
        var myModel = new SimpleModel {Name = "Hello, world"};
        var serializer = new XmlSerializer(typeof(SimpleModel));

        using(var file = File.Create(@"c:\temp\simplemodel.xml"))
            serializer.Serialize(file, myModel);
    }

    public class SimpleModel
    {
        public string Name { get; set; }
    }
}

Einmal laufen lassen (sicherstellen, dass es ein Verzeichnis c:\temp gibt). Nach der erzeugten Datei (c:\temp\simplemodel.xml) suchen und dir anschauen, dabei "aha" murmeln.

Jetzt das Model ändern in:


public class SimpleModel
{
    [XmlElement("myFancyName")]
    public string Name { get; set; }
}

Noch einmal laufen lassen. Ergebnis anschauen.

Jetzt zu https://docs.microsoft.com/de-de/dotnet/standard/serialization/examples-of-xml-serialization wechseln und in Ruhe durchlesen. Dabei immer wieder die Klasse ändern und schauen, wie das Ergebnis aussieht.
Zum Schluss die oben geposteten Klassen noch einmal genauer anschauen. Du wirst feststellen: da ist eigentlich so gut wie nix dran.

LaTino

"Furlow, is it always about money?"
"Is there anything else? I mean, how much sex can you have?"
"Don't know. I haven't maxed out yet."
(Furlow & Crichton, Farscape)

C
c#atriga Themenstarter:in
34 Beiträge seit 2018
vor 5 Jahren

Habe mir das ganze ja mal in verschiedenen Tutorials angeschaut. Da taucht jedes mal "Binary Formatter" auf.
In deiner Anweisung kann ich davon jetzt aber gar nix erkennen. Oder bin ich im falschen Video?

16.807 Beiträge seit 2008
vor 5 Jahren

BinaryFormatter bei XML? 🤔
Was soll das für ein Tutorial sein, in welchem Kontext?

C
c#atriga Themenstarter:in
34 Beiträge seit 2018
vor 5 Jahren

BinaryFormatter bei XML? 👶
Was soll das für ein Tutorial sein, in welchem Kontext?

Habe nur nach Serialisierung C# gegoogelt und da kam dies bei zwei Videos.

Ok, dann weis ich das ich weiter suchen muss

L
136 Beiträge seit 2015
vor 5 Jahren

Hallo c#atriga,

Nei, Du musst nicht weitersuchen...

Das was LaTino in seinem letzten Post schreibt ist doch schon ein Tutorial 😁
-> versuch das mal umzusetzen, sollten Fragen auftauchen dann frag einfach

Edit:
Für das Einlesen deines XML-Files (Deserialisieren) ist im zweiten Post von LaTino auch schon alles beschrieben, dabei einfach mit dem "Tutorial" starten, da dein generiertes XML welches Dir erstellt wird viel einfacher ist.

Gruss Lhyn

T
461 Beiträge seit 2013
vor 5 Jahren

Habe nur nach :::

Hey,

😉 ist klar das da mehr zum Vorschein kommt als nur Xml-Serialisierung. Hast in der Suche das XML vergessen.

Ist übrigends auch immer ein Hindernis, richtig zu suchen. Kenn ich sehr gut 😁

Ich habe den Titel mal angepasst, so dass Suchende auch etwas damit anfangen können. EDIT: Ich sollte beim Wort "Shift" im Titel das "f" nicht vergessen... 😄