2010-03-13 5 views
7

나는이 겉보기에 간단한 작업을하는 데 어려움을 겪고 있습니다. 아트 애셋을로드하는 것과 마찬가지로 쉽게 XML 파일을로드하려고합니다.XNA : XML 파일을로드하고 읽는 가장 좋은 방법은 무엇입니까?

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

잘 모르겠습니다. 이 tutorial가 도움이 될 것 같지만 StorageDevice 인스턴스를 얻으려면 어떻게해야합니까?

는 뭔가 지금 작업이 수행하지만 꽤 해키 느낌 :

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

나는 다음과 같은 XML 파일이 적용

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

그리고이 단위 테스트를 통과 할 수있다 :

internal virtual IPersistentState CreateIPersistentState(string fullpath) 
    { 
     IPersistentState target = new ReadWriteXML(File.Open(fullpath, FileMode.Open)); 
     return target; 
    } 

    /// <summary> 
    ///A test for Get with one zombie. 
    ///</summary> 
    //[TestMethod()] 
    public void SimpleGetTest() 
    { 
     string fullPath = "C:\\pathTo\\Data\\SavedZombies.xml"; 
     IPersistentState target = CreateIPersistentState(fullPath); 
     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, expected[entry.Key]); 
     } 
    } 

현재 접근법에 대한 단점 : 파일로드가 제대로 수행되지 않고 키와 값이 일치하는 것 같습니다. 그것이 필요한 것보다 더 노력하는 것 같아요. 또한이 접근법이 XML에서 둘 이상의 항목으로 분리 될 것으로 생각됩니다.

이것이 최적의 구현이라고 나는 상상할 수 없습니다.

UPDATE는 :

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]); 
     } 
    } 

로딩은 여전히 ​​꽤 엉터리이고, 어떻게 든 내가 원 -을 얻을 수 없습니다 : @ 피터 Lillevold의 조언에 따라, 나는이 조금 변경했습니다 라인 ToDictionary 그 두 람다와 함께 작동합니다. 나는 그 foreach 루프에 의지해야했다. 내가 뭘 잘못하고 있니?

+0

거기에 오타가 있습니다. @ from my sample은 문자열 변수 나 매개 변수가 아닌 문자열 리터럴에서만 사용할 수 있습니다. –

+1

XNA 콘텐츠 파이프 라인이 이미 XML 파일을 지원한다는 사실을 알고 있습니까? 따라서 XML 파일을로드하기 위해 아트 파일을로드하는 데 사용하는 것과 동일한 구문을 문자 그대로 사용할 수 있습니다. –

답변

8

새롭고 반짝이는 XElement (스포츠는 Linq to XML)입니다. 이 샘플은 XML 파일을로드 좀비를 검색하고 사전에 값을 덤프 :

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

오히려 명시 적으로 각각의 값을 선택 (자동으로 적절한 값 유형으로 변환 캐스팅 사용) 싶다면 당신이 할 수있는 수행

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"); 

업데이트 : 일부 오타를 수정하고 비트를 정리, 당신의 Get 방법은 다음과 같아야합니다

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

그리고 "좀비"앞에 @ 기호의 요점은 무엇입니까? –

+0

또한 uri보다 파일을 더 우아하게로드 할 수 있습니까? (내용 파이프 라인과 같은 것?) –

+0

죄송합니다. @는 여기에 필요 없습니다. 문자열이 그대로 있어야 할 때 문자열 접두사로 사용됩니다. 파일 형식에 맞는 사용자 지정 파이프 라인 프로세서를 만들 수 있습니다. 이것 좀 봐 : 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... 
} 

아니면 XNA에서 작동하지 않습니까?

+0

나는 그것을 시도 할 것이다. 하지만 먼저 xmlString을 파일에서 가져 오는 더 좋은 방법은 무엇입니까? –

+0

실수로 코드가 업데이트되었습니다. (doc.Load => doc.LoadXml) – TJMonk15

+0

XmlDocument가 .NET의 XNA 배포판에 포함되어 있거나 사용하려고하면 적어도 불만을 나타내고있는 것 같지 않습니다. – Arkiliknam

관련 문제