Mercurial > repos > IBBoard
changeset 22:ea058f9ea9d4
Closes #15 - Migrate to schema for translations
* Add XSD and remove DTD for translation document format
* Copy XSD to output on compile
* Make Translations validate against a schema and handle new exceptions caused by Schema use
Also:
* Tweak resolver so that it handles paths starting "dtds/" as a special case instead of just "dtds"
author | IBBoard <dev@ibboard.co.uk> |
---|---|
date | Sat, 07 Mar 2009 15:52:27 +0000 |
parents | c8d74202182a |
children | fb4fdab841db |
files | IBBoard.csproj Lang/Translation.cs Xml/IBBXmlResolver.cs dtds/translation.dtd dtds/translation.xsd |
diffstat | 5 files changed, 69 insertions(+), 16 deletions(-) [+] |
line wrap: on
line diff
--- a/IBBoard.csproj Thu Mar 05 20:34:31 2009 +0000 +++ b/IBBoard.csproj Sat Mar 07 15:52:27 2009 +0000 @@ -142,6 +142,8 @@ <ItemGroup> <None Include="COPYING.GPL" /> <None Include="COPYING.LGPL" /> - <None Include="dtds\translation.dtd" /> + <None Include="dtds\translation.xsd"> + <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> + </None> </ItemGroup> </Project> \ No newline at end of file
--- a/Lang/Translation.cs Thu Mar 05 20:34:31 2009 +0000 +++ b/Lang/Translation.cs Sat Mar 07 15:52:27 2009 +0000 @@ -27,7 +27,8 @@ private static string lang = ""; private static DirectoryInfo translationDir; private static Dictionary<string, string> translationsLocal; - private static Dictionary<string, string> translationsDefault; + private static Dictionary<string, string> translationsDefault; + private static XmlReaderSettings settings; /// <summary> /// Initialises the translations for the language specified and the default translations so that the Translation class can be used. @@ -67,18 +68,17 @@ private static XmlDocument LoadTranslationDocument(FileInfo file) { - XmlDocument doc = new XmlDocument(); - XmlReaderSettings settings = new XmlReaderSettings(); - settings.XmlResolver = new IBBXmlResolver(translationDir.Parent.FullName); - settings.ValidationType = ValidationType.DTD; - settings.ProhibitDtd = false; - settings.ValidationEventHandler+= new ValidationEventHandler(ValidationEventMethod); - XmlReader valReader = XmlReader.Create(file.FullName, settings); + XmlDocument doc = new XmlDocument(); + XmlReader valReader = XmlReader.Create(file.FullName, GetReaderSettings()); try { doc.Load(valReader); } + catch (DirectoryNotFoundException ex) + { + throw new TranslationLoadException("Problem validating schema for translation: " + ex.Message, ex); + } catch (XmlSchemaException ex) { throw new TranslationLoadException("Problem validating schema for translation: " + ex.Message, ex); @@ -95,6 +95,44 @@ return doc; } + /// <summary> + /// Lazy-getter for XML reader settings. May throw a <see cref="TranslationLoadException"/> 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 static XmlReaderSettings GetReaderSettings() + { + if (settings == null) + { + try + { + settings = new XmlReaderSettings(); + settings.XmlResolver = new IBBXmlResolver(translationDir.Parent.FullName); + settings.ValidationType = ValidationType.Schema; + settings.ValidationFlags = XmlSchemaValidationFlags.ReportValidationWarnings | XmlSchemaValidationFlags.ProcessSchemaLocation; + settings.ValidationEventHandler+= new ValidationEventHandler(ValidationEventMethod); + XmlSchemaSet cache = new XmlSchemaSet(); + cache.Add("http://ibboard.co.uk/translation", translationDir.Parent.FullName + "/dtds/translation.xsd"); + settings.Schemas.Add(cache); + } + catch (DirectoryNotFoundException ex) + { + throw new TranslationLoadException("Problem validating schema for translation: " + ex.Message, ex); + } + catch (XmlSchemaException ex) + { + throw new TranslationLoadException("Problem validating schema for translation: " + ex.Message, ex); + } + catch (XmlException ex) + { + throw new TranslationLoadException("Problem reading data for schema: " + ex.Message, ex); + } + } + + return settings; + } + private static FileInfo GetTranslationFile(string language) { FileInfo file = new FileInfo(translationDir.FullName + Constants.DirectoryString + language + ".translation"); @@ -147,8 +185,7 @@ private static void ValidationEventMethod(object sender, ValidationEventArgs e) { - //TODO: Fire a validation failure event - LogNotifier.Error(typeof(Translation), "Validation Error", e.Exception); + throw new TranslationLoadException("Problem validating schema for translation: " + e.Exception.Message, e.Exception); } /// <summary>
--- a/Xml/IBBXmlResolver.cs Thu Mar 05 20:34:31 2009 +0000 +++ b/Xml/IBBXmlResolver.cs Sat Mar 07 15:52:27 2009 +0000 @@ -21,7 +21,7 @@ public override Uri ResolveUri(Uri baseUri, string relativeUri) { - if (relativeUri.StartsWith("dtds")) + if (relativeUri.StartsWith("dtds/")) { //Uri uri = base.ResolveUri(baseUri, relativeUri); return new Uri(Uri.UriSchemeFile + "://" + baseFilePath + Constants.DirectoryString + relativeUri);
--- a/dtds/translation.dtd Thu Mar 05 20:34:31 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,4 +0,0 @@ -<!ELEMENT translations (translation*)> -<!ELEMENT translation (#PCDATA)> <!-- it's a damned ugly hack, but C# won't take "#CDATA" so use #PCDATA and always treat it as CDATA --> -<!ATTLIST translation id ID #REQUIRED> -<!ATTLIST translations lang CDATA #REQUIRED> \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dtds/translation.xsd Sat Mar 07 15:52:27 2009 +0000 @@ -0,0 +1,18 @@ +<?xml version="1.0"?> +<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="http://ibboard.co.uk/translation" xmlns="http://ibboard.co.uk/translation" elementFormDefault="qualified"> +<xs:complexType name="translationtype"> + <xs:simpleContent> + <xs:extension base="xs:string"> + <xs:attribute name="id" type="xs:ID" /> + </xs:extension> + </xs:simpleContent> +</xs:complexType> +<xs:element name="translations"> + <xs:complexType> + <xs:sequence> + <xs:element name="translation" maxOccurs="unbounded" type="translationtype"/> + </xs:sequence> + <xs:attribute name="lang" type="xs:string" use="required"/> + </xs:complexType> +</xs:element> +</xs:schema> \ No newline at end of file