Mercurial > repos > IBDev-IBBoard.WarFoundry.API
annotate api/Factories/Xml/WarFoundryXmlFactory.cs @ 42:d0d44434b557
Fixes #45 - Fix XPath problems
* Include namespace prefix and namespace manager in SelectNode calls, as per remark at http://msdn.microsoft.com/en-us/library/hcebdtae.aspx
* Add SelectNodes method that always adds NamespaceManager
* Fix XPath queries
Also:
* Add Army XSD to settings schema cache
* Stop using deprecated Category constructor
author | IBBoard <dev@ibboard.co.uk> |
---|---|
date | Sun, 22 Mar 2009 16:37:43 +0000 |
parents | 422ddd5fedd1 |
children | d0812d7de39d |
rev | line source |
---|---|
15 | 1 // This file (WarFoundryXmlFactory.cs) is a part of the IBBoard.WarFoundry.API project and is copyright 2009 IBBoard. |
0 | 2 // |
15 | 3 // The file and the library/program it is in are licensed under the GNU LGPL license, either version 3 of the License or (at your option) any later version. Please see COPYING.LGPL for more information and the full license. |
0 | 4 |
5 using System; | |
6 using System.IO; | |
7 using System.Xml; | |
8 using System.Xml.Schema; | |
34 | 9 using System.Xml.XPath; |
0 | 10 using System.Collections.Generic; |
11 using System.Text; | |
12 using IBBoard; | |
13 using IBBoard.IO; | |
14 using IBBoard.Lang; | |
15 using IBBoard.Logging; | |
16 using IBBoard.Xml; | |
17 using IBBoard.WarFoundry.API.Requirements; | |
18 using IBBoard.WarFoundry.API.Objects; | |
19 using ICSharpCode.SharpZipLib.Zip; | |
20 | |
21 namespace IBBoard.WarFoundry.API.Factories.Xml | |
22 { | |
23 /// <summary> | |
10 | 24 /// The WarFoundryXmlFactory loads WarFoundry classes from the native "XML in a zip" file format. Files are validated using the schema for the file type, so structurally invalid files should be identified at initial load. |
0 | 25 /// </summary> |
26 public class WarFoundryXmlFactory : AbstractNativeWarFoundryFactory | |
27 { | |
17
a99d3b8466ba
Change "CreateFactory" method to "GetFactory" method to allow for caching
IBBoard <dev@ibboard.co.uk>
parents:
15
diff
changeset
|
28 private static WarFoundryXmlFactory factory; |
23
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
29 private XmlReaderSettings settings; |
42 | 30 private XmlNamespaceManager nsManager; |
0 | 31 private Dictionary<IWarFoundryObject, XmlDocument> extraData = new Dictionary<IWarFoundryObject, XmlDocument>(); |
32 | |
17
a99d3b8466ba
Change "CreateFactory" method to "GetFactory" method to allow for caching
IBBoard <dev@ibboard.co.uk>
parents:
15
diff
changeset
|
33 public static AbstractNativeWarFoundryFactory GetFactory() |
0 | 34 { |
17
a99d3b8466ba
Change "CreateFactory" method to "GetFactory" method to allow for caching
IBBoard <dev@ibboard.co.uk>
parents:
15
diff
changeset
|
35 if (factory == null) |
a99d3b8466ba
Change "CreateFactory" method to "GetFactory" method to allow for caching
IBBoard <dev@ibboard.co.uk>
parents:
15
diff
changeset
|
36 { |
a99d3b8466ba
Change "CreateFactory" method to "GetFactory" method to allow for caching
IBBoard <dev@ibboard.co.uk>
parents:
15
diff
changeset
|
37 factory = new WarFoundryXmlFactory(); |
a99d3b8466ba
Change "CreateFactory" method to "GetFactory" method to allow for caching
IBBoard <dev@ibboard.co.uk>
parents:
15
diff
changeset
|
38 } |
a99d3b8466ba
Change "CreateFactory" method to "GetFactory" method to allow for caching
IBBoard <dev@ibboard.co.uk>
parents:
15
diff
changeset
|
39 |
a99d3b8466ba
Change "CreateFactory" method to "GetFactory" method to allow for caching
IBBoard <dev@ibboard.co.uk>
parents:
15
diff
changeset
|
40 return factory; |
0 | 41 } |
42 | |
43 protected WarFoundryXmlFactory() : base() | |
44 { | |
37 | 45 //Hide constructor |
0 | 46 } |
47 | |
48 protected override bool CheckCanFindArmyFileContent(ZipFile file) | |
49 { | |
50 return file.FindEntry("data.armyx", true) > -1; | |
51 } | |
52 | |
53 protected override bool CheckCanFindSystemFileContent(ZipFile file) | |
54 { | |
55 return file.FindEntry("data.systemx", true) > -1; | |
56 } | |
57 | |
58 protected override bool CheckCanFindRaceFileContent(ZipFile file) | |
59 { | |
60 return file.FindEntry("data.racex", true) > -1; | |
61 } | |
62 | |
63 protected XmlElement GetRootElementFromStream(Stream stream, WarFoundryXmlElementName elementName) | |
64 { | |
65 XmlDocument doc = CreateXmlDocumentFromStream(stream); | |
66 XmlElement elem = (XmlElement)doc.LastChild; | |
67 | |
68 if (!elem.Name.Equals(elementName.Value)) | |
69 { | |
70 throw new InvalidFileException(String.Format("Root element of XML was not valid. Expected {0} but got {1}", elementName.Value, elem.Name)); | |
71 } | |
72 | |
73 return elem; | |
74 } | |
75 | |
76 protected override Stream GetArmyDataStream(ZipFile file) | |
77 { | |
78 return file.GetInputStream(file.FindEntry("data.armyx", true)); | |
79 } | |
80 | |
81 protected override Army CreateArmyFromStream (ZipFile file, Stream dataStream) | |
82 { | |
83 XmlElement elem = GetRootElementFromStream(dataStream, WarFoundryXmlElementName.ARMY_ELEMENT); | |
84 return CreateArmyFromElement(file, elem); | |
85 } | |
86 | |
87 private Army CreateArmyFromElement(ZipFile file, XmlElement elem) | |
88 { | |
89 string name = elem.GetAttribute("name"); | |
90 string systemID = elem.GetAttribute("gameSystem"); | |
91 GameSystem system = WarFoundryLoader.GetDefault().GetGameSystem(systemID); | |
92 string raceID = elem.GetAttribute("race"); | |
93 Race race = WarFoundryLoader.GetDefault().GetRace(system, raceID); | |
94 string pointsString = elem.GetAttribute("maxPoints"); | |
95 int points = 0; | |
96 | |
97 try | |
98 { | |
99 points = int.Parse(pointsString); | |
100 } | |
101 catch(FormatException) | |
102 { | |
103 throw new FormatException("Attribute 'maxPoints' of army '"+name+"' was not a valid number"); | |
104 } | |
105 | |
10 | 106 Army army = new Army(race, name, points, file); |
0 | 107 extraData[army] = elem.OwnerDocument; |
108 return army; | |
109 } | |
110 | |
111 protected override Stream GetGameSystemDataStream (ZipFile file) | |
112 { | |
113 return file.GetInputStream(file.FindEntry("data.systemx", true)); | |
114 } | |
115 | |
116 protected override GameSystem CreateGameSystemFromStream (ZipFile file, Stream dataStream) | |
117 { | |
118 XmlElement elem = GetRootElementFromStream(dataStream, WarFoundryXmlElementName.SYSTEM_ELEMENT); | |
119 LogNotifier.Debug(GetType(), "Create GameSystem"); | |
120 return CreateSystemFromElement(file, elem); | |
121 } | |
122 | |
123 private GameSystem CreateSystemFromElement(ZipFile file, XmlElement elem) | |
124 { | |
125 string id = elem.GetAttribute("id"); | |
126 string name = elem.GetAttribute("name"); | |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
127 GameSystem system = new GameSystem(id, name, this); |
0 | 128 extraData[system] = elem.OwnerDocument; |
129 return system; | |
130 } | |
131 | |
132 protected override Stream GetRaceDataStream (ZipFile file) | |
133 { | |
134 return file.GetInputStream(file.FindEntry("data.racex", true)); | |
135 } | |
136 | |
137 protected override Race CreateRaceFromStream (ZipFile file, Stream dataStream) | |
138 { | |
139 XmlElement elem = GetRootElementFromStream(dataStream, WarFoundryXmlElementName.RACE_ELEMENT); | |
140 LogNotifier.Debug(GetType(), "Create Race"); | |
141 return CreateRaceFromElement(file, elem); | |
142 } | |
143 | |
144 private Race CreateRaceFromElement(ZipFile file, XmlElement elem) | |
145 { | |
146 string id = elem.GetAttribute("id"); | |
147 string subid = elem.GetAttribute("subid"); | |
148 string systemID = elem.GetAttribute("system"); | |
149 string name = elem.GetAttribute("name"); | |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
150 Race race = new Race(id, subid, name, systemID, this); |
0 | 151 extraData[race] = elem.OwnerDocument; |
152 return race; | |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
153 } |
0 | 154 |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
155 public override void CompleteLoading(IWarFoundryStagedLoadObject obj) |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
156 { |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
157 LogNotifier.DebugFormat(GetType(), "Complete loading of {0} with ID {1}", obj.GetType().Name, obj.ID); |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
158 |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
159 if (obj is GameSystem) |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
160 { |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
161 CompleteLoading((GameSystem)obj); |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
162 } |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
163 else if (obj is Race) |
0 | 164 { |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
165 CompleteLoading((Race)obj); |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
166 } |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
167 } |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
168 |
10 | 169 public XmlNode GetExtraData(IWarFoundryObject obj) |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
170 { |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
171 XmlDocument extra = null; |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
172 extraData.TryGetValue(obj, out extra); |
10 | 173 XmlNode node = null; |
174 | |
175 if (extra !=null) | |
176 { | |
177 node = extra.LastChild; | |
178 } | |
179 | |
180 return node; | |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
181 } |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
182 |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
183 public void CompleteLoading(GameSystem system) |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
184 { |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
185 if (system.IsFullyLoaded) |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
186 { |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
187 LogNotifier.DebugFormat(GetType(), "Object of type GameSystem with ID {0} is already fully loaded", system.ID); |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
188 return; |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
189 } |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
190 |
34 | 191 if (system.IsLoading) |
192 { | |
193 LogNotifier.WarnFormat(GetType(), "Object of type GameSystem with ID {0} is already being loaded", system.ID); | |
194 return; | |
195 } | |
196 | |
197 system.SetAsLoading(); | |
198 | |
42 | 199 XmlNode elem = GetExtraData(system); |
10 | 200 LoadCategoriesForSystem(system, elem); |
42 | 201 XmlNodeList nodeList = SelectNodes(elem, "/system:system/system:categories"); |
202 XmlNode statsElem = nodeList.Item(0); | |
203 string defaultStatsID = ((XmlElement)statsElem).GetAttribute("defaultStats", "http://ibboard.co.uk/warfoundry/system"); | |
204 LoadSystemStatsForSystem(system, elem); | |
205 system.StandardSystemStatsID = defaultStatsID; | |
10 | 206 LogNotifier.DebugFormat(GetType(), "Completed loading of GameSystem with ID {0}", system.Name); |
42 | 207 LogNotifier.DebugFormat(GetType(), "GameSystem with ID {0} default stats: {1}", system.Name, system.StandardSystemStatsID); |
10 | 208 system.SetAsFullyLoaded(); |
209 } | |
210 | |
211 private void LoadCategoriesForSystem(GameSystem system, XmlNode elem) | |
212 { | |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
213 WarFoundryObject tempObj; |
10 | 214 |
42 | 215 foreach (XmlElement cat in SelectNodes(elem, "/system:system/system:categories/cat:category")) |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
216 { |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
217 tempObj = CreateObjectFromElement(cat); |
0 | 218 |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
219 if (tempObj is Category) |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
220 { |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
221 system.AddCategory((Category)tempObj); |
0 | 222 } |
223 else | |
224 { | |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
225 LogNotifier.WarnFormat(GetType(), "Object for string {0} was not of type Category", cat.OuterXml); |
0 | 226 } |
227 } | |
228 } | |
229 | |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
230 public void CompleteLoading(Race race) |
0 | 231 { |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
232 if (race.IsFullyLoaded) |
0 | 233 { |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
234 LogNotifier.DebugFormat(GetType(), "Object of type Race with ID {0} is already fully loaded", race.ID); |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
235 return; |
0 | 236 } |
237 | |
34 | 238 if (race.IsLoading) |
239 { | |
240 LogNotifier.WarnFormat(GetType(), "Object of type Race with ID {0} is already being loaded", race.ID); | |
241 return; | |
242 } | |
243 | |
244 race.SetAsLoading(); | |
245 | |
10 | 246 XmlNode elem = GetExtraData(race); |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
247 XmlNode colNode = elem.FirstChild; |
11
5a1df00b0359
Re #9 - Make WarFoundry API load files in small methods
IBBoard <dev@ibboard.co.uk>
parents:
10
diff
changeset
|
248 |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
249 foreach (XmlElement node in colNode.ChildNodes) |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
250 { |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
251 UnitType type = CreateUnitTypeFromElement(node, race, race.GameSystem); |
11
5a1df00b0359
Re #9 - Make WarFoundry API load files in small methods
IBBoard <dev@ibboard.co.uk>
parents:
10
diff
changeset
|
252 race.AddUnitType(type); |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
253 } |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
254 |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
255 colNode = colNode.NextSibling; |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
256 |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
257 if (colNode!=null && colNode.Name == WarFoundryXmlElementName.CATEGORIES_ELEMENT.Value) |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
258 { |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
259 foreach (XmlElement node in colNode.ChildNodes) |
0 | 260 { |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
261 race.AddCategory(CreateCategoryFromElement(node)); |
0 | 262 } |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
263 |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
264 colNode = colNode.NextSibling; |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
265 } |
11
5a1df00b0359
Re #9 - Make WarFoundry API load files in small methods
IBBoard <dev@ibboard.co.uk>
parents:
10
diff
changeset
|
266 |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
267 if (colNode!=null && colNode.Name == WarFoundryXmlElementName.RACE_EQUIPMENT_ITEMS_ELEMENT.Value) |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
268 { |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
269 foreach (XmlElement node in colNode.ChildNodes) |
0 | 270 { |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
271 EquipmentItem item = CreateEquipmentItemFromElement(node, race); |
11
5a1df00b0359
Re #9 - Make WarFoundry API load files in small methods
IBBoard <dev@ibboard.co.uk>
parents:
10
diff
changeset
|
272 race.AddEquipmentItem(item); |
0 | 273 } |
274 } | |
8
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
275 |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
276 Dictionary<string, Ability> raceAbilities = new Dictionary<string, Ability>(); |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
277 //TODO: Load abilities |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
278 race.SetAbilities(raceAbilities); |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
279 race.SetAsFullyLoaded(); |
613bc5eaac59
Re #9 - Make WarFoundry loading granular
IBBoard <dev@ibboard.co.uk>
parents:
6
diff
changeset
|
280 LogNotifier.DebugFormat(GetType(), "Completed loading of Race with ID {0}", race.Name); |
0 | 281 } |
282 | |
283 protected XmlDocument CreateXmlDocumentFromStream(Stream stream) | |
284 { | |
285 XmlDocument doc = new XmlDocument(); | |
23
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
286 XmlReader reader = XmlReader.Create(stream, GetReaderSettings()); |
0 | 287 |
288 try | |
289 { | |
290 doc.Load(reader); | |
291 } | |
292 //Don't catch XMLSchemaExceptions - let them get thrown out | |
293 finally | |
294 { | |
295 reader.Close(); | |
296 } | |
297 | |
298 return doc; | |
23
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
299 } |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
300 |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
301 /// <summary> |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
302 /// Lazy-getter for XML reader settings. May throw a <see cref="InvalidDataException"/> if there is a problem with the translation schema. |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
303 /// </summary> |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
304 /// <returns> |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
305 /// A <see cref="XmlReaderSettings"/> with the default values for validating the translation document against the translation schema |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
306 /// </returns> |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
307 private XmlReaderSettings GetReaderSettings() |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
308 { |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
309 if (settings == null) |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
310 { |
41
422ddd5fedd1
Re #48 - Require schemas to validate
IBBoard <dev@ibboard.co.uk>
parents:
40
diff
changeset
|
311 settings = new XmlReaderSettings(); |
422ddd5fedd1
Re #48 - Require schemas to validate
IBBoard <dev@ibboard.co.uk>
parents:
40
diff
changeset
|
312 settings.ValidationType = ValidationType.Schema; |
422ddd5fedd1
Re #48 - Require schemas to validate
IBBoard <dev@ibboard.co.uk>
parents:
40
diff
changeset
|
313 settings.ValidationFlags = XmlSchemaValidationFlags.ReportValidationWarnings; |
422ddd5fedd1
Re #48 - Require schemas to validate
IBBoard <dev@ibboard.co.uk>
parents:
40
diff
changeset
|
314 settings.ProhibitDtd = true; |
422ddd5fedd1
Re #48 - Require schemas to validate
IBBoard <dev@ibboard.co.uk>
parents:
40
diff
changeset
|
315 settings.ValidationEventHandler+= new ValidationEventHandler(ValidationEventMethod); |
422ddd5fedd1
Re #48 - Require schemas to validate
IBBoard <dev@ibboard.co.uk>
parents:
40
diff
changeset
|
316 XmlSchemaSet cache = new XmlSchemaSet(); |
422ddd5fedd1
Re #48 - Require schemas to validate
IBBoard <dev@ibboard.co.uk>
parents:
40
diff
changeset
|
317 string path = IBBoard.Constants.ExecutablePath + "/dtds/"; |
422ddd5fedd1
Re #48 - Require schemas to validate
IBBoard <dev@ibboard.co.uk>
parents:
40
diff
changeset
|
318 string nsBase = "http://ibboard.co.uk/warfoundry/"; |
422ddd5fedd1
Re #48 - Require schemas to validate
IBBoard <dev@ibboard.co.uk>
parents:
40
diff
changeset
|
319 AddSchemaToCache(cache, nsBase + "core", path + "warfoundry-core.xsd"); |
422ddd5fedd1
Re #48 - Require schemas to validate
IBBoard <dev@ibboard.co.uk>
parents:
40
diff
changeset
|
320 AddSchemaToCache(cache, nsBase + "cats", path + "warfoundry-cats.xsd"); |
422ddd5fedd1
Re #48 - Require schemas to validate
IBBoard <dev@ibboard.co.uk>
parents:
40
diff
changeset
|
321 AddSchemaToCache(cache, nsBase + "race", path + "race.xsd"); |
422ddd5fedd1
Re #48 - Require schemas to validate
IBBoard <dev@ibboard.co.uk>
parents:
40
diff
changeset
|
322 AddSchemaToCache(cache, nsBase + "system", path + "system.xsd"); |
42 | 323 AddSchemaToCache(cache, nsBase + "army", path + "army.xsd"); |
41
422ddd5fedd1
Re #48 - Require schemas to validate
IBBoard <dev@ibboard.co.uk>
parents:
40
diff
changeset
|
324 settings.Schemas.Add(cache); |
23
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
325 } |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
326 |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
327 return settings; |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
328 } |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
329 |
41
422ddd5fedd1
Re #48 - Require schemas to validate
IBBoard <dev@ibboard.co.uk>
parents:
40
diff
changeset
|
330 private void AddSchemaToCache(XmlSchemaSet cache, string xmlNamespace, string schemaLocation) |
422ddd5fedd1
Re #48 - Require schemas to validate
IBBoard <dev@ibboard.co.uk>
parents:
40
diff
changeset
|
331 { |
422ddd5fedd1
Re #48 - Require schemas to validate
IBBoard <dev@ibboard.co.uk>
parents:
40
diff
changeset
|
332 try |
422ddd5fedd1
Re #48 - Require schemas to validate
IBBoard <dev@ibboard.co.uk>
parents:
40
diff
changeset
|
333 { |
422ddd5fedd1
Re #48 - Require schemas to validate
IBBoard <dev@ibboard.co.uk>
parents:
40
diff
changeset
|
334 cache.Add(xmlNamespace, schemaLocation); |
422ddd5fedd1
Re #48 - Require schemas to validate
IBBoard <dev@ibboard.co.uk>
parents:
40
diff
changeset
|
335 } |
422ddd5fedd1
Re #48 - Require schemas to validate
IBBoard <dev@ibboard.co.uk>
parents:
40
diff
changeset
|
336 catch (IOException ex) |
422ddd5fedd1
Re #48 - Require schemas to validate
IBBoard <dev@ibboard.co.uk>
parents:
40
diff
changeset
|
337 { |
422ddd5fedd1
Re #48 - Require schemas to validate
IBBoard <dev@ibboard.co.uk>
parents:
40
diff
changeset
|
338 LogNotifier.Warn(GetType(), "Problem reading schema: " + ex.Message, ex); |
422ddd5fedd1
Re #48 - Require schemas to validate
IBBoard <dev@ibboard.co.uk>
parents:
40
diff
changeset
|
339 } |
422ddd5fedd1
Re #48 - Require schemas to validate
IBBoard <dev@ibboard.co.uk>
parents:
40
diff
changeset
|
340 catch (XmlSchemaException ex) |
422ddd5fedd1
Re #48 - Require schemas to validate
IBBoard <dev@ibboard.co.uk>
parents:
40
diff
changeset
|
341 { |
422ddd5fedd1
Re #48 - Require schemas to validate
IBBoard <dev@ibboard.co.uk>
parents:
40
diff
changeset
|
342 LogNotifier.Warn(GetType(), "Problem validating schema for WarFoundry data: " + ex.Message, ex); |
422ddd5fedd1
Re #48 - Require schemas to validate
IBBoard <dev@ibboard.co.uk>
parents:
40
diff
changeset
|
343 } |
422ddd5fedd1
Re #48 - Require schemas to validate
IBBoard <dev@ibboard.co.uk>
parents:
40
diff
changeset
|
344 catch (XmlException ex) |
422ddd5fedd1
Re #48 - Require schemas to validate
IBBoard <dev@ibboard.co.uk>
parents:
40
diff
changeset
|
345 { |
422ddd5fedd1
Re #48 - Require schemas to validate
IBBoard <dev@ibboard.co.uk>
parents:
40
diff
changeset
|
346 LogNotifier.Warn(GetType(), "Problem reading data for schema: " + ex.Message, ex); |
422ddd5fedd1
Re #48 - Require schemas to validate
IBBoard <dev@ibboard.co.uk>
parents:
40
diff
changeset
|
347 } |
422ddd5fedd1
Re #48 - Require schemas to validate
IBBoard <dev@ibboard.co.uk>
parents:
40
diff
changeset
|
348 } |
422ddd5fedd1
Re #48 - Require schemas to validate
IBBoard <dev@ibboard.co.uk>
parents:
40
diff
changeset
|
349 |
42 | 350 private XmlNamespaceManager GetNamespaceManager() |
351 { | |
352 if (nsManager == null) | |
353 { | |
354 nsManager = new XmlNamespaceManager(new NameTable()); | |
355 nsManager.AddNamespace("core", "http://ibboard.co.uk/warfoundry/core"); | |
356 nsManager.AddNamespace("cat", "http://ibboard.co.uk/warfoundry/cats"); | |
357 nsManager.AddNamespace("race", "http://ibboard.co.uk/warfoundry/race"); | |
358 nsManager.AddNamespace("system", "http://ibboard.co.uk/warfoundry/system"); | |
359 nsManager.AddNamespace("army", "http://ibboard.co.uk/warfoundry/army"); | |
360 } | |
361 | |
362 return nsManager; | |
363 } | |
364 | |
365 private XmlNodeList SelectNodes(XmlNode element, string xpathQuery) | |
366 { | |
367 return element.SelectNodes(xpathQuery, GetNamespaceManager()); | |
368 } | |
369 | |
23
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
370 private void ValidationEventMethod(object sender, ValidationEventArgs e) |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
371 { |
f9846f896df3
Re #32 - Migrate WarFoundry files to using Schemas
IBBoard <dev@ibboard.co.uk>
parents:
17
diff
changeset
|
372 throw new InvalidDataException("Problem validating against schema for WarFoundry data: " + e.Exception.Message, e.Exception); |
0 | 373 } |
374 | |
375 private WarFoundryObject CreateObjectFromElement(XmlElement elem) | |
376 { | |
377 WarFoundryObject obj = null; | |
378 LogNotifier.DebugFormat(GetType(), "Create object for <{0}>", elem.Name); | |
379 | |
380 if (elem.Name.Equals(WarFoundryXmlElementName.CATEGORY_ELEMENT.Value)) | |
381 { | |
382 LogNotifier.Debug(GetType(), "Create Category"); | |
383 obj = CreateCategoryFromElement(elem); | |
384 } | |
385 else | |
386 { | |
387 LogNotifier.Debug(GetType(), "No match"); | |
388 } | |
389 | |
390 return obj; | |
391 } | |
392 | |
393 private Category CreateCategoryFromElement(XmlElement elem) | |
394 { | |
395 string id = elem.GetAttribute("id"); | |
396 string name = elem.GetAttribute("name"); | |
42 | 397 Category cat = new Category(id, name); |
398 cat.MinimumPercentage = GetIntValueFromAttribute(elem, "minPercentage"); | |
399 cat.MaximumPercentage = GetIntValueFromAttribute(elem, "maxPercentage"); | |
400 cat.MinimumPoints = GetIntValueFromAttribute(elem, "minPoints"); | |
401 cat.MaximumPoints = GetIntValueFromAttribute(elem, "maxPoints"); | |
402 return cat; | |
9
6ad505b6c36e
Re #10 - Refactor for readability
IBBoard <dev@ibboard.co.uk>
parents:
8
diff
changeset
|
403 } |
6ad505b6c36e
Re #10 - Refactor for readability
IBBoard <dev@ibboard.co.uk>
parents:
8
diff
changeset
|
404 |
10 | 405 private int GetIntValueFromAttribute(XmlElement elem, string attributeName) |
9
6ad505b6c36e
Re #10 - Refactor for readability
IBBoard <dev@ibboard.co.uk>
parents:
8
diff
changeset
|
406 { |
40
3664eee50390
Fixes #47 - remove magic numbers
IBBoard <dev@ibboard.co.uk>
parents:
39
diff
changeset
|
407 try |
39 | 408 { |
40
3664eee50390
Fixes #47 - remove magic numbers
IBBoard <dev@ibboard.co.uk>
parents:
39
diff
changeset
|
409 return int.Parse(elem.GetAttribute(attributeName)); |
39 | 410 } |
40
3664eee50390
Fixes #47 - remove magic numbers
IBBoard <dev@ibboard.co.uk>
parents:
39
diff
changeset
|
411 catch(FormatException) |
3664eee50390
Fixes #47 - remove magic numbers
IBBoard <dev@ibboard.co.uk>
parents:
39
diff
changeset
|
412 { |
3664eee50390
Fixes #47 - remove magic numbers
IBBoard <dev@ibboard.co.uk>
parents:
39
diff
changeset
|
413 throw new FormatException(String.Format("Attribute '{0}' of {1} with ID {2} was not a valid number", attributeName, elem.Name, elem.GetAttribute("id"))); |
3664eee50390
Fixes #47 - remove magic numbers
IBBoard <dev@ibboard.co.uk>
parents:
39
diff
changeset
|
414 } |
0 | 415 } |
416 | |
417 private UnitType CreateUnitTypeFromElement(XmlElement elem, Race parentRace, GameSystem system) | |
418 { | |
419 string id = elem.GetAttribute("id"); | |
420 string name = elem.GetAttribute("typeName"); | |
12
ac232763858b
Re #9 - Make WarFoundry API use smaller methods
IBBoard <dev@ibboard.co.uk>
parents:
11
diff
changeset
|
421 UnitType type = new UnitType(id, name, parentRace); |
ac232763858b
Re #9 - Make WarFoundry API use smaller methods
IBBoard <dev@ibboard.co.uk>
parents:
11
diff
changeset
|
422 type.MinNumber = GetIntValueFromAttribute(elem, "minNum"); |
ac232763858b
Re #9 - Make WarFoundry API use smaller methods
IBBoard <dev@ibboard.co.uk>
parents:
11
diff
changeset
|
423 type.MaxNumber = GetIntValueFromAttribute(elem, "maxNum"); |
ac232763858b
Re #9 - Make WarFoundry API use smaller methods
IBBoard <dev@ibboard.co.uk>
parents:
11
diff
changeset
|
424 type.MinSize = GetIntValueFromAttribute(elem, "minSize"); |
ac232763858b
Re #9 - Make WarFoundry API use smaller methods
IBBoard <dev@ibboard.co.uk>
parents:
11
diff
changeset
|
425 type.MaxSize = GetIntValueFromAttribute(elem, "maxSize"); |
ac232763858b
Re #9 - Make WarFoundry API use smaller methods
IBBoard <dev@ibboard.co.uk>
parents:
11
diff
changeset
|
426 //TODO: Add base size |
ac232763858b
Re #9 - Make WarFoundry API use smaller methods
IBBoard <dev@ibboard.co.uk>
parents:
11
diff
changeset
|
427 type.CostPerTrooper = GetIntValueFromAttribute(elem, "points"); |
ac232763858b
Re #9 - Make WarFoundry API use smaller methods
IBBoard <dev@ibboard.co.uk>
parents:
11
diff
changeset
|
428 type.BaseUnitCost = GetIntValueFromAttribute(elem, "unitPoints"); |
ac232763858b
Re #9 - Make WarFoundry API use smaller methods
IBBoard <dev@ibboard.co.uk>
parents:
11
diff
changeset
|
429 string mainCatID = elem.GetAttribute("cat"); |
ac232763858b
Re #9 - Make WarFoundry API use smaller methods
IBBoard <dev@ibboard.co.uk>
parents:
11
diff
changeset
|
430 type.MainCategory = parentRace.GetCategory(mainCatID); |
42 | 431 XmlNodeList nodes = SelectNodes(elem, "/race:race/race:units/race:unit/race:stats"); |
34 | 432 XmlNode node = nodes.Item(0); |
12
ac232763858b
Re #9 - Make WarFoundry API use smaller methods
IBBoard <dev@ibboard.co.uk>
parents:
11
diff
changeset
|
433 type.UnitStats = ParseUnitStats((XmlElement)node, system); |
0 | 434 //TODO: Add unit requirements |
34 | 435 LogNotifier.Debug(GetType(), "Loaded "+type.Name); |
0 | 436 return type; |
437 } | |
438 | |
439 private Stats ParseUnitStats(XmlElement elem, GameSystem system) | |
440 { | |
441 List<Stat> statsList = new List<Stat>(); | |
442 String statsID = elem.GetAttribute("statSet"); | |
443 SystemStats statsSet; | |
444 | |
445 if (statsID == "") | |
446 { | |
447 statsSet = system.StandardSystemStats; | |
448 } | |
449 else | |
450 { | |
6 | 451 statsSet = system.GetSystemStatsForID(statsID); |
0 | 452 } |
453 | |
454 Stats stats = new Stats(statsSet); | |
455 | |
456 foreach (XmlElement stat in elem.ChildNodes) | |
457 { | |
458 String statID = stat.GetAttribute("name"); | |
459 StatSlot slot = statsSet[statID]; | |
460 | |
461 if (slot!=null) | |
462 { | |
463 statsList.Add(new Stat(slot, stat.InnerText)); | |
464 } | |
465 else | |
466 { | |
467 throw new InvalidFileException("The stat "+statID+" was not found in stats set "+statsID); | |
468 } | |
469 } | |
470 | |
471 stats.SetStats(statsList); | |
472 | |
473 return stats; | |
474 } | |
475 | |
42 | 476 private void LoadSystemStatsForSystem(GameSystem system, XmlNode elem) |
0 | 477 { |
42 | 478 foreach (XmlElement stats in SelectNodes(elem, "/system:system/system:sysStatsList/system:sysStats")) |
0 | 479 { |
480 SystemStats sysStats = CreateSystemStatsFromElement(stats); | |
6 | 481 system.AddSystemStats(sysStats); |
0 | 482 } |
483 } | |
484 | |
485 private SystemStats CreateSystemStatsFromElement(XmlElement elem) | |
486 { | |
487 List<StatSlot> slots = new List<StatSlot>(); | |
488 string id = elem.GetAttribute("id"); | |
489 | |
490 foreach (XmlElement slot in elem.ChildNodes) | |
491 { | |
492 StatSlot statSlot = new StatSlot(slot.GetAttribute("name")); | |
493 slots.Add(statSlot); | |
494 } | |
495 | |
496 return new SystemStats(id, slots.ToArray()); | |
497 } | |
498 | |
499 private EquipmentItem CreateEquipmentItemFromElement(XmlElement elem, Race race) | |
500 { | |
501 string id = elem.GetAttribute("id"); | |
502 string name = elem.GetAttribute("name"); | |
503 float cost = 0, min = 0, max = 0; | |
504 ArmourType armourType; | |
505 | |
506 try | |
507 { | |
508 cost = float.Parse(elem.GetAttribute("cost")); | |
509 } | |
510 catch(FormatException) | |
511 { | |
512 throw new FormatException("Attribute 'cost' of equipment item "+id+" was not a valid number"); | |
513 } | |
514 | |
515 try | |
516 { | |
517 min = float.Parse(elem.GetAttribute("min")); | |
518 } | |
519 catch(FormatException) | |
520 { | |
521 throw new FormatException("Attribute 'min' of equipment item "+id+" was not a valid number"); | |
522 } | |
523 | |
524 try | |
525 { | |
526 max = float.Parse(elem.GetAttribute("max")); | |
527 } | |
528 catch(FormatException) | |
529 { | |
530 throw new FormatException("Attribute 'max' of equipment item "+id+" was not a valid number"); | |
531 } | |
532 | |
533 try | |
534 { | |
535 armourType = (ArmourType)Enum.Parse(typeof(ArmourType), elem.GetAttribute("armourType")); | |
536 } | |
537 catch(FormatException) | |
538 { | |
539 throw new InvalidFileException("Attribute 'armourType' of equipment "+id+" was not a valid value from the enumeration"); | |
540 } | |
541 | |
542 if (elem.ChildNodes.Count>0) | |
543 { | |
544 //It has stats! | |
545 //TODO: Parse equipment stats | |
546 } | |
547 | |
548 return new EquipmentItem(id, name, cost, min, max, armourType, race); | |
549 } | |
550 } | |
551 } |