copying the latest Sys.Web.Services from trunk.
[mono.git] / mcs / class / Commons.Xml.Relaxng / Commons.Xml.Nvdl / NvdlValidator.cs
1 using System;
2 using System.Collections;
3 using System.IO;
4 using System.Xml;
5
6 namespace Commons.Xml.Nvdl
7 {
8         internal class NvdlDebug
9         {
10                 public static TextWriter Writer = TextWriter.Null;
11 //              public static TextWriter Writer = Console.Out;
12         }
13
14         internal class NvdlDispatcher
15         {
16                 NvdlValidatingReader validator;
17                 SimpleRules rules;
18                 NvdlSection section;
19                 // Actually this dispatcher puts possibly identical sections
20                 // onto this stack at every StartElement() (unless
21                 // IsEmptyElement is true).
22                 NvdlSectionStack sectionStack = new NvdlSectionStack ();
23
24                 public NvdlDispatcher (SimpleRules rules, NvdlValidatingReader source)
25                 {
26                         this.validator = source;
27                         this.rules = rules;
28                 }
29
30                 internal NvdlValidatingReader Validator {
31                         get { return validator; }
32                 }
33
34                 internal XmlReader Reader {
35                         get { return validator.Reader; }
36                 }
37
38                 public SimpleRules Rules {
39                         get { return rules; }
40                 }
41
42                 public void StartElement ()
43                 {
44 NvdlDebug.Writer.WriteLine ("  <dispatcher.StartElement {0}. stack depth: {1}. current section ns {2}",
45 Reader.Name, sectionStack.Count, section == null ? "(none)" : section.Namespace);
46                         if (section == null)
47                                 section = new NvdlSection (this, null);
48                         else if (section.Namespace != Reader.NamespaceURI)
49                                 section = new NvdlSection (this, section);
50
51                         sectionStack.Push (section);
52                         section.StartElement ();
53                         if (Reader.IsEmptyElement)
54                                 sectionStack.Pop ().EndSection ();
55                 }
56
57                 public void EndElement ()
58                 {
59 NvdlDebug.Writer.WriteLine ("  <dispatcher.EndElement {0}. depth: {1}",
60 Reader.Name, sectionStack.Count);
61                         if (section != null) {
62                                 section = sectionStack.Pop ();
63                                 section.EndElement ();
64                                 section.EndSection ();
65                                 if (sectionStack.Count > 0)
66                                         section = sectionStack.Peek ();
67                                 else
68                                         section = null;
69                         }
70                 }
71
72                 public void Text ()
73                 {
74                         if (section != null)
75                                 section.Text ();
76                 }
77
78                 public void Whitespace ()
79                 {
80                         if (section != null)
81                                 section.Whitespace ();
82                 }
83         }
84
85         //
86         // This class is instantiated for every NVDL section.
87         //
88         // For interpretations, the list might share the same
89         // NvdlInterpretation I with other sections (as specified in
90         // step 4 (8.6) of the spec.
91         //
92         internal class NvdlSection
93         {
94                 readonly NvdlDispatcher dispatcher;
95                 readonly string ns;
96                 readonly NvdlInterpretationList ilist = new NvdlInterpretationList ();
97                 readonly ArrayList elementNameStack = new ArrayList ();
98
99                 public NvdlSection (NvdlDispatcher dispatcher,
100                         NvdlSection parentState)
101                 {
102                         this.dispatcher = dispatcher;
103                         this.ns = dispatcher.Reader.NamespaceURI;
104
105                         if (parentState == null) {
106                                 foreach (SimpleAction a in FindElementRule (
107                                         dispatcher.Rules.StartMode,
108                                         dispatcher.Reader).Actions)
109                                         ilist.Add (GetInterp (a, dispatcher));
110                         } else {
111                                 foreach (NvdlInterpretation pi in
112                                         parentState.ilist) {
113                                         PopulateInterp (dispatcher, pi);
114                                 }
115                         }
116
117 NvdlDebug.Writer.WriteLine ("New section: ns {0} / interp.count {1} / loc: {2}", ns, ilist.Count, ((IXmlLineInfo) dispatcher.Reader).LineNumber);
118                 }
119
120                 private NvdlInterpretation GetInterp (
121                         SimpleAction a, NvdlDispatcher d)
122                 {
123                         return CreateInterp (d, d.Rules.StartMode, a, null);
124                 }
125
126                 private NvdlInterpretation CreateInterp (NvdlDispatcher d,
127                         SimpleMode m, SimpleAction a, NvdlInterpretation p)
128                 {
129 NvdlDebug.Writer.WriteLine ("***** new interp from action {0} from mode {1}", a.Location, m.Location);
130                         SimpleValidate v = a as SimpleValidate;
131                         if (v != null)
132                                 return new NvdlValidateInterp (d, m, v, p);
133                         return new NvdlResultInterp (d, m, (SimpleResultAction) a, p);
134                 }
135
136                 private void PopulateInterp (
137                         NvdlDispatcher d, NvdlInterpretation i)
138                 {
139                         SimpleMode m = FindContextMode (i.Action);
140                         SimpleRule rule = FindElementRule (m, dispatcher.Reader);
141 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);
142                         foreach (SimpleAction a in rule.Actions) {
143                                 NvdlInterpretation cur = i;
144                                 for (;cur != null; cur = cur.Parent)
145                                         if (cur.CreatedMode == m && cur.Action == a) {
146 NvdlDebug.Writer.WriteLine ("------- corresponding PlanElem already exists.");
147                                                 break;
148                                         }
149                                 if (cur == null)
150                                         cur = CreateInterp (d, m, a, i);
151                                 ilist.Add (cur);
152                         }
153                 }
154
155                 private SimpleMode FindContextMode (SimpleAction a)
156                 {
157                         if (a.Contexts != null)
158                                 foreach (SimpleContext ctx in a.Contexts)
159                                         foreach (SimplePath path in ctx.Path)
160                                                 if (MatchPath (path))
161                                                         return ctx.UseMode;
162                         return a.DefaultMode;
163                 }
164
165                 private bool MatchPath (SimplePath path)
166                 {
167                         int elemStep = elementNameStack.Count - 1;
168                         for (int i = path.Steps.Length; i >= 0 && elemStep >= 0;) {
169                                 SimplePathStep ps = path.Steps [i];
170                                 if (ps.Name != elementNameStack [elemStep] as string) {
171                                         if (!ps.Descendants)
172                                                 return false;
173                                         if (--elemStep < 0)
174                                                 return false;
175                                 }
176                                 else {
177                                         i--;
178                                         elemStep--;
179                                 }
180                         }
181                         return false;
182                 }
183
184                 public NvdlDispatcher Dispatcher {
185                         get { return dispatcher; }
186                 }
187
188                 public NvdlInterpretationList Interpretations {
189                         get { return ilist; }
190                 }
191
192                 public string Namespace {
193                         get { return ns; }
194                 }
195
196                 public XmlReader Reader {
197                         get { return dispatcher.Reader; }
198                 }
199
200                 private SimpleRule FindElementRule (SimpleMode mode, XmlReader reader)
201                 {
202                         SimpleRule any = null;
203                         foreach (SimpleRule rule in mode.ElementRules) {
204                                 if (rule.MatchNS (reader.NamespaceURI)) {
205                                         if (!rule.IsAny)
206                                                 return rule;
207                                         else
208                                                 any = rule;
209                                 }
210                         }
211 NvdlDebug.Writer.WriteLine (" : : : : anyNamespace rule being applied.");
212                         if (any != null)
213                                 return any;
214                         throw new NvdlValidationException ("NVDL internal error: should not happen. No matching rule was found.", Reader as IXmlLineInfo);
215                 }
216
217                 // It is invoked regardless of IsEmptyElement.
218                 public void EndSection ()
219                 {
220                         foreach (NvdlInterpretation i in ilist)
221                                 i.EndSection ();
222                 }
223
224                 public void StartElement ()
225                 {
226 NvdlDebug.Writer.WriteLine ("    <state.StartElement {0}", Reader.Name);
227                         elementNameStack.Add (Reader.LocalName);
228                         ValidateStartElement ();
229                         if (Reader.IsEmptyElement)
230                                 elementNameStack.RemoveAt (elementNameStack.Count - 1);
231                 }
232
233                 private void ValidateStartElement ()
234                 {
235                         foreach (NvdlInterpretation i in ilist)
236                                 i.StartElement ();
237                 }
238
239                 public void EndElement ()
240                 {
241 NvdlDebug.Writer.WriteLine ("    <state.EndElement {0} (for {2}). {1} interp.", Reader.Name, ilist.Count, Namespace);
242                         ValidateEndElement ();
243                         elementNameStack.RemoveAt (elementNameStack.Count - 1);
244                 }
245
246                 private void ValidateEndElement ()
247                 {
248                         foreach (NvdlInterpretation i in ilist)
249                                 i.EndElement ();
250                 }
251
252                 public void Text ()
253                 {
254                         ValidateText ();
255                 }
256
257                 private void ValidateText ()
258                 {
259                         foreach (NvdlInterpretation i in ilist)
260                                 i.Text ();
261                 }
262
263                 public void Whitespace ()
264                 {
265                         ValidateWhitespace ();
266                 }
267
268                 private void ValidateWhitespace ()
269                 {
270                         foreach (NvdlInterpretation i in ilist)
271                                 i.Whitespace ();
272                 }
273         }
274
275         internal class NvdlSectionStack : CollectionBase
276         {
277                 public void Push (NvdlSection state)
278                 {
279                         List.Add (state);
280                 }
281
282                 public NvdlSection this [int i] {
283                         get { return (NvdlSection) List [i]; }
284                 }
285
286                 public NvdlSection Peek ()
287                 {
288                         return (NvdlSection) List [List.Count - 1];
289                 }
290
291                 public NvdlSection Pop ()
292                 {
293                         NvdlSection ret = this [List.Count - 1];
294                         List.RemoveAt (List.Count - 1);
295                         return ret;
296                 }
297         }
298
299         internal class NvdlInterpretationList : CollectionBase
300         {
301                 public void Add (NvdlInterpretation i)
302                 {
303                         List.Add (i);
304                 }
305
306                 public NvdlInterpretation this [int i] {
307                         get { return (NvdlInterpretation) List [i]; }
308                 }
309
310                 public void Remove (NvdlInterpretation i)
311                 {
312                         List.Remove (i);
313                 }
314         }
315         internal abstract class NvdlInterpretation
316         {
317                 NvdlDispatcher dispatcher;
318                 SimpleMode createdMode; // IM(s)
319                 SimpleAction action; // IA(s)
320                 NvdlInterpretation parent;
321
322                 public NvdlInterpretation (NvdlDispatcher dispatcher,
323                         SimpleMode createdMode, SimpleAction action,
324                         NvdlInterpretation parent)
325                 {
326                         this.dispatcher = dispatcher;
327                         this.createdMode = createdMode;
328                         this.action = action;
329                         this.parent = parent;
330                 }
331
332                 internal NvdlDispatcher Dispatcher {
333                         get { return dispatcher; }
334                 }
335
336                 public SimpleMode CreatedMode {
337                         get { return createdMode; }
338                 }
339
340                 public SimpleAction Action {
341                         get { return action; }
342                 }
343
344                 public NvdlInterpretation Parent {
345                         get { return parent; }
346                 }
347
348                 public abstract void AttachPlaceHolder ();
349                 public abstract void DetachPlaceHolder ();
350                 public abstract void StartElement ();
351                 public abstract void EndElement ();
352                 public abstract void Text ();
353                 public abstract void Whitespace ();
354                 public abstract void ValidateStartElement ();
355                 public abstract void ValidateEndElement ();
356                 public abstract void ValidateText ();
357                 public abstract void ValidateWhitespace ();
358                 public abstract void EndSection ();
359         }
360
361         internal class NvdlResultInterp : NvdlInterpretation
362         {
363                 NvdlResultType type;
364
365                 public NvdlResultInterp (NvdlDispatcher dispatcher,
366                         SimpleMode createdMode,
367                         SimpleResultAction resultAction,
368                         NvdlInterpretation parent)
369                         : base (dispatcher, createdMode, resultAction, parent)
370                 {
371 NvdlDebug.Writer.WriteLine ("++++++ new resultAction " + resultAction.Location);
372                         type = resultAction.ResultType;
373
374                         if (type == NvdlResultType.AttachPlaceHolder && parent != null)
375                                 parent.AttachPlaceHolder ();
376                 }
377
378                 public override void EndSection ()
379                 {
380                         if (type == NvdlResultType.AttachPlaceHolder && Parent != null)
381                                 Parent.DetachPlaceHolder ();
382                 }
383
384                 public override void AttachPlaceHolder ()
385                 {
386                         if (type == NvdlResultType.Unwrap)
387                                 Parent.AttachPlaceHolder ();
388                 }
389
390                 public override void DetachPlaceHolder ()
391                 {
392                         if (type == NvdlResultType.Unwrap)
393                                 Parent.DetachPlaceHolder ();
394                 }
395
396                 public override void StartElement ()
397                 {
398 NvdlDebug.Writer.WriteLine ("            <result.StartElement : " + type + "/"+ Action.Location);
399                         if (type != NvdlResultType.Unwrap)
400                                 ValidateStartElement (); // unwrap itself does not dispatch to parent interpretation
401 NvdlDebug.Writer.WriteLine ("            </result>");
402                 }
403
404                 public override void EndElement ()
405                 {
406 NvdlDebug.Writer.WriteLine ("            <result.EndElement : " + type + "/" + ((IXmlLineInfo) Dispatcher.Reader).LineNumber);
407                         if (type != NvdlResultType.Unwrap)
408                                 ValidateEndElement (); // unwrap itself does not dispatch to parent interpretation
409 NvdlDebug.Writer.WriteLine ("            </result>");
410                 }
411
412                 public override void Text ()
413                 {
414 NvdlDebug.Writer.WriteLine ("            <result.Text : " + type + "/" + ((IXmlLineInfo) Dispatcher.Reader).LineNumber);
415                         if (type != NvdlResultType.Unwrap)
416                                 ValidateText (); // unwrap itself does not dispatch to parent interpretation
417 NvdlDebug.Writer.WriteLine ("            </result>");
418                 }
419
420                 public override void Whitespace ()
421                 {
422 NvdlDebug.Writer.WriteLine ("            <result.Whitespace : " + type + "/" + ((IXmlLineInfo) Dispatcher.Reader).LineNumber);
423                         if (type != NvdlResultType.Unwrap)
424                                 ValidateWhitespace (); // unwrap itself does not dispatch to parent interpretation
425 NvdlDebug.Writer.WriteLine ("            </result>");
426                 }
427
428                 public override void ValidateStartElement ()
429                 {
430                         switch (type) {
431                         case NvdlResultType.Unwrap:
432 NvdlDebug.Writer.WriteLine (": : : : Unwrapping StartElement ");
433                                 goto case NvdlResultType.Attach;
434                         case NvdlResultType.Attach:
435                                 Parent.ValidateStartElement ();
436                                 break;
437                         case NvdlResultType.AttachPlaceHolder:
438                                 throw new NotImplementedException ();
439                         }
440                 }
441                 public override void ValidateEndElement ()
442                 {
443                         switch (type) {
444                         case NvdlResultType.Unwrap:
445 NvdlDebug.Writer.WriteLine (": : : : Unwrapping EndElement ");
446                                 goto case NvdlResultType.Attach;
447                         case NvdlResultType.Attach:
448                                 Parent.ValidateEndElement ();
449                                 break;
450                         case NvdlResultType.AttachPlaceHolder:
451                                 throw new NotImplementedException ();
452                         }
453                 }
454                 public override void ValidateText ()
455                 {
456                         switch (type) {
457                         case NvdlResultType.Unwrap:
458 NvdlDebug.Writer.WriteLine (": : : : Unwrapping Text ");
459                                 goto case NvdlResultType.Attach;
460                         case NvdlResultType.Attach:
461                                 Parent.ValidateText ();
462                                 break;
463                         case NvdlResultType.AttachPlaceHolder:
464                                 throw new NotImplementedException ();
465                         }
466                 }
467                 public override void ValidateWhitespace ()
468                 {
469                         switch (type) {
470                         case NvdlResultType.Unwrap:
471 NvdlDebug.Writer.WriteLine (": : : : Unwrapping Whitespace ");
472                                 goto case NvdlResultType.Attach;
473                         case NvdlResultType.Attach:
474                                 Parent.ValidateWhitespace ();
475                                 break;
476                         case NvdlResultType.AttachPlaceHolder:
477                                 throw new NotImplementedException ();
478                         }
479                 }
480         }
481
482         internal class NvdlValidateInterp : NvdlInterpretation
483         {
484                 NvdlFilteredXmlReader reader; // s
485                 XmlReader validator;
486
487                 public NvdlValidateInterp (NvdlDispatcher dispatcher,
488                         SimpleMode createdMode, SimpleValidate validate,
489                         NvdlInterpretation parent)
490                         : base (dispatcher, createdMode, validate, parent)
491                 {
492 NvdlDebug.Writer.WriteLine ("++++++ new validate " + validate.Location);
493                         this.reader = new NvdlFilteredXmlReader (dispatcher.Reader, this);
494                         validator = validate.CreateValidator (this.reader);
495
496                         dispatcher.Validator.OnMessage (validate.Messages);
497                 }
498
499                 public override void AttachPlaceHolder ()
500                 {
501                         reader.AttachPlaceHolder ();
502                         validator.Read (); // check start Element
503                 }
504
505                 public override void DetachPlaceHolder ()
506                 {
507                         reader.DetachPlaceHolder ();
508                         validator.Read (); // check EndElement
509                 }
510
511                 public override void EndSection ()
512                 {
513                 }
514
515                 public override void StartElement ()
516                 {
517                         ValidateStartElement ();
518                 }
519
520                 public override void EndElement ()
521                 {
522                         ValidateEndElement ();
523                 }
524
525                 public override void Text ()
526                 {
527                         ValidateText ();
528                 }
529
530                 public override void Whitespace ()
531                 {
532                         ValidateWhitespace ();
533                 }
534
535                 public override void ValidateStartElement ()
536                 {
537 NvdlDebug.Writer.WriteLine ("###### interp.ValidateStartElement : " + Action.Location);
538                         validator.Read ();
539                 }
540
541                 public override void ValidateEndElement ()
542                 {
543 NvdlDebug.Writer.WriteLine ("###### interp.ValidateEndElement : " + Action.Location);
544                         validator.Read ();
545                 }
546
547                 public override void ValidateText ()
548                 {
549 NvdlDebug.Writer.WriteLine ("###### interp.ValidateText : " + Action.Location);
550                         validator.Read ();
551                 }
552
553                 public override void ValidateWhitespace ()
554                 {
555 NvdlDebug.Writer.WriteLine ("###### interp.Whitespace : " + Action.Location);
556                         validator.Read ();
557                 }
558         }
559 }
560