2010-03-13 4 views
7

Ich habe Schwierigkeiten, diese scheinbar einfache Aufgabe zu erledigen. Ich möchte XML-Dateien mit der gleichen Leichtigkeit des Ladens von Art Assets laden:XNA: Der beste Weg, um eine XML-Datei zu laden und zu lesen?

 content = new ContentManager(Services); 
     content.RootDirectory = "Content"; 
     Texture2d background = content.Load<Texture2D>("images\\ice"); 

Ich bin mir nicht sicher, wie dies zu tun ist. Diese tutorial scheint hilfreich, aber wie bekomme ich eine StorageDevice Instanz?

ich habe jetzt etwas zu arbeiten, aber es fühlt sich ziemlich hacky:

public IDictionary<string, string> Get(string typeName) 
     { 
      IDictionary<String, String> result = new Dictionary<String, String>(); 
      xmlReader.Read(); // get past the XML declaration 

      string element = null; 
      string text = null; 

      while (xmlReader.Read()) 
      { 

       switch (xmlReader.NodeType) 
       { 
        case XmlNodeType.Element: 
         element = xmlReader.Name; 
         break; 
        case XmlNodeType.Text: 
         text = xmlReader.Value; 
         break; 
       } 

       if (text != null && element != null) 
       { 
        result[element] = text; 
        text = null; 
        element = null; 
       } 

      } 
      return result; 
     } 

ich diese Datei in der folgenden XML-Anwendung:

<?xml version="1.0" encoding="utf-8" ?> 
<zombies> 
    <zombie> 
    <health>100</health> 
    <positionX>23</positionX> 
    <positionY>12</positionY> 
    <speed>2</speed> 
    </zombie> 
</zombies> 

Und es ist in der Lage diese Einheit Test bestehen:

Nachteile der aktuellen Ansatz: Datei laden ist schlecht gemacht, und übereinstimmende Schlüssel zu Werten scheint es ist viel mehr Aufwand als nötig. Außerdem vermute ich, dass dieser Ansatz mit mehr als einem Eintrag in der XML auseinander fallen würde.

Ich kann mir nicht vorstellen, dass dies die optimale Implementierung ist.

UPDATE: Im Anschluss an die Beratung von @ Peter Lillevold, habe ich dies ein wenig geändert:

public IDictionary<string, string> Get(string typeName) 
    { 
     IDictionary<String, String> result = new Dictionary<String, String>(); 

     IEnumerable<XElement> zombieValues = root.Element(@typeName).Elements(); 

     //result["health"] = zombie.Element("health").ToString(); 

     IDictionary<string, XElement> nameToElement = zombieValues.ToDictionary(element => element.Name.ToString()); 

     foreach (KeyValuePair<string, XElement> entry in nameToElement) 
     { 
      result[entry.Key] = entry.Value.FirstNode.ToString(); 
     } 

     return result; 
    } 

    public ReadWriteXML(string uri) 
    { 
     root = XElement.Load(uri); 
    } 

    internal virtual IPersistentState CreateIPersistentState(string fullpath) 
    { 
     return new ReadWriteXML(fullpath); 
    } 

    /// <summary> 
    ///A test for Get with one zombie. 
    ///</summary> 
    [TestMethod()] 
    public void SimpleGetTest() 
    { 
     IPersistentState target = CreateIPersistentState("../../../path/Data/SavedZombies.xml"); 
     string typeName = "zombie"; 

     IDictionary<string, string> expected = new Dictionary<string, string>(); 
     expected["health"] = "100"; 
     expected["positionX"] = "23"; 
     expected["positionY"] = "12"; 
     expected["speed"] = "2"; 

     IDictionary<string, string> actual = target.Get(typeName); 

     foreach (KeyValuePair<string, string> entry in expected) 
     { 
      Assert.AreEqual(entry.Value, actual[entry.Key]); 
     } 
    } 

Der Laden ist immer noch ziemlich beschissen ist, und irgendwie war ich nicht in der Lage, die ein- bis bekommen Linie ToDictionary mit diesen beiden Lambdas arbeiten. Ich musste auf diese foreach-Schleife zurückgreifen. Was mache ich da falsch?

+0

Sie haben einen Tippfehler dort. Das @ aus meinem Beispiel kann nur mit String-Literalen, nicht mit String-Variablen oder Parametern verwendet werden. –

+1

Sie erkennen, dass die XNA-Content-Pipeline unterstützt XML-Dateien, nein? Sie können also die gleiche Syntax verwenden, die Sie zum Laden von XML-Dateien verwenden. –

Antwort

8

Es gibt auch die neue und glänzende XElement (die Linq to XML Sport). Diese Probe wird eine XML-Datei laden, die Zombie nachschlagen und Dump die Werte in ein Wörterbuch:

var doc = XElement.Load("filename"); 
var zombieValues = doc.Element("zombie").Elements(); 
var zombieDictionary = 
    zombieValues.ToDictionary(
     element => element.Name.ToString(), 
     element => element.Value); 

Wenn Sie lieber jeden Wert explizit wählen würde (und Gießen verwenden, um automatisch in Typen richtigen Wert konvertieren) können Sie tun:

var zombie = doc.Element("zombie"); 
var health = (int)zombie.Element("health"); 
var positionX = (int)zombie.Element("positionX"); 
var positionY = (int)zombie.Element("positionY"); 
var speed = (int)zombie.Element("speed"); 

Update: einige Tippfehler Fixierung und ein bisschen, Ihre Get Methode sollte wie folgt aussehen Reinigung:

public IDictionary<string, string> Get(string typeName) 
{ 
    var zombie = root.Element(typeName); 
    return zombie.Elements() 
      .ToDictionary(
        element => element.Name.ToString(), 
        element => element.Value); 
} 
+0

Und was ist der Sinn des @ Symbols vor "Zombie"? –

+0

Wie kann ich die Datei auch eleganter laden als eine URI? (so etwas wie eine Content-Pipeline?) –

+0

Sorry, das @ war hier nicht nötig. Es wird Präfixzeichenfolgen verwendet, wenn die Zeichenfolge wortgetreu sein soll. Sie könnten einen benutzerdefinierten Pipeline-Prozessor für Ihren Dateityp erstellen. Schau dir das an: http://msdn.microsoft.com/en-us/library/bb447754.aspx –

2
System.Xml.XmlDocument doc = new System.Xml.XmlDocument(); 
doc.LoadXml(xmlString); 

string health = doc["zombies"]["zombie"]["health"].InnerText; 
// etc.. 

// or looping 

foreach(XmlNode node in doc["zombies"].ChildNodes) 
{ 
    string health = node["health"].InnerText; 
    // etc... 
} 

Oder funktioniert das nicht in XNA?

+0

Ich werde das versuchen. Aber was ist ein besserer Weg, um diesen xmlString von einer Datei an erster Stelle zu bekommen? –

+0

Der Code wurde aktualisiert, weil ich einen Fehler gemacht habe. (doc.Load => doc.LoadXml) – TJMonk15

+0

Es scheint nicht so, als ob XmlDocument in der XNA-Distribution von .NET enthalten wäre, oder es klagt zumindest, wenn ich versuche, es zu benutzen. – Arkiliknam

Verwandte Themen