view api/Factories/Xml/WarFoundryXmlFactoryUtils.cs @ 219:f609bcf7035b

Fixes #222: decimal comma/point not handled correctly (again?) in costMultiplier * Replace two "type.Parse" calls with XmlTools calls All decimals in WarFoundry should use the decimal point (or "period" to Americans) rather than the decimal comma because that's what XML uses in its default type definitions
author IBBoard <dev@ibboard.co.uk>
date Sat, 28 Nov 2009 16:40:27 +0000
parents a1a6b527cd70
children f097888efcfe
line wrap: on
line source

//  This file (WarFoundryXmlFactoryUtils.cs) is a part of the IBBoard.WarFoundry.API project and is copyright 2009 IBBoard
// 
// The file and the library/program it is in are licensed and distributed, without warranty, under the GNU Affero GPL license, either version 3 of the License or (at your option) any later version. Please see COPYING for more information and the full license.

using System;
using System.IO;
using System.Xml;
using System.Xml.Schema;
using IBBoard.WarFoundry.API.Objects;
using IBBoard.IO;

namespace IBBoard.WarFoundry.API.Factories.Xml
{
	/// <summary>
	/// A collection of useful utility methods for loading WarFoundry data from XML files
	/// </summary>
	public class WarFoundryXmlFactoryUtils
	{
		public static readonly string NS_BASE = "http://ibboard.co.uk/warfoundry/";
		private static XmlReaderSettings settings;
		private static XmlNamespaceManager nsManager;
		
		public static XmlNodeList SelectNodes(XmlNode element, string xpathQuery)
		{
			return element.SelectNodes(xpathQuery, GetNamespaceManager());
		}
		
		public static XmlNode SelectSingleNode(XmlNode element, string xpathQuery)
		{
			return element.SelectSingleNode(xpathQuery, GetNamespaceManager());
		}
		
		public static XmlElement SelectSingleElement(XmlNode element, string xpathQuery)
		{
			XmlNode node = SelectSingleNode(element, xpathQuery);
			return (node is XmlElement) ? (XmlElement) node : null;
		}
				
		public static XmlNamespaceManager GetNamespaceManager()
		{
			if (nsManager == null)
			{
				nsManager = new XmlNamespaceManager(new NameTable());
				nsManager.AddNamespace("core", NS_BASE + "core");
				nsManager.AddNamespace("cat", NS_BASE + "cats");
				nsManager.AddNamespace("race", NS_BASE + "race");
				nsManager.AddNamespace("system", NS_BASE + "system");
				nsManager.AddNamespace("army", NS_BASE + "army");
			}
			
			return nsManager;
		}
		
		/// <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>
		public static XmlReaderSettings GetReaderSettings()
		{
			if (settings == null)
			{
				settings = new XmlReaderSettings();
				settings.ValidationType = ValidationType.Schema;
				settings.ValidationFlags = XmlSchemaValidationFlags.ReportValidationWarnings;
				settings.ProhibitDtd = true;
				settings.ValidationEventHandler+= new ValidationEventHandler(ValidationEventMethod);
				XmlSchemaSet cache = new XmlSchemaSet();
				string path =  IBBoard.Constants.ExecutablePath + "/dtds/";
				AddSchemaToCache(cache, NS_BASE + "core", path + "warfoundry-core.xsd");
				AddSchemaToCache(cache, NS_BASE + "cats", path + "warfoundry-cats.xsd");
				AddSchemaToCache(cache, NS_BASE + "race", path + "race.xsd");
				AddSchemaToCache(cache, NS_BASE + "system", path + "system.xsd");
				AddSchemaToCache(cache, NS_BASE + "army", path + "army.xsd");
				settings.Schemas.Add(cache);
			}
			
			return settings;
		}
		
		private static void ValidationEventMethod(object sender, ValidationEventArgs e)
		{
			throw new InvalidFileException("Problem validating against schema for WarFoundry data: " + e.Message, e.Exception);
		}
		
		private static void AddSchemaToCache(XmlSchemaSet cache, string xmlNamespace, string schemaLocation)
		{
			try
			{
				cache.Add(xmlNamespace, schemaLocation);
			}
			catch (IOException ex)
			{
				//TODO: Warn on schema failure
			}
			catch (XmlSchemaException ex)
			{
				//TODO: Warn on schema failure
			}
			catch (XmlException ex)
			{
				//TODO: Warn on schema failure
			}
		}
		
		public static XmlDocument CreateXmlDocumentFromStream(Stream stream)
		{
			XmlDocument doc = new XmlDocument();
			XmlReader reader = XmlReader.Create(stream, GetReaderSettings());
			
			try
			{
				doc.Load(reader);
			}
			//Don't catch XMLSchemaExceptions - let them get thrown out
			finally
			{
				reader.Close();
			}

			return doc;
		}
		
		public static bool CanCompleteLoading(IWarFoundryStagedLoadObject obj)
		{
			bool canLoad = true;			
			
			if (obj.IsFullyLoaded)
			{
				canLoad = false;
			}
			else if (obj.IsLoading)
			{
				canLoad = false;
			}
			
			return canLoad;
		}
	}
}