using System; using System.Collections; using System.IO; using System.Xml; namespace Commons.Xml.Nvdl { internal class NvdlDebug { public static TextWriter Writer = TextWriter.Null; // public static TextWriter Writer = Console.Out; } internal class NvdlDispatcher { NvdlValidatingReader validator; SimpleRules rules; NvdlSection section; // Actually this dispatcher puts possibly identical sections // onto this stack at every StartElement() (unless // IsEmptyElement is true). NvdlSectionStack sectionStack = new NvdlSectionStack (); // This qname stack is required for section 7.3 check that // if parent "element" of an element (note that it is not // "element section") must not be located by the same // trigger element Stack qnameStack = new Stack (); public NvdlDispatcher (SimpleRules rules, NvdlValidatingReader source) { this.validator = source; this.rules = rules; } internal NvdlValidatingReader Validator { get { return validator; } } internal XmlReader Reader { get { return validator.Reader; } } public SimpleRules Rules { get { return rules; } } public void StartElement () { NvdlDebug.Writer.WriteLine (" 0 && rules.Triggers.Length > 0) { for (int t = 0; t < rules.Triggers.Length; t++) { SimpleTrigger st = rules.Triggers [t]; XmlQualifiedName parent = (XmlQualifiedName) qnameStack.Peek (); if (st.Cover (Reader.LocalName, Reader.NamespaceURI) && !st.Cover (parent.Name, parent.Namespace)) { NvdlDebug.Writer.WriteLine ("======== triggered by {0}", st.Location); return new NvdlSection (this, section); } } } return section; } public void EndElement () { NvdlDebug.Writer.WriteLine (" 0) section = sectionStack.Peek (); else section = null; } qnameStack.Pop (); } public void Text () { if (section != null) section.Text (); } public void Whitespace () { if (section != null) section.Whitespace (); } } // // This class is instantiated for every NVDL section. // // For interpretations, the list might share the same // NvdlInterpretation I with other sections (as specified in // step 4 (8.6) of the spec. // internal class NvdlSection { readonly NvdlDispatcher dispatcher; readonly string ns; readonly NvdlInterpretationList ilist = new NvdlInterpretationList (); readonly ArrayList elementNameStack = new ArrayList (); public NvdlSection (NvdlDispatcher dispatcher, NvdlSection parentState) { this.dispatcher = dispatcher; this.ns = dispatcher.Reader.NamespaceURI; if (parentState == null) { foreach (SimpleAction a in FindElementRule ( dispatcher.Rules.StartMode, dispatcher.Reader).Actions) ilist.Add (GetInterp (a, dispatcher)); } else { foreach (NvdlInterpretation pi in parentState.ilist) { PopulateInterp (dispatcher, pi, parentState); } } NvdlDebug.Writer.WriteLine ("New section: ns {0} / interp.count {1} / loc: {2}", ns, ilist.Count, ((IXmlLineInfo) dispatcher.Reader).LineNumber); } private NvdlInterpretation GetInterp ( SimpleAction a, NvdlDispatcher d) { return CreateInterp (d, d.Rules.StartMode, a, null); } private NvdlInterpretation CreateInterp (NvdlDispatcher d, SimpleMode m, SimpleAction a, NvdlInterpretation p) { NvdlDebug.Writer.WriteLine ("***** new interp from action {0} from mode {1}", a.Location, m.Location); SimpleValidate v = a as SimpleValidate; if (v != null) return new NvdlValidateInterp (d, m, v, p); return new NvdlResultInterp (d, m, (SimpleResultAction) a, p); } private void PopulateInterp ( NvdlDispatcher d, NvdlInterpretation i, NvdlSection parentState) { SimpleMode m = FindContextMode (i.Action, parentState); SimpleRule rule = FindElementRule (m, dispatcher.Reader); NvdlDebug.Writer.WriteLine ("***** populate interp from action {0} whose mode is {1}. Rule is {2} whose actions are {3}", i.Action.Location, m.Location, rule.Location, rule.Actions.Length); foreach (SimpleAction a in rule.Actions) { NvdlInterpretation cur = i; for (;cur != null; cur = cur.Parent) if (cur.CreatedMode == m && cur.Action == a) { NvdlDebug.Writer.WriteLine ("------- corresponding PlanElem already exists."); break; } if (cur == null) cur = CreateInterp (d, m, a, i); ilist.Add (cur); } } private SimpleMode FindContextMode (SimpleAction a, NvdlSection parentState) { if (a.Contexts != null) foreach (SimpleContext ctx in a.Contexts) foreach (SimplePath path in ctx.Path) if (MatchPath (path, parentState)) { NvdlDebug.Writer.WriteLine ("------ matched context at {0}.", ctx.Location); return ctx.UseMode; } return a.DefaultMode; } private bool MatchPath (SimplePath path, NvdlSection parentState) { ArrayList stack = parentState.elementNameStack; if (stack.Count == 0) return false; int elemStep = stack.Count - 1; for (int i = path.Steps.Length - 1; i >= 0 && elemStep >= 0;) { SimplePathStep ps = path.Steps [i]; if (ps.Name != stack [elemStep] as string) { // reject a/b while allow a//b if (!ps.Descendants) return false; --elemStep; } else { i--; elemStep--; } } NvdlDebug.Writer.Write ("------ matched path: "); for (int i = 0; i < stack.Count; i++) NvdlDebug.Writer.Write ('[' + (string) stack [i] + ']'); NvdlDebug.Writer.Write (" -> "); for (int i = 0; i < path.Steps.Length; i++) NvdlDebug.Writer.Write ('[' + path.Steps [i].Name + ']'); NvdlDebug.Writer.WriteLine (); return true; } public NvdlDispatcher Dispatcher { get { return dispatcher; } } public NvdlInterpretationList Interpretations { get { return ilist; } } public string Namespace { get { return ns; } } public XmlReader Reader { get { return dispatcher.Reader; } } private SimpleRule FindElementRule (SimpleMode mode, XmlReader reader) { SimpleRule any = null; foreach (SimpleRule rule in mode.ElementRules) { if (rule.MatchNS (reader.NamespaceURI)) { if (!rule.IsAny) return rule; else any = rule; } } NvdlDebug.Writer.WriteLine (" : : : : anyNamespace rule being applied."); if (any != null) return any; throw new NvdlValidationException ("NVDL internal error: should not happen. No matching rule was found.", Reader as IXmlLineInfo); } // It is invoked regardless of IsEmptyElement. public void EndSection () { NvdlDebug.Writer.WriteLine (" ({0})", ns); foreach (NvdlInterpretation i in ilist) i.EndSection (); } public void StartElement () { NvdlDebug.Writer.WriteLine (" "); } public override void EndElement () { NvdlDebug.Writer.WriteLine (" "); } public override void Text () { NvdlDebug.Writer.WriteLine (" "); } public override void Whitespace () { NvdlDebug.Writer.WriteLine (" "); } public override void ValidateStartElement () { switch (type) { case NvdlResultType.Unwrap: NvdlDebug.Writer.WriteLine (": : : : Unwrapping StartElement "); goto case NvdlResultType.Attach; case NvdlResultType.Attach: Parent.ValidateStartElement (); break; case NvdlResultType.AttachPlaceholder: break; } } public override void ValidateEndElement () { switch (type) { case NvdlResultType.Unwrap: NvdlDebug.Writer.WriteLine (": : : : Unwrapping EndElement "); goto case NvdlResultType.Attach; case NvdlResultType.Attach: Parent.ValidateEndElement (); break; case NvdlResultType.AttachPlaceholder: break; } } public override void ValidateText () { switch (type) { case NvdlResultType.Unwrap: NvdlDebug.Writer.WriteLine (": : : : Unwrapping Text "); goto case NvdlResultType.Attach; case NvdlResultType.Attach: Parent.ValidateText (); break; case NvdlResultType.AttachPlaceholder: break; } } public override void ValidateWhitespace () { switch (type) { case NvdlResultType.Unwrap: NvdlDebug.Writer.WriteLine (": : : : Unwrapping Whitespace "); goto case NvdlResultType.Attach; case NvdlResultType.Attach: Parent.ValidateWhitespace (); break; case NvdlResultType.AttachPlaceholder: break; } } } internal class NvdlValidateInterp : NvdlInterpretation { NvdlFilteredXmlReader reader; // s SimpleValidate validate; XmlReader validator; public NvdlValidateInterp (NvdlDispatcher dispatcher, SimpleMode createdMode, SimpleValidate validate, NvdlInterpretation parent) : base (dispatcher, createdMode, validate, parent) { NvdlDebug.Writer.WriteLine ("++++++ new validate " + validate.Location); this.reader = new NvdlFilteredXmlReader (dispatcher.Reader, this); this.validate = validate; validator = validate.CreateValidator (this.reader); dispatcher.Validator.OnMessage (validate.Messages); } public override void AttachPlaceholder () { reader.AttachPlaceholder (); validator.Read (); // check start Element } public override void DetachPlaceholder () { reader.DetachPlaceholder (); // since placeholder is *empty*, we don't have to // validate this virtual element. //validator.Read (); } public override void EndSection () { } public override void StartElement () { NvdlDebug.Writer.WriteLine ("