changeset 114:7ca4acc659bb

* Add resource resolver for use with DTDs as resources * Add helper method for loading schemas into a set from resources
author IBBoard <dev@ibboard.co.uk>
date Mon, 25 Jun 2012 21:06:25 +0100
parents e32b5ccda410
children 07660ac09a5f
files IBBoard.csproj Xml/XmlResourceResolver.cs Xml/XmlTools.cs
diffstat 3 files changed, 222 insertions(+), 177 deletions(-) [+]
line diff
     1.1 --- a/IBBoard.csproj	Sun Jun 24 15:48:25 2012 +0100
     1.2 +++ b/IBBoard.csproj	Mon Jun 25 21:06:25 2012 +0100
     1.3 @@ -157,6 +157,7 @@
     1.4      <Compile Include="EqualityChecker.cs" />
     1.5      <Compile Include="IO\StreamUtil.cs" />
     1.6      <Compile Include="Collections\Collections.cs" />
     1.7 +    <Compile Include="Xml\XmlResourceResolver.cs" />
     1.8    </ItemGroup>
     1.9    <ItemGroup>
    1.10      <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/Xml/XmlResourceResolver.cs	Mon Jun 25 21:06:25 2012 +0100
     2.3 @@ -0,0 +1,40 @@
     2.4 +using System;
     2.5 +using System.Xml;
     2.6 +using System.Reflection;
     2.7 +using System.Collections.Generic;
     2.8 +using System.IO;
     2.9 +using System.Net;
    2.10 +
    2.11 +namespace IBBoard.Xml
    2.12 +{
    2.13 +		public class XmlResourceResolver : XmlUrlResolver
    2.14 +		{
    2.15 +				private Assembly assm;
    2.16 +				private Dictionary<string, string> relativeToUriMap = new Dictionary<string, string>();
    2.17 +
    2.18 +				public XmlResourceResolver(Assembly assembly)
    2.19 +				{
    2.20 +						assm = assembly;
    2.21 +				}
    2.22 +
    2.23 +				public void AddMapping(string relativeURI, string resourceName)
    2.24 +				{
    2.25 +						relativeToUriMap[relativeURI] = resourceName;
    2.26 +				}
    2.27 +
    2.28 +				public override object GetEntity(Uri absoluteUri, string role, Type ofObjectToReturn)
    2.29 +				{
    2.30 +						string absoluteUriString = absoluteUri.ToString();
    2.31 +
    2.32 +						if (relativeToUriMap.ContainsKey(absoluteUriString))
    2.33 +						{
    2.34 +								string file = relativeToUriMap[absoluteUriString];
    2.35 +								Stream stream = assm.GetManifestResourceStream(file);
    2.36 +								return stream;
    2.37 +						}
    2.38 +
    2.39 +						return base.GetEntity(absoluteUri, role, ofObjectToReturn);
    2.40 +				}
    2.41 +		}
    2.42 +}
    2.43 +
     3.1 --- a/Xml/XmlTools.cs	Sun Jun 24 15:48:25 2012 +0100
     3.2 +++ b/Xml/XmlTools.cs	Mon Jun 25 21:06:25 2012 +0100
     3.3 @@ -7,186 +7,190 @@
     3.4  using System.Globalization;
     3.5  using System.Text.RegularExpressions;
     3.6  using System.Xml;
     3.7 +using System.Reflection;
     3.8 +using System.IO;
     3.9 +using System.Xml.Schema;
    3.10  
    3.11  namespace IBBoard.Xml
    3.12  {
    3.13 -	/// <summary>
    3.14 -	/// Some basic tools for handling XML files and retrieving their values
    3.15 -	/// </summary>
    3.16 -	public class XmlTools
    3.17 -	{
    3.18 -		private static Regex idRegex;
    3.19 -		private static Regex multiUnderscoreRegex;
    3.20 -		private static NumberFormatInfo doubleFormat;
    3.21 +		/// <summary>
    3.22 +		/// Some basic tools for handling XML files and retrieving their values
    3.23 +		/// </summary>
    3.24 +		public class XmlTools
    3.25 +		{
    3.26 +				private static Regex idRegex;
    3.27 +				private static Regex multiUnderscoreRegex;
    3.28 +				private static NumberFormatInfo doubleFormat;
    3.29  
    3.30 -		/// <summary>
    3.31 -		/// Gets the value of an attribute of an element as a boolean. Throws a FormatException if the attribute is not a boolean.
    3.32 -		/// </summary>
    3.33 -		/// <param name="elem">
    3.34 -		/// The <see cref="XmlElement"/> to get the attribute value of
    3.35 -		/// </param>
    3.36 -		/// <param name="attributeName">
    3.37 -		/// The name of the attribute to get as a boolean
    3.38 -		/// </param>
    3.39 -		/// <returns>
    3.40 -		/// The value of the attribute as an boolean
    3.41 -		/// </returns>
    3.42 -		public static bool GetBoolValueFromAttribute(XmlElement elem, string attributeName)
    3.43 -		{
    3.44 -			try
    3.45 -			{
    3.46 -				return bool.Parse(elem.GetAttribute(attributeName));
    3.47 -			}
    3.48 -			catch(FormatException)
    3.49 -			{
    3.50 -				throw new FormatException(String.Format("Attribute '{0}' of {1} with ID {2} was not a valid boolean", attributeName, elem.Name, elem.GetAttribute("id")));
    3.51 -			}
    3.52 +				/// <summary>
    3.53 +				/// Gets the value of an attribute of an element as a boolean. Throws a FormatException if the attribute is not a boolean.
    3.54 +				/// </summary>
    3.55 +				/// <param name="elem">
    3.56 +				/// The <see cref="XmlElement"/> to get the attribute value of
    3.57 +				/// </param>
    3.58 +				/// <param name="attributeName">
    3.59 +				/// The name of the attribute to get as a boolean
    3.60 +				/// </param>
    3.61 +				/// <returns>
    3.62 +				/// The value of the attribute as an boolean
    3.63 +				/// </returns>
    3.64 +				public static bool GetBoolValueFromAttribute(XmlElement elem, string attributeName)
    3.65 +				{
    3.66 +						try
    3.67 +						{
    3.68 +								return bool.Parse(elem.GetAttribute(attributeName));
    3.69 +						} catch (FormatException)
    3.70 +						{
    3.71 +								throw new FormatException(String.Format("Attribute '{0}' of {1} with ID {2} was not a valid boolean", attributeName, elem.Name, elem.GetAttribute("id")));
    3.72 +						}
    3.73 +				}
    3.74 +		
    3.75 +				/// <summary>
    3.76 +				/// Gets the value of an attribute of an element as an integer. Throws a FormatException if the attribute is not an integer.
    3.77 +				/// </summary>
    3.78 +				/// <param name="elem">
    3.79 +				/// The <see cref="XmlElement"/> to get the attribute value of
    3.80 +				/// </param>
    3.81 +				/// <param name="attributeName">
    3.82 +				/// The name of the attribute to get as an integer
    3.83 +				/// </param>
    3.84 +				/// <returns>
    3.85 +				/// The value of the attribute as an integer
    3.86 +				/// </returns>
    3.87 +				public static int GetIntValueFromAttribute(XmlElement elem, string attributeName)
    3.88 +				{
    3.89 +						try
    3.90 +						{
    3.91 +								return int.Parse(elem.GetAttribute(attributeName));
    3.92 +						} catch (FormatException)
    3.93 +						{
    3.94 +								throw new FormatException(String.Format("Attribute '{0}' of {1} with ID {2} was not a valid number", attributeName, elem.Name, elem.GetAttribute("id")));
    3.95 +						}
    3.96 +				}
    3.97 +							
    3.98 +				/// <summary>
    3.99 +				/// Gets the value of an attribute of an element as a double. Throws a FormatException if the attribute is not a double.
   3.100 +				/// </summary>
   3.101 +				/// <param name="elem">
   3.102 +				/// The <see cref="XmlElement"/> to get the attribute value of
   3.103 +				/// </param>
   3.104 +				/// <param name="attributeName">
   3.105 +				/// The name of the attribute to get as a double
   3.106 +				/// </param>
   3.107 +				/// <returns>
   3.108 +				/// The value of the attribute as an double
   3.109 +				/// </returns>
   3.110 +				public static double GetDoubleValueFromAttribute(XmlElement elem, string attributeName)
   3.111 +				{
   3.112 +						double doubleVal = double.NaN;
   3.113 +						string attribValue = elem.GetAttribute(attributeName);
   3.114 +			
   3.115 +						if (attribValue == "INF")
   3.116 +						{
   3.117 +								doubleVal = double.PositiveInfinity;
   3.118 +						} else
   3.119 +						{
   3.120 +								try
   3.121 +								{
   3.122 +										return double.Parse(attribValue, GetNumberFormatInfo());
   3.123 +								} catch (FormatException)
   3.124 +								{
   3.125 +										throw new FormatException(String.Format("Attribute '{0}' of {1} with ID {2} was not a valid number", attributeName, elem.Name, elem.GetAttribute("id")));
   3.126 +								}
   3.127 +						}
   3.128 +			
   3.129 +						return doubleVal;
   3.130 +				}
   3.131 +		
   3.132 +				public static T GetEnumValueFromAttribute<T>(XmlElement elem, string attributeName)
   3.133 +				{
   3.134 +						return GetEnumValueFromAttribute<T>(elem, attributeName, true);
   3.135 +				}
   3.136 +		
   3.137 +				public static T GetEnumValueFromAttribute<T>(XmlElement elem, string attributeName, bool ignoreCase)
   3.138 +				{
   3.139 +						string attribValue = elem.GetAttribute(attributeName);
   3.140 +			
   3.141 +						try
   3.142 +						{
   3.143 +								return EnumTools.ParseEnum<T>(attribValue, ignoreCase);
   3.144 +						} catch (ArgumentException)
   3.145 +						{
   3.146 +								throw new FormatException(String.Format("Attribute '{0}' with value {1} for {2} with ID '{3}' was not a valid {4} enum", attributeName, attribValue, elem.Name, elem.GetAttribute("id"), typeof(T).Name));
   3.147 +						}
   3.148 +				}
   3.149 +
   3.150 +				private static NumberFormatInfo GetNumberFormatInfo()
   3.151 +				{
   3.152 +						if (doubleFormat == null)
   3.153 +						{
   3.154 +								doubleFormat = NumberFormatInfo.InvariantInfo;
   3.155 +						}
   3.156 +
   3.157 +						return doubleFormat;
   3.158 +				}
   3.159 +
   3.160 +				private static Regex GetIdRegex()
   3.161 +				{
   3.162 +						if (idRegex == null)
   3.163 +						{
   3.164 +								idRegex = new Regex("[^a-zA-Z0-9:\\._-]+");
   3.165 +						}
   3.166 +			
   3.167 +						return idRegex;
   3.168 +				}
   3.169 +		
   3.170 +				private static Regex GetMultiUnderscoreRegex()
   3.171 +				{
   3.172 +						if (multiUnderscoreRegex == null)
   3.173 +						{
   3.174 +								multiUnderscoreRegex = new Regex("_{2,}");
   3.175 +						}
   3.176 +			
   3.177 +						return multiUnderscoreRegex;
   3.178 +				}
   3.179 +		
   3.180 +				/// <summary>
   3.181 +				/// Gets a valid XML ID for a given string that does not contain accented and non-ASCII characters. Matches the allowed characters
   3.182 +				/// in the XML spec (http://www.w3.org/TR/xml/#NT-NameStartChar) where the characters do not use Unicode character codes. If the ID
   3.183 +				/// starts with an invalid character then it will be prepended with an underscore.
   3.184 +				/// </summary>
   3.185 +				/// <param name="str">
   3.186 +				/// The <see cref="System.String"/> to turn in to a valid ID
   3.187 +				/// </param>
   3.188 +				/// <returns>
   3.189 +				/// The valid XML ID with all series of invalid characters replaced with an underscore
   3.190 +				/// </returns>
   3.191 +				public static string GetAsciiXmlIdForString(string str)
   3.192 +				{
   3.193 +						string id = GetIdRegex().Replace(str, "_");
   3.194 +						id = GetMultiUnderscoreRegex().Replace(id, "_");
   3.195 +			
   3.196 +						if (!IdStartsWithValidCharacter(id))
   3.197 +						{
   3.198 +								id = "_" + id;
   3.199 +						}
   3.200 +			
   3.201 +						return id;
   3.202 +				}
   3.203 +		
   3.204 +				private static bool IdStartsWithValidCharacter(string id)
   3.205 +				{
   3.206 +						bool valid = false;
   3.207 +			
   3.208 +						if (id.Length > 0)
   3.209 +						{
   3.210 +								char firstChar = id[0];
   3.211 +								valid = ('A' <= firstChar && firstChar <= 'Z') || ('a' <= firstChar && firstChar <= 'z') || firstChar == '_' || firstChar == ':';
   3.212 +						}
   3.213 +			
   3.214 +						return valid;
   3.215 +				}
   3.216 +
   3.217 +				public static void AddSchemaToSetFromResource(XmlSchemaSet schemaSet, string targetNamespace, Assembly assm, string id)
   3.218 +				{
   3.219 +						Stream resStream = assm.GetManifestResourceStream(id);
   3.220 +						schemaSet.Add(targetNamespace, new XmlTextReader(resStream));
   3.221 +				}
   3.222  		}
   3.223 -		
   3.224 -		/// <summary>
   3.225 -		/// Gets the value of an attribute of an element as an integer. Throws a FormatException if the attribute is not an integer.
   3.226 -		/// </summary>
   3.227 -		/// <param name="elem">
   3.228 -		/// The <see cref="XmlElement"/> to get the attribute value of
   3.229 -		/// </param>
   3.230 -		/// <param name="attributeName">
   3.231 -		/// The name of the attribute to get as an integer
   3.232 -		/// </param>
   3.233 -		/// <returns>
   3.234 -		/// The value of the attribute as an integer
   3.235 -		/// </returns>
   3.236 -		public static int GetIntValueFromAttribute(XmlElement elem, string attributeName)
   3.237 -		{
   3.238 -			try
   3.239 -			{
   3.240 -				return int.Parse(elem.GetAttribute(attributeName));
   3.241 -			}
   3.242 -			catch(FormatException)
   3.243 -			{
   3.244 -				throw new FormatException(String.Format("Attribute '{0}' of {1} with ID {2} was not a valid number", attributeName, elem.Name, elem.GetAttribute("id")));
   3.245 -			}
   3.246 -		}
   3.247 -							
   3.248 -		/// <summary>
   3.249 -		/// Gets the value of an attribute of an element as a double. Throws a FormatException if the attribute is not a double.
   3.250 -		/// </summary>
   3.251 -		/// <param name="elem">
   3.252 -		/// The <see cref="XmlElement"/> to get the attribute value of
   3.253 -		/// </param>
   3.254 -		/// <param name="attributeName">
   3.255 -		/// The name of the attribute to get as a double
   3.256 -		/// </param>
   3.257 -		/// <returns>
   3.258 -		/// The value of the attribute as an double
   3.259 -		/// </returns>
   3.260 -		public static double GetDoubleValueFromAttribute(XmlElement elem, string attributeName)
   3.261 -		{
   3.262 -			double doubleVal = double.NaN;
   3.263 -			string attribValue = elem.GetAttribute(attributeName);
   3.264 -			
   3.265 -			if (attribValue == "INF")
   3.266 -			{
   3.267 -				doubleVal = double.PositiveInfinity;
   3.268 -			}
   3.269 -			else
   3.270 -			{
   3.271 -				try
   3.272 -				{
   3.273 -					return double.Parse(attribValue, GetNumberFormatInfo());
   3.274 -				}
   3.275 -				catch(FormatException)
   3.276 -				{
   3.277 -					throw new FormatException(String.Format("Attribute '{0}' of {1} with ID {2} was not a valid number", attributeName, elem.Name, elem.GetAttribute("id")));
   3.278 -				}
   3.279 -			}
   3.280 -			
   3.281 -			return doubleVal;
   3.282 -		}
   3.283 -		
   3.284 -		public static T GetEnumValueFromAttribute<T>(XmlElement elem, string attributeName)
   3.285 -		{
   3.286 -			return GetEnumValueFromAttribute<T>(elem, attributeName, true);
   3.287 -		}
   3.288 -		
   3.289 -		public static T GetEnumValueFromAttribute<T>(XmlElement elem, string attributeName, bool ignoreCase)
   3.290 -		{
   3.291 -			string attribValue = elem.GetAttribute (attributeName);
   3.292 -			
   3.293 -			try
   3.294 -			{
   3.295 -				return EnumTools.ParseEnum<T>(attribValue, ignoreCase);
   3.296 -			}
   3.297 -			catch(ArgumentException)
   3.298 -			{
   3.299 -				throw new FormatException(String.Format("Attribute '{0}' with value {1} for {2} with ID '{3}' was not a valid {4} enum", attributeName, attribValue, elem.Name, elem.GetAttribute("id"), typeof(T).Name));
   3.300 -			}
   3.301 -		}
   3.302 -
   3.303 -		private static NumberFormatInfo GetNumberFormatInfo()
   3.304 -		{
   3.305 -			if (doubleFormat == null)
   3.306 -			{
   3.307 -				doubleFormat = NumberFormatInfo.InvariantInfo;
   3.308 -			}
   3.309 -
   3.310 -			return doubleFormat;
   3.311 -		}
   3.312 -
   3.313 -		private static Regex GetIdRegex()
   3.314 -		{
   3.315 -			if (idRegex == null)
   3.316 -			{
   3.317 -				idRegex = new Regex("[^a-zA-Z0-9:\\._-]+");
   3.318 -			}
   3.319 -			
   3.320 -			return idRegex;
   3.321 -		}
   3.322 -		
   3.323 -		private static Regex GetMultiUnderscoreRegex()
   3.324 -		{
   3.325 -			if (multiUnderscoreRegex == null)
   3.326 -			{
   3.327 -				multiUnderscoreRegex = new Regex("_{2,}");
   3.328 -			}
   3.329 -			
   3.330 -			return multiUnderscoreRegex;
   3.331 -		}
   3.332 -		
   3.333 -		/// <summary>
   3.334 -		/// Gets a valid XML ID for a given string that does not contain accented and non-ASCII characters. Matches the allowed characters
   3.335 -		/// in the XML spec (http://www.w3.org/TR/xml/#NT-NameStartChar) where the characters do not use Unicode character codes. If the ID
   3.336 -		/// starts with an invalid character then it will be prepended with an underscore.
   3.337 -		/// </summary>
   3.338 -		/// <param name="str">
   3.339 -		/// The <see cref="System.String"/> to turn in to a valid ID
   3.340 -		/// </param>
   3.341 -		/// <returns>
   3.342 -		/// The valid XML ID with all series of invalid characters replaced with an underscore
   3.343 -		/// </returns>
   3.344 -		public static string GetAsciiXmlIdForString(string str)
   3.345 -		{
   3.346 -			string id = GetIdRegex().Replace(str, "_");
   3.347 -			id = GetMultiUnderscoreRegex().Replace(id, "_");
   3.348 -			
   3.349 -			if (!IdStartsWithValidCharacter(id))
   3.350 -			{
   3.351 -				id = "_" + id;
   3.352 -			}
   3.353 -			
   3.354 -			return id;
   3.355 -		}
   3.356 -		
   3.357 -		private static bool IdStartsWithValidCharacter(string id)
   3.358 -		{
   3.359 -			bool valid = false;
   3.360 -			
   3.361 -			if (id.Length > 0)
   3.362 -			{
   3.363 -				char firstChar = id[0];
   3.364 -				valid = ('A' <= firstChar && firstChar <= 'Z') || ('a' <= firstChar && firstChar <= 'z') || firstChar == '_' || firstChar == ':';
   3.365 -			}
   3.366 -			
   3.367 -			return valid;
   3.368 -		}
   3.369 -	}
   3.370  }