2 using System.Collections;
6 namespace Commons.Xml.Nvdl
8 internal class NvdlFilteredXmlReader : XmlReader, IXmlLineInfo
10 // In this XmlReader, when AttachPlaceHolder() is called,
11 // it treats the next node as to point virtual "placeholder"
12 // element where IsEmptyElement is false. When it is
13 // Detached, then *current* node becomes the usual reader
17 int placeHolderDepth = 0;
18 XmlNodeType nextPlaceHolder;
19 XmlNodeType placeHolder = XmlNodeType.None;
20 bool placeHolderLocalNameAttr;
21 NvdlValidateInterp validate;
23 IXmlLineInfo reader_as_line_info;
25 AttributeInfo [] attributes = new AttributeInfo [10];
26 int attributeCount = 0;
28 // PlanAtt validation cache.
29 Hashtable attributeValidators = new Hashtable ();
33 public string LocalName;
34 public string NamespaceURI;
37 public NvdlFilteredXmlReader (XmlReader reader,
38 NvdlValidateInterp validate)
41 reader_as_line_info = reader as IXmlLineInfo;
42 this.validate = validate;
45 public bool HasLineInfo ()
47 return reader_as_line_info != null ? reader_as_line_info.HasLineInfo () : false;
50 public int LineNumber {
51 get { return reader_as_line_info != null ? reader_as_line_info.LineNumber : 0; }
54 public int LinePosition {
55 get { return reader_as_line_info != null ? reader_as_line_info.LinePosition : 0; }
58 public void AttachPlaceholder ()
61 nextPlaceHolder = XmlNodeType.Element;
64 public void DetachPlaceholder ()
67 placeHolder = XmlNodeType.None;
70 private void AddAttribute ()
72 if (attributes.Length == attributeCount) {
73 AttributeInfo [] newArr =
74 new AttributeInfo [attributeCount * 2];
75 Array.Copy (attributes, newArr, attributeCount);
77 AttributeInfo ai = attributes [attributeCount];
79 ai = new AttributeInfo ();
80 attributes [attributeCount] = ai;
82 ai.LocalName = reader.LocalName;
83 ai.NamespaceURI = reader.NamespaceURI;
87 private SimpleRule FindAttributeRule (string ns, SimpleMode mode)
89 SimpleRule any = null;
90 foreach (SimpleRule rule in mode.AttributeRules) {
91 if (!rule.MatchNS (ns))
99 throw new NvdlValidationException ("NVDL internal error: should not happen. No matching rule was found.", reader as IXmlLineInfo);
104 public override bool Read ()
106 // This class itself never proceeds, just checks if
107 // the reader is placed on EOF.
114 if (nextPlaceHolder != XmlNodeType.None) {
115 placeHolder = nextPlaceHolder;
116 nextPlaceHolder = XmlNodeType.None;
120 if (placeHolder != XmlNodeType.None)
121 // Inside placeHolder, ignore all contents.
122 // The source XmlReader should proceed
123 // regardless of this filtered reader.
126 if (!reader.MoveToFirstAttribute ())
129 // Attribute rule application
130 attributeValidators.Clear ();
132 if (reader.NamespaceURI == "http://www.w3.org/2000/xmlns/")
134 // FIXME: could be more efficient
135 SimpleRule rule = FindAttributeRule (
137 validate.CreatedMode);
138 foreach (SimpleAction a in rule.Actions) {
139 SimpleResultAction ra =
140 a as SimpleResultAction;
142 ra.ResultType == NvdlResultType.Attach)
146 attributeValidators [reader.NamespaceURI] = a;
148 } while (reader.MoveToNextAttribute ());
149 reader.MoveToElement ();
151 if (attributeValidators.Count > 0) {
152 foreach (string ns in attributeValidators.Keys) {
153 ((SimpleValidate) attributeValidators [
154 ns]).ValidateAttributes (reader, ns);
161 public override int AttributeCount {
163 switch (placeHolder) {
164 case XmlNodeType.Element:
165 case XmlNodeType.Attribute: // ns or localName attribute on placeHolder element
166 case XmlNodeType.Text: // attribute value of ns or localName attribute on placeHolder element
168 case XmlNodeType.EndElement:
171 return attributeCount;
176 public override string BaseURI {
177 get { return reader.BaseURI; }
180 public override int Depth {
182 if (placeHolderDepth == 0)
184 int basis = reader.Depth + 1;
185 switch (placeHolder) {
186 case XmlNodeType.Text:
188 case XmlNodeType.Attribute:
196 public override bool EOF {
197 get { return reader.EOF && placeHolder != XmlNodeType.None; }
200 public override bool HasValue {
202 switch (placeHolder) {
203 case XmlNodeType.Attribute:
204 case XmlNodeType.Text:
206 case XmlNodeType.Element:
207 case XmlNodeType.EndElement:
210 return reader.HasValue;
215 public override bool IsDefault {
217 return placeHolder == XmlNodeType.None &&
222 public override bool IsEmptyElement {
224 return placeHolder != XmlNodeType.None ||
225 reader.IsEmptyElement;
229 public override string LocalName {
231 switch (placeHolder) {
232 case XmlNodeType.Element:
233 case XmlNodeType.EndElement:
234 return "placeholder";
235 case XmlNodeType.Attribute:
236 return placeHolderLocalNameAttr ?
238 case XmlNodeType.Text:
241 return reader.LocalName;
246 public override string Name {
248 switch (placeHolder) {
249 case XmlNodeType.Element:
250 case XmlNodeType.EndElement:
251 return "placeholder";
252 case XmlNodeType.Attribute:
253 return placeHolderLocalNameAttr ?
255 case XmlNodeType.Text:
263 public override string NamespaceURI {
265 switch (placeHolder) {
266 case XmlNodeType.Element:
267 case XmlNodeType.EndElement:
268 return Nvdl.InstanceNamespace;
269 case XmlNodeType.Attribute:
271 case XmlNodeType.Text:
274 return reader.NamespaceURI;
279 public override XmlNameTable NameTable {
280 get { return reader.NameTable; }
283 public override XmlNodeType NodeType {
285 return placeHolder != XmlNodeType.None ?
286 placeHolder : reader.NodeType;
290 public override string Prefix {
292 return placeHolder != XmlNodeType.None ?
293 String.Empty : reader.Name;
297 public override char QuoteChar {
298 get { return reader.QuoteChar; }
301 public override ReadState ReadState {
303 return initial ? ReadState.Initial :
304 placeHolder != XmlNodeType.None &&
305 reader.ReadState != ReadState.Error ?
306 ReadState.Interactive :
311 public override string Value {
313 switch (placeHolder) {
314 case XmlNodeType.Element:
315 case XmlNodeType.EndElement:
317 case XmlNodeType.Attribute:
318 case XmlNodeType.Text:
319 return placeHolderLocalNameAttr ?
328 // FIXME: xml:lang might have been filtered
329 public override string XmlLang {
330 get { return reader.XmlLang; }
333 // FIXME: xml:space might have been filtered
334 public override XmlSpace XmlSpace {
335 get { return reader.XmlSpace; }
338 public override string this [int i] {
339 get { return GetAttribute (i); }
342 public override string this [string name] {
343 get { return GetAttribute (name); }
346 public override string this [string localName, string ns] {
347 get { return GetAttribute (localName, ns); }
350 public override string GetAttribute (int i)
352 if (placeHolder == XmlNodeType.Element)
353 return placeHolderLocalNameAttr ?
354 reader.LocalName : reader.NamespaceURI;
356 return reader.GetAttribute (
357 attributes [i].LocalName,
358 attributes [i].NamespaceURI);
361 public override string GetAttribute (string name)
363 if (placeHolder == XmlNodeType.Element) {
366 return reader.LocalName;
368 return reader.NamespaceURI;
373 return reader.GetAttribute (name);
376 public override string GetAttribute (string localName, string ns)
378 if (placeHolder == XmlNodeType.Element) {
379 if (ns != String.Empty)
381 return GetAttribute (localName);
383 return reader.GetAttribute (localName, ns);
386 public override void ResolveEntity ()
388 if (placeHolder != XmlNodeType.None)
389 throw new XmlException ("Current node is not an EntityReference.");
390 reader.ResolveEntity ();
393 public override void Close ()
398 public override string LookupNamespace (string prefix)
400 // For placeHolder element, we treat them as to have
401 // empty prefix. So we have to handle empty prefix as if
402 // it was mapped to the namespace.
403 if (placeHolder != XmlNodeType.None && prefix == String.Empty)
404 return Nvdl.InstanceNamespace;
405 return reader.LookupNamespace (prefix);
408 public override bool MoveToElement ()
410 switch (placeHolder) {
411 case XmlNodeType.Element:
412 case XmlNodeType.EndElement:
414 case XmlNodeType.Attribute:
415 case XmlNodeType.Text:
416 placeHolder = XmlNodeType.Element;
417 placeHolderLocalNameAttr = false;
420 return reader.MoveToElement ();
424 public override bool MoveToFirstAttribute ()
426 switch (placeHolder) {
427 case XmlNodeType.Element:
428 placeHolder = XmlNodeType.Attribute;
429 placeHolderLocalNameAttr = true;
431 case XmlNodeType.EndElement:
433 case XmlNodeType.Attribute:
434 case XmlNodeType.Text:
435 placeHolder = XmlNodeType.Attribute;
436 placeHolderLocalNameAttr = true;
439 if (attributeCount == 0)
441 return reader.MoveToAttribute (
442 attributes [0].LocalName,
443 attributes [0].NamespaceURI);
447 public override bool MoveToNextAttribute ()
449 switch (placeHolder) {
450 case XmlNodeType.Element:
451 case XmlNodeType.EndElement:
453 case XmlNodeType.Attribute:
454 case XmlNodeType.Text:
455 if (!placeHolderLocalNameAttr)
457 placeHolderLocalNameAttr = false;
458 placeHolder = XmlNodeType.Attribute;
461 if (reader.NodeType == XmlNodeType.Element)
463 for (int i = 0; i < attributeCount - 1; i++) {
464 if (attributes [i].LocalName != reader.LocalName ||
465 attributes [i].NamespaceURI != reader.NamespaceURI)
467 reader.MoveToAttribute (
468 attributes [i + 1].LocalName,
469 attributes [i + 1].NamespaceURI);
476 public override bool ReadAttributeValue ()
478 switch (placeHolder) {
479 case XmlNodeType.Element:
480 case XmlNodeType.EndElement:
481 case XmlNodeType.Text:
483 case XmlNodeType.Attribute:
484 placeHolder = XmlNodeType.Text;
487 return reader.ReadAttributeValue ();
491 public override void MoveToAttribute (int i)
493 switch (placeHolder) {
494 case XmlNodeType.EndElement:
495 throw new IndexOutOfRangeException ();
496 case XmlNodeType.Element:
497 case XmlNodeType.Attribute:
498 case XmlNodeType.Text:
501 placeHolderLocalNameAttr = true;
504 placeHolderLocalNameAttr = false;
507 throw new IndexOutOfRangeException ();
509 if (i < 0 || attributeCount <= i)
510 throw new IndexOutOfRangeException ();
511 reader.MoveToAttribute (
512 attributes [i].LocalName,
513 attributes [i].NamespaceURI);
518 public override bool MoveToAttribute (string qname)
520 int index = qname.IndexOf (':');
522 return MoveToAttribute (qname, String.Empty);
523 return MoveToAttribute (qname.Substring (index + 1),
524 LookupNamespace (qname.Substring (0, index)));
527 public override bool MoveToAttribute (string localName, string ns)
529 switch (placeHolder) {
530 case XmlNodeType.EndElement:
532 case XmlNodeType.Element:
533 case XmlNodeType.Attribute:
534 case XmlNodeType.Text:
535 if (ns != String.Empty)
548 for (int i = 0; i < attributeCount; i++) {
549 if (attributes [i].LocalName != localName ||
550 attributes [i].NamespaceURI != ns)
552 return reader.MoveToAttribute (localName, ns);