C# Problem mit XML Datei

Cartman999

Lieutenant
Registriert
Aug. 2007
Beiträge
814
Ich habe 2 Klassen(Levelinfos, Gegnerinfos) und eine XML Datei. Die beiden Klassen befinden sich im SharedContent-Projekt. Ich habe einige Daten zur Hintergrundtextur und Gegnertexturen angegeben. Für die Gegnerinformationen wollte ich eine Liste einbauen, jedoch bekomme ich immer diese Fehlermeldung: XML has too many entries in the space-separated list.
Darf man nur ein entry pro Item haben(z.B. nur <name></name>) oder wo liegt das Problem? Ich dachte man könnte auch mehrere Sachen zwischen <item></item> schreiben:confused_alt:
Code:
<?xml version="1.0" encoding="utf-8" ?> 
<XnaContent> 
  <Asset Type="SharedContent.Levelinfos"> 
    <Backname>Background</Backname> 
    <Backposition>0 0</Backposition> 
    <Backrotation>0</Backrotation> 
    <Backscale>.1 .1</Backscale> 
    <Backtexture>Hintergrund_Wald</Backtexture> 
  <Gegner> 
    <Item> 
      <name>Gegner1</name> 
      <Position>20 40</Position> 
      <Rotation>0</Rotation> 
      <Scale>.1 .1</Scale> 
    </Item> 
    <Item> 
      <name>Gegner2</name> 
      <Position>80 120</Position> 
      <Rotation>0</Rotation> 
      <Scale>.1 .1</Scale> 
    </Item> 
    <Item> 
      <name>Gegner3</name> 
      <Position>200 80</Position> 
      <Rotation>0</Rotation> 
      <Scale>.1 .1</Scale> 
    </Item>    
  </Gegner> 
  </Asset> 
</XnaContent> 


namespace SharedContent 
{ 
    public class Levelinfos 
    {        
        public string Backname; 
        public Vector2 Backposition; 
        public int Backrotation; 
        public float Backscale; 
        public Texture2D Backtexture; 
        public List<Gegnerinfos> Gegner; 
    } 
} 


namespace SharedContent 
{ 
    public class Gegnerinfos 
    { 
        public string name; 
        public Vector2 Position; 
        public int Rotation; 
        public float Scale; 
    }
 
Wie tshape schon meinte: <Scale>.1 .1</Scale>

das .1 .1 ist doch kein float. Also erkennt er wohl eine Liste: (0,1 0,1) findet aber nix wo er die 2. Zahl reinschreiben soll.
 
Ich habe <Backscale> und <Scale> jetzt überall auf 1 gesetzt und die Variablen auf integer geändert. Jedoch kommt nun folgende Fehlermeldung: XML element "Tag" not found.
Was bedeutet das?
 
Wie liest und schreibst du denn diese XML-Daten?

Wenn du Objekte als XML schreiben und lesen willst, solltest du sie vorher serialisieren, bzw. deserialisieren. Das dürfte bei dir nicht passieren, da du die Klassen gar nicht als Serialisierbar markiert hast.
Wenn du die XML-Geschichte korrekt implementierst dürfte es keine Probleme geben.

Ich weiß nicht ob das XNAStudio spezielle vorgefertigete Dinge mitbringt um sowas zu realisieren, aber in reinem CSharp gehts ungefähr so:

Die Klasse:
Code:
    [Serializable()]
    public class Datenklasse
    {
        public float Floatwert {get;set;}
        public int Intwert {get;set;}
        public Point EinPunkt {get;set;}
    }

Der Programmcode:
Code:
            Datenklasse kl = new Datenklasse();

            kl.EinPunkt = new Point(1, 5);
            kl.Floatwert = 0.145F;
            kl.Intwert = 5;
            
            XmlWriter writer = XmlWriter.Create(@"c:\xmloutput.xml");
            XmlSerializer serializer = new XmlSerializer(typeof(Datenklasse));
            serializer.Serialize(writer, kl);
            writer.Close();

Das was dabei rauskommt:
Code:
<?xml version="1.0" encoding="UTF-8"?>
<Datenklasse xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Floatwert>0.145</Floatwert>
<Intwert>5</Intwert>
<EinPunkt>
<X>1</X>
<Y>5</Y>
</EinPunkt>
</Datenklasse>
 
Zuletzt bearbeitet:
Ich habe alles so gemacht wie du es beschrieben hast jedoch kam die Fehlermeldung trotzdem noch. Daraufhin habe ich die Zeile <Backtexture> aus der XML Datei entfernt und in der Klasse auch die Texture2D Variable und auf einmal funktioniert fast alles. Leider nur fast da ich wegen dieser Zeile XmlWriter.Create(@"c:\xmloutput.xml"); folgende Fehlermeldung bekomme: Access to the path c:\xmloutput.xml is denied.
Was kann man da machen?
Um nochmal auf das Problem mit der Variable Texture2D zurückzukommen. In diesem Link steht unter Type Translations etwas dazu: http://blogs.msdn.com/b/shawnhar/ar...xnb-serialization-in-xna-game-studio-3-1.aspx
So wie es scheint muss ich in meinem Fall diesen Code in meiner Klasse schreiben:
Code:
public Texture2DContent Backtexture;
Ich werde das nachher noch ausprobieren.
 
Cartman999 schrieb:
Leider nur fast da ich wegen dieser Zeile XmlWriter.Create(@"c:\xmloutput.xml"); folgende Fehlermeldung bekomme: Access to the path c:\xmloutput.xml is denied.
Du hast keine Schreibrechte auf C:\. Entweder du legst einen neuen Ordner an (C:\Temp) oder speicherst in Eigenen Dateien oder startest das Programm als Administrator.
 
Ja, so ein bißchen muss man schon mitdenken ;)
Ich habe Schreibrechte auf C:, du nicht. Kannst aber in deinen eigenen Userprofilordner schreiben. Das geht.

Was die automatische Serialisierung von XNA angeht die in dem Artikel beschrieben wird, kenn ich mich nicht so gut aus. Möglich wäre aber, dass dieses Texture-Dings nicht serialisierbar ist, oder dass du statt

Code:
public List<Gegnerinfos> Gegner;
in den Levelinfos
Code:
public Gegnerinfos[] Gegner;
verwenden musst, so wie es in dem Beispiel auch gemacht wurde.

EDIT: Habe jetzt mal deine Datenstruktur durch den normalen XML-Serializer gejagt und folgendes bekommen:

Code:
<?xml version="1.0" encoding="UTF-8"?>
<Levelinfos xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<Backname>Backname</Backname>
<Backrotation>1</Backrotation>
<Backscale>0.1</Backscale>
<Gegner>
<Gegnerinfos>
<name>Horst</name>
<Rotation>12</Rotation>
<Scale>0.788</Scale>
</Gegnerinfos>
<Gegnerinfos>
<name>Rolf</name>
<Rotation>4</Rotation>
<Scale>0.3</Scale>
</Gegnerinfos>
<Gegnerinfos>
<name>Bernhard</name>
<Rotation>7</Rotation>
<Scale>0.144</Scale>
</Gegnerinfos>
</Gegner>
</Levelinfos>

Das Beispiel dazu ist:

Code:
 [Serializable()]
       public class Levelinfos
        {
        public string Backname;
        public int Backrotation;
        public float Backscale;
        public List<Gegnerinfos> Gegner;
        }

        [Serializable()]
        public class Gegnerinfos
        {
        public string name;
        public int Rotation;
        public float Scale;
        }

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Levelinfos kl = new Levelinfos();

            kl.Backname = "Backname";
            kl.Backrotation = 1;
            kl.Backscale=0.1F;
            kl.Gegner = new List<Gegnerinfos>();

            Gegnerinfos gegner1 = new Gegnerinfos();
            gegner1.name = "Horst";
            gegner1.Rotation = 12;
            gegner1.Scale = 0.788F;

            Gegnerinfos gegner2 = new Gegnerinfos();
            gegner2.name = "Rolf";
            gegner2.Rotation = 4;
            gegner2.Scale = 0.3F;

            Gegnerinfos gegner3 = new Gegnerinfos();
            gegner3.name = "Bernhard";
            gegner3.Rotation = 7;
            gegner3.Scale = 0.144F;

            kl.Gegner.Add(gegner1);
            kl.Gegner.Add(gegner2);
            kl.Gegner.Add(gegner3);

            XmlWriter writer = XmlWriter.Create(@"c:\xmloutput.xml");
            XmlSerializer serializer = new XmlSerializer(typeof(Levelinfos));
            serializer.Serialize(writer, kl);
            writer.Close();
        }

Es funktioniert soweit richtig, obwohl ich aufgrund fehlender Assemblies Vector2 und Texture2D nicht testen konnte. Aber da gabs ja auch keine Fehler.

Was ich mich nun frage ist, wieso du bei <Scale> 2x .1 in einer Zeile bekommst und ich nicht.
 
Zuletzt bearbeitet:
Ich habe hier noch einen Artikel zu Texture2D und XML gefunden: http://blogs.msdn.com/b/shawnhar/ar...ic-xnb-serialization-and-content-classes.aspx
Ich gehe davon aus dass man mein Problem mit der dritten Möglichkeit im Artikel(Generics) wohl am einfachsten lösen kann, oder was meint ihr?
Ich habe das noch nicht ausprobiert da ich nicht weiß wie ich meine XML Datei umändern muss damit es funktioniert. Zum Bespiel habe ich keine Ahnung was folgende Zeilen im Artikel bedeuten und wie das in meinem Fall aussehen würde:(
<Width>2</Width>
<Height>2</Height>
<Pixels>
<Row>FFFF0000 FF00FF00</Row>
<Row>FF0000FF FF000000</Row>
</Pixels>
 
@Cartman999
Du sollst die XML Datei nicht per Hand schreiben.
Du kannst dir eine Klasse einfach serialisieren lassen, wodurch du automatisch valides XML erhältst ohne rumfrickeln zu müssen. (was MacGyver schon die ganze Zeit versucht dir zu verklickern)

Hier gibts ein kleines Beispiel von MS dazu: klick

@MacGyver
Das SerializableAttribute ist nicht für die XML-Serialization gedacht und wird auch nicht benötigt.
Der XmlSerializer serialisiert automatisch alle öffentlichen Eigenschaften, da brauchts nicht extra ein Attribut.
Außerdem brauchst du zum speichern der Datei keine XmlWriter.
Es reicht auch dem XmlSerializer nen einfachen FileStream zu übergeben. ;)
 
Grantig schrieb:
@MacGyver
Das SerializableAttribute ist nicht für die XML-Serialization gedacht und wird auch nicht benötigt.
Der XmlSerializer serialisiert automatisch alle öffentlichen Eigenschaften, da brauchts nicht extra ein Attribut.
Außerdem brauchst du zum speichern der Datei keine XmlWriter.
Es reicht auch dem XmlSerializer nen einfachen FileStream zu übergeben. ;)

Ich gebe Serializable schon aus Gewohnheit immer an.
Erstens schadet es nicht, zweitens ists ein guter Hinweis wenn man den Quellcode liest und drittens kann man es dann nicht vergessen wenn man es wirklich braucht. Bei Soap z.B.

Und ob ich nun nen Filestream, nen TextWriter oder nen XmlWriter nehme ist mehr oder weniger wurscht, gell? :D
 
MacGyver schrieb:
Ich gebe Serializable schon aus Gewohnheit immer an.
Erstens schadet es nicht, zweitens ists ein guter Hinweis wenn man den Quellcode liest und drittens kann man es dann nicht vergessen wenn man es wirklich braucht. Bei Soap z.B.
Ist ja jetzt auch nicht verkehrt, nur der Satz von dir:
MacGyver schrieb:
Wenn du Objekte als XML schreiben und lesen willst, solltest du sie vorher serialisieren, bzw. deserialisieren. Das dürfte bei dir nicht passieren, da du die Klassen gar nicht als Serialisierbar markiert hast.
...hört sich halt so an, als ob das Attribut notwendig wäre.

MacGyver schrieb:
Und ob ich nun nen Filestream, nen TextWriter oder nen XmlWriter nehme ist mehr oder weniger wurscht, gell?
Da hast du allerdings Recht - hab mir mal den Code angeschaut und hab festgestellt XmlSerializer.Serialize erstellt intern sowieso immer nen XmlWriter, auch wenn die Methode mit nem FileStream aufgerufen wird.
Da ist meine Korinthenkackerei mal wieder nach hinten losgegangen :D
Naja, wenigstens hab ich was dabei gelernt :)
 
Das Programm läuft zwar jetzt, bekomme keine Fehlermeldung, jedoch wird die XML Datei aus irgendeinem Grund nicht auf die Festplatte geschrieben:confused_alt: Ich habe die Datei auch schon mit der Suche auf C: gesucht jedoch nichts gefunden.
Der aktuelle Code(ich habe die XML Datei die ich vorher per Hand erstellt hatte gelöscht):
Code:
[Serializable()]
    public class Levelinfos
    {
        public string Backname;
        public Vector2 Backposition;
        public int Backrotation;
        public float Backscale;
        public Texture2DContent Backtexture;
        public List<Gegnerinfos> Gegner;
    }

[Serializable()]
    public class Gegnerinfos
    {
        public string name;
        public Vector2 Position;
        public int Rotation;
        public float Scale;
    }
private void Form1_Load(object sender, EventArgs e)
        {
            Levelinfos kl = new Levelinfos();
            kl.Backname = "Jeff";
            kl.Backposition = new Vector2(20, 30);
            kl.Backrotation = 1;
            kl.Backscale = 0.5F;
            kl.Backtexture = Content.Load<Texture2DContent>("light");

                Gegnerinfos gegner1 = new Gegnerinfos();
	            gegner1.name = "Horst";
	            gegner1.Rotation = 12;
                gegner1.Scale = 0.1F;
	 
	            Gegnerinfos gegner2 = new Gegnerinfos();
	            gegner2.name = "Rolf";
                gegner2.Rotation = 4;
	            gegner2.Scale = 0.2F;
	 
	            Gegnerinfos gegner3 = new Gegnerinfos();
	            gegner3.name = "Bernhard";
	            gegner3.Rotation = 7;
                gegner3.Scale = 0.3F;
	 
	            kl.Gegner.Add(gegner1);
	            kl.Gegner.Add(gegner2);
	            kl.Gegner.Add(gegner3);

            System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(kl.GetType());
              XmlWriter writer = XmlWriter.Create(@"C:\Benutzer\Mein Name\xmloutput.xml");
        }
Ich habe auch schon versucht Benutzer durch Users zu ersetzen jedoch hat das auch nicht funktioniert.
 
Code:
x.Serialize( writer, kl );

In die letzte Zeile der Methode schreiben -> fertig.
 
Ich habe die letzten Zeilen des Codes so umgeändert jedoch hat das nichts gebracht:(
Code:
XmlWriter writer = XmlWriter.Create(@"C:\Users\Mein Name\Eigene Dokumente\xmloutput.xml");      
System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(kl.GetType());            
x.Serialize(writer, kl);
writer.Close();
 
Code:
namespace WindowsGame16
{
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }
         
              private void Form1_Load(object sender, EventArgs e)
        {
            Levelinfos kl = new Levelinfos();
            kl.Backname = "Jeff";
            kl.Backposition = new Vector2(20, 30);
            kl.Backrotation = 1;
            kl.Backscale = 0.5F;
            kl.Backtexture = Content.Load<Texture2DContent>("light");

                Gegnerinfos gegner1 = new Gegnerinfos();
	            gegner1.name = "Horst";
	            gegner1.Rotation = 12;
                gegner1.Scale = 0.1F;
	 
	            Gegnerinfos gegner2 = new Gegnerinfos();
	            gegner2.name = "Rolf";
                gegner2.Rotation = 4;
	            gegner2.Scale = 0.2F;
	 
	            Gegnerinfos gegner3 = new Gegnerinfos();
	            gegner3.name = "Bernhard";
	            gegner3.Rotation = 7;
                gegner3.Scale = 0.3F;
	 
	            kl.Gegner.Add(gegner1);
	            kl.Gegner.Add(gegner2);
	            kl.Gegner.Add(gegner3);


                XmlWriter writer = XmlWriter.Create(@"C:\Users\Sammy\Eigene Dokumente\xmloutput.xml");      
                System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(kl.GetType());            
                x.Serialize(writer, kl);
                writer.Close();
        }

        protected override void Initialize()
        {
            base.Initialize();
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
        }

        protected override void UnloadContent()
        {
        }

        protected override void Update(GameTime gameTime)
        {
            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            base.Draw(gameTime);
        }
    }
}
Die beiden Klassen aus dem SharedContent-Projekt:
Code:
namespace SharedContent
{
    [Serializable()]
    public class Levelinfos
    {
        public string Backname;
        public Vector2 Backposition;
        public int Backrotation;
        public float Backscale;
        public Texture2DContent Backtexture;
        public List<Gegnerinfos> Gegner;
    }
}

namespace SharedContent
{
    [Serializable()]
    public class Gegnerinfos
    {
        public string name;
        public Vector2 Position;
        public int Rotation;
        public float Scale;
    }
}

Außer dem light.png Bild habe ich keine Dateien im Content-Projekt liegen.
 
Ich seh da keinen Fehler.
Setz mal bitte einen Breakpoint in Zeile 16 ( Levelinfos kl = new Levelinfos(); ) und schau, ob der ausgelöst wird. Wenn nicht, feuert das Loaded Event nicht (wahrscheinlich hast du es dann nicht angemeldet).
 
Ähm, sorry. Ist ja mein Beispiel und ich habe dummerweise das Form_Load Event für den Progarmmcode gewählt. Da kann es passieren dass bei Exceptions keine Fehlermeldung kommt, sondern die leere Form einfach dargestellt wird als ob nichts wäre.

Mach einfach kurz nen Button und pack alles was in Form_Load drin ist in das entsprechende Button_Click rein. Dann siehst du auf jeden Fall wenn das Programm aufschlägt. Noch einfacher: Alles in einen try - catch Block reintun.
 
Es gibt kein WinForms für XNA.
Da ist nichts mit "Form_Load" und "Button reinsetzen und bei OnClick".

Weißt du überhaupt was du da machst Cartman?
Ich würde dir dringenst raten, dich erstmal in Programmierung einzulesen, bevor du versuchst mit XNA irgendwas herumzufuchteln. Du hast offensichtlich das Prinzip der OOP nicht verstanden.

MacGyver schrieb:
Da kann es passieren dass bei Exceptions keine Fehlermeldung kommt, sondern die leere Form einfach dargestellt wird als ob nichts wäre.

?
Bei Paint-Methoden von Controls werden gerne mal Exceptions unterschlagen. Das wird dann aber mit einem entsprechenden roten Kreuz anstelle des Controls "angedeutet".
 
Zuletzt bearbeitet:
Zurück
Oben