// // Commons.Xml.Relaxng.RelaxngPattern.cs // // Author: // Atsushi Enomoto // // 2003 Atsushi Enomoto "No rights reserved." // // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // using System; using System.Collections; using System.IO; using System.Xml; using Commons.Xml.Relaxng.Derivative; namespace Commons.Xml.Relaxng { #region Common abstract public abstract class RelaxngElementBase { bool isCompiled; int lineNumber, linePosition; string baseUri; internal bool IsCompiled { get { return isCompiled; } set { isCompiled = value; } } public int LineNumber { get { return lineNumber; } set { lineNumber = value; } } public int LinePosition { get { return linePosition; } set { linePosition = value; } } public string BaseUri { get { return baseUri; } set { baseUri = value; } } public abstract void Write (XmlWriter write); } public abstract class RelaxngSingleContentPattern : RelaxngPattern { private RelaxngPatternList patterns = new RelaxngPatternList (); public RelaxngPatternList Patterns { get { return patterns; } } internal RdpPattern makeSingle (RelaxngGrammar g) { // Flatten patterns into RdpGroup. See 4.12. if (patterns.Count == 0) throw new RelaxngException ("No pattern contents."); RdpPattern p = ((RelaxngPattern) patterns [0]).Compile (g); if (patterns.Count == 1) return p; for (int i=1; i 0 && g.Starts.Count == 0) throw new RelaxngException ("When the included grammar does not contain start components, this include component must not contain start components."); RelaxngGrammarContentList appliedStarts = (this.starts.Count > 0) ? this.starts : g.Starts; RelaxngDiv div = new RelaxngDiv (); div.BaseUri = this.BaseUri; div.LinePosition = this.LinePosition; div.LineNumber = this.LineNumber; foreach (RelaxngStart start in appliedStarts) div.Starts.Add (start); // defines. Hashtable overrides = new Hashtable (); Hashtable originalDefs = new Hashtable (); foreach (RelaxngDefine def in defines) { overrides.Add (def.Name, def.Name); div.Defines.Add (def); } foreach (RelaxngDefine def in g.Defines) { originalDefs.Add (def.Name, def.Name); if (overrides [def.Name] == null) div.Defines.Add (def); // else discard. } foreach (string name in overrides.Values) if (!originalDefs.Contains (name)) throw new RelaxngException ("The include component must not contain define components whose name does not appear in the included grammar component."); grammar.IncludedUris.Remove (Href); return div; } } public class RelaxngDiv : RelaxngElementBase, IGrammarContent { RelaxngGrammarContentList starts = new RelaxngGrammarContentList (); RelaxngGrammarContentList defines = new RelaxngGrammarContentList (); RelaxngGrammarContentList includes = new RelaxngGrammarContentList (); RelaxngGrammarContentList divs = new RelaxngGrammarContentList (); public RelaxngDiv () { } public RelaxngGrammarContentList Starts { get { return starts; } } public RelaxngGrammarContentList Defines { get { return defines; } } public RelaxngGrammarContentList Includes { get { return includes; } } public RelaxngGrammarContentList Divs { get { return divs; } } public override void Write (XmlWriter writer) { writer.WriteStartElement ("", "div", RelaxngGrammar.NamespaceURI); foreach (RelaxngStart start in Starts) start.Write (writer); foreach (RelaxngDefine define in Defines) define.Write (writer); foreach (RelaxngInclude include in Includes) include.Write (writer); foreach (RelaxngDiv div in Divs) div.Write (writer); writer.WriteEndElement (); } internal void Compile (RelaxngGrammar grammar) { foreach (RelaxngDiv div in divs) div.Compile (grammar); foreach (RelaxngInclude inc in includes) inc.Compile (grammar).Compile (grammar); // compile compiled divs foreach (RelaxngStart start in starts) grammar.Starts.Add (start); foreach (RelaxngDefine define in defines) grammar.Defines.Add (define); } } #endregion #region RelaxngPatterns public abstract class RelaxngPattern : RelaxngElementBase { // static public static RelaxngPattern Read (XmlReader xmlReader) { return Read (xmlReader, null); } public static RelaxngPattern Read (XmlReader xmlReader, RelaxngDatatypeProvider provider) { RelaxngReader r = new RelaxngReader (xmlReader, null); if (r.ReadState == ReadState.Initial) r.Read (); r.MoveToContent (); RelaxngPattern p = r.ReadPattern (); p.DataProvider = provider; return p; } // Private Fields RdpPattern startRelaxngPattern; RelaxngDatatypeProvider provider; XmlResolver resolver; bool nullResolver; // Public public XmlResolver XmlResolver { set { nullResolver = value == null; resolver = value; } } public abstract RelaxngPatternType PatternType { get; } public RelaxngDatatypeProvider DataProvider { get { return provider; } set { provider = value; } } public void Compile () { RelaxngGrammar g = null; if (this is RelaxngGrammar) g = (RelaxngGrammar) this; else { g = new RelaxngGrammar (); g.XmlResolver = this.Resolver; g.BaseUri = this.BaseUri; g.LineNumber = this.LineNumber; g.LinePosition = this.LinePosition; RelaxngStart st = new RelaxngStart (); st.BaseUri = this.BaseUri; st.LineNumber = this.LineNumber; st.LinePosition = this.LinePosition; st.Pattern = this; g.Starts.Add (st); g.Provider = provider; } startRelaxngPattern = g.Compile (null); this.IsCompiled = true; } // Internal internal XmlResolver Resolver { get { if (nullResolver) return null; if (resolver == null) resolver = new XmlUrlResolver (); return resolver; } } internal abstract void CheckConstraints (); protected RelaxngPattern () { } internal abstract RdpPattern Compile (RelaxngGrammar grammar); internal RdpPattern StartPattern { get { return startRelaxngPattern; } } } public class RelaxngPatternList : CollectionBase { public RelaxngPatternList () { } public void Add (RelaxngPattern p) { List.Add (p); } public RelaxngPattern this [int i] { get { return this.List [i] as RelaxngPattern; } set { this.List [i] = value; } } public void Insert (int pos, RelaxngPattern p) { List.Insert (pos, p); } public void Remove (RelaxngPattern p) { List.Remove (p); } } public class RelaxngGrammarContentList : CollectionBase { public RelaxngGrammarContentList () { } public void Add (IGrammarContent p) { List.Add (p); } public IGrammarContent this [int i] { get { return this.List [i] as IGrammarContent; } set { this.List [i] = value; } } public void Insert (int pos, IGrammarContent p) { List.Insert (pos, p); } public void Remove (IGrammarContent p) { List.Remove (p); } } // strict to say, it's not a pattern ;) public class RelaxngNotAllowed : RelaxngPattern { public RelaxngNotAllowed () { } public override RelaxngPatternType PatternType { get { return RelaxngPatternType.NotAllowed; } } public override void Write (XmlWriter writer) { writer.WriteStartElement ("", "notAllowed", RelaxngGrammar.NamespaceURI); writer.WriteEndElement (); } internal override RdpPattern Compile (RelaxngGrammar grammar) { return RdpNotAllowed.Instance; } internal override void CheckConstraints () { // nothing to check } } public class RelaxngEmpty : RelaxngPattern { public RelaxngEmpty () { } public override RelaxngPatternType PatternType { get { return RelaxngPatternType.Empty; } } public override void Write (XmlWriter writer) { writer.WriteStartElement ("", "empty", RelaxngGrammar.NamespaceURI); writer.WriteEndElement (); } internal override RdpPattern Compile (RelaxngGrammar grammar) { return RdpEmpty.Instance; } internal override void CheckConstraints () { // nothing to check } } public class RelaxngText : RelaxngPattern { public RelaxngText () { } public override RelaxngPatternType PatternType { get { return RelaxngPatternType.Text; } } public override void Write (XmlWriter writer) { writer.WriteStartElement ("", "text", RelaxngGrammar.NamespaceURI); writer.WriteEndElement (); } internal override RdpPattern Compile (RelaxngGrammar grammar) { return RdpText.Instance; } internal override void CheckConstraints () { // nothing to check } } public abstract class RelaxngDataSupport : RelaxngPattern { string type; string datatypeLibrary; public string Type { get { return type; } set { type = value; } } public string DatatypeLibrary { get { return datatypeLibrary; } set { datatypeLibrary = value; } } internal void CheckDatatypeName () { // Data type name check is done in RdpData(Except) derivative creation. } } public class RelaxngData : RelaxngDataSupport { RelaxngParamList paramList = new RelaxngParamList (); RelaxngExcept except; public RelaxngData () { } public override RelaxngPatternType PatternType { get { return RelaxngPatternType.Data; } } public RelaxngParamList ParamList { get { return paramList; } } public RelaxngExcept Except { get { return except; } set { except = value; } } public override void Write (XmlWriter writer) { writer.WriteStartElement ("", "data", RelaxngGrammar.NamespaceURI); if (DatatypeLibrary != null && DatatypeLibrary != String.Empty) writer.WriteAttributeString ("xmlns", "data", "http://www.w3.org/2000/xmlns/", DatatypeLibrary); writer.WriteStartAttribute ("type", String.Empty); writer.WriteQualifiedName (Type, DatatypeLibrary); writer.WriteEndAttribute (); foreach (RelaxngParam p in ParamList) p.Write (writer); if (Except != null) Except.Write (writer); writer.WriteEndElement (); } internal override RdpPattern Compile (RelaxngGrammar grammar) { // RdpParamList rdpl = new RdpParamList (); // foreach (RelaxngParam prm in this.paramList) // rdpl.Add (prm.Compile (grammar)); RdpPattern p = null; if (this.except != null) { if (except.Patterns.Count == 0) throw new RelaxngException ("data except pattern have no children."); p = except.Patterns [0].Compile (grammar); for (int i=1; i