changeset 23:f9846f896df3

Re #32 - Migrate WarFoundry files to using Schemas * Add missing spaces to Cats and Core XSD * Fix some incorrect namespaces in Race XSD * Copy schemas to output dir on build * Make WarFoundryXmlFactory validate against Schemas * Make WarFoundryLoader handle failed file loads slightly differently so that we can log out as a warning * Correctly structure "simpleContent" sections of Race XSD Still to do: * Work out why Race XSD doesn't like core:nonNegativeDecimal but appears to be fine with core:percentage * Migrate test files to define namespaces and make sure they match the structure
author IBBoard <dev@ibboard.co.uk>
date Thu, 12 Mar 2009 21:35:17 +0000
parents 28e99aa0053f
children 72312a7ac08a
files IBBoard.WarFoundry.API.csproj api/Factories/Xml/WarFoundryXmlFactory.cs api/WarFoundryLoader.cs dtds/race.xsd dtds/warfoundry-cats.xsd dtds/warfoundry-core.xsd
diffstat 6 files changed, 97 insertions(+), 31 deletions(-) [+]
line wrap: on
line diff
--- a/IBBoard.WarFoundry.API.csproj	Mon Mar 09 20:45:45 2009 +0000
+++ b/IBBoard.WarFoundry.API.csproj	Thu Mar 12 21:35:17 2009 +0000
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <PropertyGroup>
     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@@ -44,6 +44,18 @@
     <None Include="dtds\army.dtd" />
     <None Include="dtds\race.dtd" />
     <None Include="dtds\system.dtd" />
+    <None Include="dtds\system.xsd">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="dtds\race.xsd">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="dtds\warfoundry-core.xsd">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
+    <None Include="dtds\warfoundry-cats.xsd">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </None>
   </ItemGroup>
   <ItemGroup>
     <Compile Include="api\Commands\CreateAndAddUnitCommand.cs" />
--- a/api/Factories/Xml/WarFoundryXmlFactory.cs	Mon Mar 09 20:45:45 2009 +0000
+++ b/api/Factories/Xml/WarFoundryXmlFactory.cs	Thu Mar 12 21:35:17 2009 +0000
@@ -25,6 +25,7 @@
 	public class WarFoundryXmlFactory : AbstractNativeWarFoundryFactory
 	{
 		private static WarFoundryXmlFactory factory;
+		private XmlReaderSettings settings;
 		private Dictionary<IWarFoundryObject, XmlDocument> extraData = new Dictionary<IWarFoundryObject, XmlDocument>();
 		private XmlResolver xmlResolver;
 
@@ -266,12 +267,7 @@
 		protected XmlDocument CreateXmlDocumentFromStream(Stream stream)
 		{
 			XmlDocument doc = new XmlDocument();
-			XmlReaderSettings settings = new XmlReaderSettings();
-			settings.XmlResolver = xmlResolver;
-			settings.ValidationType = ValidationType.DTD;
-			settings.ProhibitDtd = false;
-			settings.ValidationEventHandler+= new ValidationEventHandler(ValidationEventMethod);
-			XmlReader reader = XmlReader.Create(stream, settings);
+			XmlReader reader = XmlReader.Create(stream, GetReaderSettings());
 			
 			try
 			{
@@ -289,6 +285,51 @@
 			}
 
 			return doc;
+		}
+		
+				/// <summary>
+		/// Lazy-getter for XML reader settings. May throw a <see cref="InvalidDataException"/> if there is a problem with the translation schema.
+		/// </summary>
+		/// <returns>
+		/// A <see cref="XmlReaderSettings"/> with the default values for validating the translation document against the translation schema
+		/// </returns>
+		private XmlReaderSettings GetReaderSettings()
+		{
+			if (settings == null)
+			{
+				try
+				{
+					settings = new XmlReaderSettings();
+					settings.ValidationType = ValidationType.Schema;
+					settings.ValidationFlags = XmlSchemaValidationFlags.ReportValidationWarnings;
+					settings.ValidationEventHandler+= new ValidationEventHandler(ValidationEventMethod);
+					XmlSchemaSet cache = new XmlSchemaSet();
+					cache.Add("http://ibboard.co.uk/warfoundry/core", IBBoard.Constants.ExecutablePath + "/dtds/warfoundry-core.xsd");
+					cache.Add("http://ibboard.co.uk/warfoundry/cats", IBBoard.Constants.ExecutablePath + "/dtds/warfoundry-cats.xsd");
+					cache.Add("http://ibboard.co.uk/warfoundry/race", IBBoard.Constants.ExecutablePath + "/dtds/race.xsd");
+					cache.Add("http://ibboard.co.uk/warfoundry/system", IBBoard.Constants.ExecutablePath + "/dtds/system.xsd");
+					settings.Schemas.Add(cache);
+				}
+				catch (DirectoryNotFoundException ex)
+				{
+					throw new InvalidDataException("Problem validating schema for WarFoundry data: " + ex.Message, ex);
+				}
+				catch (XmlSchemaException ex)
+				{
+					throw new InvalidDataException("Problem validating schema for WarFoundry data: " + ex.Message, ex);
+				}
+				catch (XmlException ex)
+				{
+					throw new InvalidDataException("Problem reading data for schema: " + ex.Message, ex);
+				}
+			}
+			
+			return settings;
+		}
+		
+		private void ValidationEventMethod(object sender, ValidationEventArgs e)
+		{
+			throw new InvalidDataException("Problem validating against schema for WarFoundry data: " + e.Exception.Message, e.Exception);
 		}
 
 		protected XmlDocument CreateXmlDocumentFromString(string xmlString)
@@ -512,11 +553,5 @@
 			
 			return new EquipmentItem(id, name, cost, min, max, armourType, race);
 		}
-		
-		private void ValidationEventMethod(object sender, ValidationEventArgs e)
-		{
-			//TODO: Fire a validation failure event
-    		LogNotifier.WarnFormat(GetType(), "Validation Error: {0}", e.Message);
-		}
 	}
 }
\ No newline at end of file
--- a/api/WarFoundryLoader.cs	Mon Mar 09 20:45:45 2009 +0000
+++ b/api/WarFoundryLoader.cs	Thu Mar 12 21:35:17 2009 +0000
@@ -275,18 +275,26 @@
 			
 			foreach (FileInfo file in gameSystemFiles.Keys)
 			{
+				FileLoadFailure failure = null;
+				
 				try
 				{
 					bool loaded = LoadObject(file, gameSystemFiles[file]);
 	
 					if (!loaded)
 					{
-						fails.Add(new FileLoadFailure(file, "FileLoadFailed", "Failed to load {0} as Race using {1}"));
+						failure = new FileLoadFailure(file, "FileLoadFailed", "Failed to load {0} as Race using {1}");
 					}
 				}
 				catch (Exception ex)
 				{
-					fails.Add(new FileLoadFailure(file, ex.Message));
+					failure = new FileLoadFailure(file, ex.Message);
+				}
+						
+				if (failure!=null)
+				{
+					fails.Add(failure);
+					LogNotifier.Warn(GetType(), failure.Message);
 				}
 			}
 			
@@ -299,18 +307,26 @@
 			
 			foreach (FileInfo file in raceFiles.Keys)
 			{
+				FileLoadFailure failure = null;
+				
 				try
 				{
 					bool loaded = LoadObject(file, raceFiles[file]);
 	
 					if (!loaded)
 					{
-						fails.Add(new FileLoadFailure(file, "FileLoadFailed", "Failed to load {0} as Race using {1}"));
+						failure = new FileLoadFailure(file, "FileLoadFailed", "Failed to load {0} as Race using {1}");
 					}
 				}
 				catch (Exception ex)
 				{
-					fails.Add(new FileLoadFailure(file, ex.Message));
+					failure = new FileLoadFailure(file, ex.Message);
+				}
+						
+				if (failure!=null)
+				{
+					fails.Add(failure);
+					LogNotifier.Warn(GetType(), failure.Message);
 				}
 			}
 			
--- a/dtds/race.xsd	Mon Mar 09 20:45:45 2009 +0000
+++ b/dtds/race.xsd	Thu Mar 12 21:35:17 2009 +0000
@@ -28,7 +28,7 @@
     <xs:element name="requirements" type="requirementstype" />
     <xs:element name="contains" type="containstype" />
     <xs:element name="extraData" type="extradatatype" />
-    <xs:element name="notes" type="xsd:string" />
+    <xs:element name="notes" type="xs:string" />
   </xs:all>
   <xs:attribute name="id" type="xs:ID" />
   <xs:attribute name="typeName" type="xs:string" use="required"/>
@@ -39,7 +39,7 @@
   <xs:attribute name="maxNumber" type="core:infiniteOrNonNegativeInteger" default="-1"/>
   <xs:attribute name="minSize" type="core:positiveInteger" default="5"/>
   <xs:attribute name="maxSize" type="core:infiniteOrNonNegativeInteger" default="-1"/>
-  <xs:attribute name="baseSize" type="xsd:nonNegativeInteger" default="0"/>
+  <xs:attribute name="baseSize" type="xs:nonNegativeInteger" default="0"/>
 </xs:complexType>
 <xs:complexType name="statstype">
   <xs:sequence>
@@ -48,9 +48,10 @@
 </xs:complexType>
 <xs:complexType name="stattype">
   <xs:simpleContent>
-    <xs:extension base="xs:string"/>
+    <xs:extension base="xs:string">
+      <xs:attribute name="name" type="xs:string" use="required"/>
+    </xs:extension>
   </xs:simpleContent>
-  <xs:attribute name="name" type="xs:string" use="required"/>
 </xs:complexType>
 <xs:complexType name="unitequipmenttype">
   <xs:sequence>
@@ -89,9 +90,10 @@
 </xs:complexType>
 <xs:complexType name="requirementtype">
   <xs:simpleContent>
-    <xs:extension base="xs:string"/>
+    <xs:extension base="xs:string">
+      <xs:attribute name="requirementName" type="xs:string" use="required"/>
+    </xs:extension>
   </xs:simpleContent>
-  <xs:attribute name="requirementName" type="xs:string" use="required"/>
 </xs:complexType>
 <xs:complexType name="containstype">
   <xs:sequence>
@@ -108,9 +110,10 @@
 </xs:complexType>
 <xs:complexType name="extradatadatatype">
   <xs:simpleContent>
-    <xs:extension base="xs:string"/>
+    <xs:extension base="xs:string">
+      <xs:attribute name="id" type="xs:ID" use="required"/>
+    </xs:extension>
   </xs:simpleContent>
-  <xs:attribute name="id" type="xs:ID" use="required"/>
 </xs:complexType>
 <xs:complexType name="equipmenttype">
   <xs:sequence>
@@ -119,7 +122,7 @@
 </xs:complexType>
 <xs:complexType name="equipmentitemtype">
   <xs:all>
-    <xs:element name="description" type="xsd:string" />
+    <xs:element name="description" type="xs:string" />
   </xs:all>
   <xs:attribute name="id" type="xs:ID" use="required"/>
   <xs:attribute name="name" type="xs:string" use="required"/>
@@ -132,7 +135,7 @@
 </xs:complexType>
 <xs:complexType name="equipmentitemtype">
   <xs:all>
-    <xs:element name="description" type="xsd:string" />
+    <xs:element name="description" type="xs:string" />
   </xs:all>
   <xs:attribute name="id" type="xs:ID" use="required"/>
   <xs:attribute name="name" type="xs:string" use="required"/>
@@ -140,7 +143,7 @@
   <xs:attribute name="armoutType" type="armourtype" default="none"/>
 </xs:complexType>
 <xs:simpleType name="armourtype">
-  <xs:restriction base="xsd:string">
+  <xs:restriction base="xs:string">
     <xs:enumeration value="None"/>
     <xs:enumeration value="Shield"/>
     <xs:enumeration value="LightArmour"/>
@@ -162,7 +165,7 @@
 </xs:complexType>
 <xs:complexType name="abilitytype">
   <xs:all>
-    <xs:element name="description" type="xsd:string" />
+    <xs:element name="description" type="xs:string" />
   </xs:all>
   <xs:attribute name="id" type="xs:ID" use="required"/>
   <xs:attribute name="name" type="xs:string" use="required"/>
--- a/dtds/warfoundry-cats.xsd	Mon Mar 09 20:45:45 2009 +0000
+++ b/dtds/warfoundry-cats.xsd	Thu Mar 12 21:35:17 2009 +0000
@@ -1,6 +1,6 @@
 <?xml version="1.0"?>
 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://ibboard.co.uk/warfoundry/cats"
-xmlns="http://ibboard.co.uk/warfoundry/cats"elementFormDefault="qualified">
+xmlns="http://ibboard.co.uk/warfoundry/cats" elementFormDefault="qualified">
 <xs:complexType name="categoriestype">
   <xs:sequence>
     <xs:element name="cat" type="cattype" minOccurs="1" maxOccurs="unbounded"/>
--- a/dtds/warfoundry-core.xsd	Mon Mar 09 20:45:45 2009 +0000
+++ b/dtds/warfoundry-core.xsd	Thu Mar 12 21:35:17 2009 +0000
@@ -1,6 +1,6 @@
 <?xml version="1.0"?>
 <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://ibboard.co.uk/warfoundry/core"
-xmlns="http://ibboard.co.uk/warfoundry/core"elementFormDefault="qualified">
+xmlns="http://ibboard.co.uk/warfoundry/core" elementFormDefault="qualified">
 <xs:simpleType name="infiniteOrNonNegativeDecimal">
   <xs:restriction base="xs:decimal">
     <xs:minInclusive value="-1"/>