Entwickler-Ecke

IO, XML und Registry - XML Datei einlesen


Skywalker19 - Mo 21.11.05 10:49
Titel: XML Datei einlesen
möchte eine XML-Datei einlesen, die folgende Struktur hat:


Quelltext
1:
2:
3:
4:
5:
<xml version="1.0" encoding="utf-8"?>
<settings>
  <text1 xmlns="gggg" />
  <text2 xmlns="hhhh" />
</settings>


mein bisheriger Code dazu ist der hier:


C#-Quelltext
1:
2:
3:
4:
XmlDocument settings = new XmlDocument();      
settings.LoadXml("settings.xml");
XmlNode node = settings.SelectSingleNode("//settings/text1");    
textBox1.Text = node.InnerText;


aber in Zeile 3 bekomm ich eine System.XML.Exception ausgewurfen :(

Was mach ich falsch?

Moderiert von user profile iconChristian S.: C#-und Code-Tags hinzugefügt
Moderiert von user profile iconChristian S.: Topic aus C# - Die Sprache verschoben am Mo 21.11.2005 um 11:23


Delete - Mo 21.11.05 12:38
Titel: Re: XML Datei einlesen
user profile iconSkywalker19 hat folgendes geschrieben:
Was mach ich falsch?

Einiges.
  1. Grund für deine Exception ist die Verwendung von LoadXml. Damit lädst du direkt XML-Code und nicht den Inhalt deiner XML-Datei. Du brauchst also Load.
  2. Wenn du das änderst, bekommst du die nächste Exception. Grund: Du hast in der ersten Zeile der XML-Datei das Fragezeichen vorn, nach dem öffnenden Tag, vergessen.
  3. Wenn du das änderst, erhältst du die dritte Exception, weil deine XML-Datei das xmlns-Attribut für einen fremden Namespace benutzt. "SelectSingleNode" findet daher nichts, node ist null.
  4. Erst wenn du das Problem löst, siehst du den Inhalt des Knotens im Eingabefeld. Das heißt, eigentlich siehst du nichts, denn der Knoten hat ja keinen Inhalt. ;)


Skywalker19 - Mo 21.11.05 16:08

danke erstmal!
die ersten beiden Fehler sind behoben aber was muss ich nun genau beim dritten Problem machen?


Delete - Mo 21.11.05 16:41

.NET Framework SDK: XmlNamespaceManager.


Skywalker19 - Mo 21.11.05 20:32

ja also das xmlns hat es ja standartmäßig beim speichern der Datei hinzugefügt.
aber was muss ich da jetzt genau beim Laden angeben?
hab bisher:

XmlNamespaceManager nsmanager = new XmlNamespaceManager(settings.NameTable);

und dann muss ich doch irgendwas mit

nsmanager.AddNamespace

hinzufügen oder ?

blick da noch nicht ganz durch, hab leider auch noch keine Ahnung von XML.


Delete - Mo 21.11.05 23:05

Du bist aber auf dem richtigen Weg. Du musst dem Befehl SelectSingleNode sagen, dass es sich bei dem gesuchten Knoten um einen mit einem anderen Namespace handelt. Das machst du bei XPath, indem du ein Präfix voranstellst. Dessen Namen kannst du dir auch selbst ausdenken:

C#-Quelltext
1:
nsmanager.AddNamespace("bla""gggg");                    

Beim Einlesen stellst du dieses Präfix bla: nun vor den eigentlichen Namen des Knotens, und du musst auch den XmlNamespaceManager verwenden:

C#-Quelltext
1:
XmlNode node = settings.SelectSingleNode("//settings/bla:text1", nsmanager);                    

Und das war´s. Wenn du dem Knoten jetzt noch Inhalt gibst

Quelltext
1:
<text1 xmlns="gggg">Hallo, Welt!</text1>                    

dann siehst du im Eingabefeld auch was.


Übrigens, wenn du vorhast, Einstellungen deines Programms in einer XML-Datei zu speichern, dann solltest du mal einen Blick auf die Serialization/Deserialization werfen. Das ist nämlich richtig genial. Du erstellst eine Klasse mit den Eigenschaften, die dein Programm benötigt (Höhe, Breite, Position, was weiß ich ...), und dank XmlSerializer erzeugt CSharp daraus automatisch eine XML-Datei. Und umgekehrt: Ein Befehl liest die XML-Datei wieder ein, und du hast Zugriff auf die gespeicherten Eigenschaften.


Skywalker19 - Di 22.11.05 08:56

gut danke funktionert, aber eins noch:
das "gggg" ist ja schon Text aus meiner Textbox, den es da speichert. Gibt es keine Möglichkeit darauf zuzugreifen? Sonst muss ich wieder meine Speicherfunktion umschreiben...


Skywalker19 - Di 22.11.05 09:03

oder besser gefragt:

<text1 xmlns="gggg">Hallo, Welt!</text1>

Wie kann ich in dieser Zeile den Text (Hallo Welt) beim speichern der XML anlegen?


Delete - Di 22.11.05 10:41

Das habe ich mir gedacht, ;). xmlns ist ein Attributname, der grundsätzlich für Namespace-Deklarationen verwendet wird. Aus dem Grund scheitert dann auch deine Leseroutine. Es gibt drei Varianten, einen Text richtig in einem XML-Knoten zu speichern.

1. Entweder als Attribut:

C#-Quelltext
1:
2:
3:
4:
XmlElement node = xmldoc.CreateElement("text1");
node.SetAttribute("Text", textBox1.Text);

// Ergebnis: <text1 Text="Hallo, Welt!"/>


2. Als Knoteninhalt:

C#-Quelltext
1:
2:
3:
4:
XmlElement node = xmldoc.CreateElement("text1");
node.InnerText  = textBox1.Text;

// Ergebnis: <text1>Hallo, Welt!</text1>


3. Die absolut beste Variante ist aber die Verwendung einer <![CDATA[ ]]>-Sektion, weil du damit sicherstellst, dass auch Sonderzeichen, die normalerweise in XML nichts zu suchen haben (&, <, >, usw.) gespeichert werden. In dem Fall geht es aber grundsätzlich nur als Inhalt des Knotens und nicht als Attribut:

C#-Quelltext
1:
2:
3:
4:
5:
XmlElement node         = xmldoc.CreateElement("text1");
XmlCDataSection content = xmldoc.CreateCDataSection(textBox1.Text);
node.AppendChild(content);

// Ergebnis: <text1><![CDATA[Hallo, & Welt! <bla>]]></text1>


Skywalker19 - Di 22.11.05 11:27

besten Dank! jetzt funzt alles! *freu* ^^


Robert_G - Di 22.11.05 12:35

hmm...
Geht auch ganz anders. ;)

Hier noch ein bleistift, wie man es benutzt:

C#-Quelltext
1:
2:
3:
4:
5:
6:
settings settings = settings.Load("Settings.xml");

settings.text1 += "a(&, <, >, usw.)";
settings.text2 += "b(&, <, >, usw.)";

settings.Save();




user profile iconMathiasSimmack hat folgendes geschrieben:
3. Die absolut beste Variante ist aber die Verwendung einer <![CDATA[ ]]>-Sektion, weil du damit sicherstellst, dass auch Sonderzeichen, die normalerweise in XML nichts zu suchen haben (&, <, >, usw.) gespeichert werden. In dem Fall geht es aber grundsätzlich nur als Inhalt des Knotens und nicht als Attribut:

C#-Quelltext
1:
2:
3:
4:
XmlElement node         = xmldoc.CreateElement("text1");
XmlCDataSection content = xmldoc.CreateCDataSection(textBox1.Text);
node.AppendChild(content);
// Ergebnis: <text1><![CDATA[Hallo, & Welt! <bla>]]></text1>
Nope, solche Sache lasse ich lieber vom Framework entscheiden. Beim Beispiel von oben wird diese XML erzeugt: ;)

Quelltext
1:
2:
3:
4:
5:
6:
7:
<?xml version="1.0" encoding="utf-8"?>
<settings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:xsd="http://www.w3.org/2001/XMLSchema"
          xmlns="SkywalkersSchema.xsd">
  <text1 xmlns="gggg">a(&, <, >, usw.)</text1>
  <text2 xmlns="hhhh">b(&, <, >, usw.)</text2>
</settings>

Das Framework bleibt up-to-date was die XML Syntax betrifft. Wenn ich sowas fest in den Code einbaue läuft es vllt nächstes Jahr nichtmehr. Außerdem müsste ich es selbst in den Code einbauen... :mrgreen:

Moderiert von user profile iconChristian S.: Code-Tags repariert


Delete - Mi 23.11.05 07:28

Ist das nicht etwas Overkill? ;) Wenn ich das richtig sehe, dann war es eh bloß ein Versehen des Beitragserstellers, dass er xmlns benutzt hat.


Skywalker19 - Mi 23.11.05 08:43

glaub auch das is bissel aufwendig in der Form und richtig, war auch eher ein Versehen ^^


Robert_G - Mi 23.11.05 10:32

Oh ich dachte das war nur ein gekürzter Bleistift...
Normal halte ich autogenerierte Container und Serialisierung als nette Möglichkeit realtiv flexibel zu Änderungen in den Daten zu bleiben. ;)


ven000m - Mi 14.05.08 15:23

Hallo,

ich habe genau das gleiche Problem wie Skywalker.

Allerdings funktioniert es bei mir noch nicht: Folgendes ist bei mir der Fall, ich erhalte einen XML Stream von einem Webservice zurück.

Davon möchte ich bestimmte Knoten an bestimmte Steuerelemente meines Forms zurückschreiben, ich suche schon den ganzen Tag nach diesem Thread und wäre super dankbar wenn ich damit heute auch abschließen könnte und weitermachen könnte.

Da ich nicht soo versiert bin, wären direkte Code-Beispiele echt toll!

Ich interessiere mich für zwei Knoten:
// text und //adBKMURL

Der Namespace meines XML Streams lautet wie folgt:
xmlns="urn:Corticon" xmlns:xsi="http://.... schema-instance"

Was kommt jetzt anstatt von bla dort beim NamespaceManager bzw. beim xPath rein?

Hier ist der Code:


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
         try{

              Corticon.CcServerMessagingAxisService myWebHandler = new Corticon.CcServerMessagingAxisService();

              MessageBox.Show(request);
              string response=myWebHandler.executeRPC(request);
              MessageBox.Show(response);


              XmlDocument myXMLDoc = new XmlDocument();
              myXMLDoc.Load(response);

              XmlNamespaceManager nsmanager = new XmlNamespaceManager(myXMLDoc.NameTable);
              nsmanager.AddNamespace("bla","ggg");

              XmlNodeList nodes = myXMLDoc.SelectNodes("/CorticonResponse/Messages/Message/bla:text", nsmanager);
               // /CorticonResponse/Messages/Message/text                           

              int i = 1;

              foreach (XmlNode myNode in nodes)
              {
                  ResultBox.AppendText(i++ + "." + myNode.InnerText);
              }

              /*Zweiter Knoten adBKMURL auslesen:*/

              XmlNode bkmNode = myXMLDoc.SelectSingleNode("/CorticonResponse/WorkDocuments/OEM/bla:adBKMURL", nsmanager);
              // /CorticonResponse/WorkDocuments/OEM/adBKMURL
             
              BKMBox.Text = bkmNode.InnerText; //hier ist der fehler
              // BKMBox.Text = myXMLDoc.InnerText;
            

          }
          catch (Exception ex) 
          { ResultBox.Text = ex.StackTrace; }


Moderiert von user profile iconChristian S.: Code- durch C#-Tags ersetzt