2 // DTDValidatingReader2.cs
5 // Atsushi Enomoto atsushi@ximian.com
7 // (C)2003 Atsushi Enomoto
8 // (C)2004-2006 Novell Inc.
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 DTDValidatingReader requires somewhat different ResolveEntity()
37 implementation because unlike other readers (XmlTextReaderImpl and
38 XmlNodeReaderImpl), DTDValidatingReader manages validation state
39 and it must not be held in each entity reader.
41 Say, if there are such element and entity definitions:
43 <!ELEMENT root (child)>
44 <!ELEMENT child EMPTY>
45 <!ENTITY foo "<child />">
51 When the container XmlReader encounters "&foo;", it creates another
52 XmlReader for resolved entity "<child/>". However, the generated
53 reader must not be another standalone DTDValidatingReader since
54 <child/> must be a participant of the container's validation.
56 Thus, this reader handles validation, and it holds an
57 EntityResolvingXmlReader as its validation source XmlReader.
60 IsDefault messes all around the reader, so simplify it.
61 isWhitespace/isText/blah mess the code too, so clear it as well.
66 using System.Collections;
68 using System.Collections.Generic;
73 using System.Xml.Schema;
76 using XmlTextReaderImpl = Mono.Xml2.XmlTextReader;
78 using XmlTextReaderImpl = System.Xml.XmlTextReader;
84 internal class DTDValidatingReader : XmlReader, IXmlLineInfo,
86 IXmlNamespaceResolver,
88 IHasXmlParserContext, IHasXmlSchemaInfo
90 public DTDValidatingReader (XmlReader reader)
95 internal DTDValidatingReader (XmlReader reader,
96 XmlValidatingReader validatingReader)
98 IHasXmlParserContext container = reader as IHasXmlParserContext;
99 this.reader = new EntityResolvingXmlReader (reader,
100 container != null ? container.ParserContext : null);
101 this.sourceTextReader = reader as XmlTextReader;
102 elementStack = new Stack ();
103 automataStack = new Stack ();
104 attributes = new AttributeSlot [10];
105 nsmgr = new XmlNamespaceManager (reader.NameTable);
106 this.validatingReader = validatingReader;
107 valueBuilder = new StringBuilder ();
108 idList = new ArrayList ();
109 missingIDReferences = new ArrayList ();
110 XmlTextReader xtReader = reader as XmlTextReader;
111 if (xtReader != null) {
112 resolver = xtReader.Resolver;
115 resolver = new XmlUrlResolver ();
118 // The primary xml source
119 EntityResolvingXmlReader reader;
121 // This is used to acquire "Normalization" property which
122 // could be dynamically changed.
123 XmlTextReader sourceTextReader;
125 // This field is used to get properties (such as
126 // EntityHandling) and to raise events.
127 XmlValidatingReader validatingReader;
129 // We hold DTDObjectModel for such case that the source
130 // XmlReader does not implement IHasXmlParerContext
131 // (especially for non-sys.xml.dll readers).
134 // Used to resolve entities (as expected)
135 XmlResolver resolver;
137 // mainly used to retrieve DTDElementDeclaration
138 string currentElement;
139 AttributeSlot [] attributes;
142 // Holds MoveTo*Attribute()/ReadAttributeValue() status.
143 int currentAttribute = -1;
144 bool consumedAttribute;
146 // Ancestor and current node context for each depth.
151 // Validation context.
153 DTDAutomata currentAutomata;
154 DTDAutomata previousAutomata;
156 ArrayList missingIDReferences;
158 // Holds namespace context. It must not be done in source
159 // XmlReader because default attributes could affect on it.
160 XmlNamespaceManager nsmgr;
162 // Those fields are used to store on-constructing text value.
163 // They are required to support entity-mixed text, so they
164 // are likely to be moved to EntityResolvingXmlReader.
165 string currentTextValue;
166 string constructingTextValue;
167 bool shouldResetCurrentTextValue;
168 bool isSignificantWhitespace;
173 Stack attributeValueEntityStack = new Stack ();
174 StringBuilder valueBuilder;
179 public string LocalName;
181 public string Prefix;
182 public string Value; // normalized
183 public bool IsDefault;
187 Prefix = String.Empty;
188 LocalName = String.Empty;
190 Value = String.Empty;
195 internal EntityResolvingXmlReader Source {
196 // we cannot return EntityResolvingXmlReader.source
197 // since it must check non-wellformedness error
198 // (undeclared entity in use).
199 get { return reader; }
202 public DTDObjectModel DTD {
206 public EntityHandling EntityHandling {
207 get { return reader.EntityHandling; }
208 set { reader.EntityHandling = value; }
211 public override void Close ()
216 int GetAttributeIndex (string name)
218 for (int i = 0; i < attributeCount; i++)
219 if (attributes [i].Name == name)
224 int GetAttributeIndex (string localName, string ns)
226 for (int i = 0; i < attributeCount; i++)
227 if (attributes [i].LocalName == localName &&
228 attributes [i].NS == ns)
233 // We had already done attribute validation, so can ignore name.
234 public override string GetAttribute (int i)
236 if (currentTextValue != null)
237 throw new IndexOutOfRangeException ("Specified index is out of range: " + i);
239 if (attributeCount <= i)
240 throw new IndexOutOfRangeException ("Specified index is out of range: " + i);
241 return attributes [i].Value;
244 public override string GetAttribute (string name)
246 if (currentTextValue != null)
249 int i = GetAttributeIndex (name);
250 return i < 0 ? null : attributes [i].Value;
253 public override string GetAttribute (string name, string ns)
255 if (currentTextValue != null)
258 int i = GetAttributeIndex (name, ns);
259 return i < 0 ? null : attributes [i].Value;
263 IDictionary<string, string> IXmlNamespaceResolver.GetNamespacesInScope (XmlNamespaceScope scope)
265 IXmlNamespaceResolver res = reader as IXmlNamespaceResolver;
266 return res != null ? res.GetNamespacesInScope (scope) : new Dictionary<string, string> ();
270 bool IXmlLineInfo.HasLineInfo ()
272 IXmlLineInfo ixli = reader as IXmlLineInfo;
274 return ixli.HasLineInfo ();
279 public override string LookupNamespace (string prefix)
281 string s = nsmgr.LookupNamespace (NameTable.Get (prefix));
282 return s == String.Empty ? null : s;
286 string IXmlNamespaceResolver.LookupPrefix (string ns)
288 IXmlNamespaceResolver res = reader as IXmlNamespaceResolver;
289 return res != null ? res.LookupPrefix (ns) : null;
293 public override void MoveToAttribute (int i)
295 if (currentTextValue != null)
296 throw new IndexOutOfRangeException ("The index is out of range.");
298 if (attributeCount <= i)
299 throw new IndexOutOfRangeException ("The index is out of range.");
301 if (i < reader.AttributeCount) // non-default attribute
302 reader.MoveToAttribute (i);
303 currentAttribute = i;
304 consumedAttribute = false;
308 public override bool MoveToAttribute (string name)
310 if (currentTextValue != null)
313 int i = GetAttributeIndex (name);
316 if (i < reader.AttributeCount)
317 reader.MoveToAttribute (i);
318 currentAttribute = i;
319 consumedAttribute = false;
323 public override bool MoveToAttribute (string name, string ns)
325 if (currentTextValue != null)
328 int i = GetAttributeIndex (name, ns);
331 if (i < reader.AttributeCount)
332 reader.MoveToAttribute (i);
333 currentAttribute = i;
334 consumedAttribute = false;
338 public override bool MoveToElement ()
340 if (currentTextValue != null)
343 bool b = reader.MoveToElement ();
344 if (!b && !IsDefault)
346 currentAttribute = -1;
347 consumedAttribute = false;
351 public override bool MoveToFirstAttribute ()
353 if (currentTextValue != null)
356 if (attributeCount == 0)
358 currentAttribute = 0;
359 reader.MoveToFirstAttribute ();
360 consumedAttribute = false;
364 public override bool MoveToNextAttribute ()
366 if (currentTextValue != null)
369 if (currentAttribute == -1)
370 return MoveToFirstAttribute ();
371 if (++currentAttribute == attributeCount) {
376 if (currentAttribute < reader.AttributeCount)
377 reader.MoveToAttribute (currentAttribute);
378 consumedAttribute = false;
382 public override bool Read ()
384 if (currentTextValue != null)
385 shouldResetCurrentTextValue = true;
387 if (currentAttribute >= 0)
390 currentElement = null;
391 currentAttribute = -1;
392 consumedAttribute = false;
394 isWhitespace = false;
395 isSignificantWhitespace = false;
398 bool b = ReadContent () || currentTextValue != null;
401 (Settings == null || (Settings.ValidationFlags & XmlSchemaValidationFlags.ProcessIdentityConstraints) == 0) &&
403 this.missingIDReferences.Count > 0) {
404 this.HandleError ("Missing ID reference was found: " +
405 String.Join (",", missingIDReferences.ToArray (typeof (string)) as string []),
406 XmlSeverityType.Error);
407 // Don't output the same errors so many times.
408 this.missingIDReferences.Clear ();
410 if (validatingReader != null)
411 EntityHandling = validatingReader.EntityHandling;
415 private bool ReadContent ()
422 if (elementStack.Count == 0)
423 // it reached to the end of document element,
424 // so reset to non-validating state.
425 currentAutomata = null;
428 bool b = !reader.EOF;
429 if (shouldResetCurrentTextValue) {
430 currentTextValue = null;
431 shouldResetCurrentTextValue = false;
437 if (elementStack.Count != 0)
438 throw new InvalidOperationException ("Unexpected end of XmlReader.");
442 return ProcessContent ();
445 bool ProcessContent ()
447 switch (reader.NodeType) {
448 case XmlNodeType.XmlDeclaration:
450 if (GetAttribute ("standalone") == "yes")
454 case XmlNodeType.DocumentType:
458 case XmlNodeType.Element:
459 if (constructingTextValue != null) {
460 currentTextValue = constructingTextValue;
461 constructingTextValue = null;
463 ValidateWhitespaceNode ();
466 ProcessStartElement ();
469 case XmlNodeType.EndElement:
470 if (constructingTextValue != null) {
471 currentTextValue = constructingTextValue;
472 constructingTextValue = null;
475 ProcessEndElement ();
478 case XmlNodeType.CDATA:
479 isSignificantWhitespace = isWhitespace = false;
484 if (currentTextValue != null) {
485 currentTextValue = constructingTextValue;
486 constructingTextValue = null;
490 case XmlNodeType.SignificantWhitespace:
492 isSignificantWhitespace = true;
493 isWhitespace = false;
494 goto case XmlNodeType.DocumentFragment;
495 case XmlNodeType.Text:
496 isWhitespace = isSignificantWhitespace = false;
498 goto case XmlNodeType.DocumentFragment;
499 case XmlNodeType.DocumentFragment:
500 // it should not happen, but in case if
501 // XmlReader really returns it, just ignore.
502 if (reader.NodeType == XmlNodeType.DocumentFragment)
508 case XmlNodeType.Whitespace:
509 if (!isText && !isSignificantWhitespace)
511 goto case XmlNodeType.DocumentFragment;
514 ValidateWhitespaceNode ();
515 currentTextValue = constructingTextValue;
516 constructingTextValue = null;
520 private void FillAttributes ()
522 if (reader.MoveToFirstAttribute ()) {
524 AttributeSlot slot = GetAttributeSlot ();
525 slot.Name = reader.Name;
526 slot.LocalName = reader.LocalName;
527 slot.Prefix = reader.Prefix;
528 slot.NS = reader.NamespaceURI;
529 slot.Value = reader.Value;
530 } while (reader.MoveToNextAttribute ());
531 reader.MoveToElement ();
535 private void ValidateText ()
537 if (currentAutomata == null)
540 DTDElementDeclaration elem = null;
541 if (elementStack.Count > 0)
542 elem = dtd.ElementDecls [elementStack.Peek () as string];
543 // Here element should have been already validated, so
544 // if no matching declaration is found, simply ignore.
545 if (elem != null && !elem.IsMixedContent && !elem.IsAny && !isWhitespace) {
546 HandleError (String.Format ("Current element {0} does not allow character data content.", elementStack.Peek () as string),
547 XmlSeverityType.Error);
548 currentAutomata = previousAutomata;
552 private void ValidateWhitespaceNode ()
554 // VC Standalone Document Declaration (2.9)
555 if (this.isStandalone && DTD != null && elementStack.Count > 0) {
556 DTDElementDeclaration elem = DTD.ElementDecls [elementStack.Peek () as string];
557 if (elem != null && !elem.IsInternalSubset && !elem.IsMixedContent && !elem.IsAny && !elem.IsEmpty)
558 HandleError ("In a standalone document, whitespace cannot appear in an element which is declared to contain only element children.", XmlSeverityType.Error);
562 private XmlException NotWFError (string message)
564 return new XmlException (this as IXmlLineInfo, BaseURI, message);
567 private void HandleError (string message, XmlSeverityType severity)
569 if (validatingReader != null &&
570 validatingReader.ValidationType == ValidationType.None)
573 IXmlLineInfo info = this as IXmlLineInfo;
574 bool hasLine = info.HasLineInfo ();
575 XmlSchemaException ex = new XmlSchemaException (
577 hasLine ? info.LineNumber : 0,
578 hasLine ? info.LinePosition : 0,
582 HandleError (ex, severity);
585 private void HandleError (XmlSchemaException ex, XmlSeverityType severity)
587 if (validatingReader != null &&
588 validatingReader.ValidationType == ValidationType.None)
591 if (validatingReader != null)
592 this.validatingReader.OnValidationEvent (this,
593 new ValidationEventArgs (ex, ex.Message, severity));
594 else if (severity == XmlSeverityType.Error)
598 private void ValidateAttributes (DTDAttListDeclaration decl, bool validate)
600 DtdValidateAttributes (decl, validate);
602 for (int i = 0; i < attributeCount; i++) {
603 AttributeSlot slot = attributes [i];
604 if (slot.Name == "xmlns" || slot.Prefix == "xmlns")
606 slot.Prefix == "xmlns" ? slot.LocalName : String.Empty,
610 for (int i = 0; i < attributeCount; i++) {
611 AttributeSlot slot = attributes [i];
612 if (slot.Name == "xmlns")
613 slot.NS = XmlNamespaceManager.XmlnsXmlns;
614 else if (slot.Prefix.Length > 0)
615 slot.NS = LookupNamespace (slot.Prefix);
617 slot.NS = String.Empty;
621 AttributeSlot GetAttributeSlot ()
623 if (attributeCount == attributes.Length) {
624 AttributeSlot [] tmp = new AttributeSlot [attributeCount << 1];
625 Array.Copy (attributes, tmp, attributeCount);
628 if (attributes [attributeCount] == null)
629 attributes [attributeCount] = new AttributeSlot ();
630 AttributeSlot slot = attributes [attributeCount];
636 private void DtdValidateAttributes (DTDAttListDeclaration decl, bool validate)
638 while (reader.MoveToNextAttribute ()) {
639 string attrName = reader.Name;
640 AttributeSlot slot = GetAttributeSlot ();
641 slot.Name = reader.Name;
642 slot.LocalName = reader.LocalName;
643 slot.Prefix = reader.Prefix;
644 XmlReader targetReader = reader;
645 string attrValue = String.Empty;
646 // For attribute node, it always resolves
647 // entity references on attributes.
648 while (attributeValueEntityStack.Count >= 0) {
649 if (!targetReader.ReadAttributeValue ()) {
650 if (attributeValueEntityStack.Count > 0) {
651 targetReader = attributeValueEntityStack.Pop () as XmlReader;
656 switch (targetReader.NodeType) {
657 case XmlNodeType.EntityReference:
658 DTDEntityDeclaration edecl = DTD.EntityDecls [targetReader.Name];
660 HandleError (String.Format ("Referenced entity {0} is not declared.", targetReader.Name),
661 XmlSeverityType.Error);
663 XmlTextReader etr = new XmlTextReader (edecl.EntityValue, XmlNodeType.Attribute, ParserContext);
664 attributeValueEntityStack.Push (targetReader);
669 case XmlNodeType.EndEntity:
672 attrValue += targetReader.Value;
677 reader.MoveToElement ();
678 reader.MoveToAttribute (attrName);
679 slot.Value = FilterNormalization (attrName, attrValue);
686 DTDAttributeDefinition def = decl [reader.Name];
688 HandleError (String.Format ("Attribute {0} is not declared.", reader.Name),
689 XmlSeverityType.Error);
693 // check enumeration constraint
694 if (def.EnumeratedAttributeDeclaration.Count > 0)
695 if (!def.EnumeratedAttributeDeclaration.Contains (slot.Value))
696 HandleError (String.Format ("Attribute enumeration constraint error in attribute {0}, value {1}.",
697 reader.Name, attrValue), XmlSeverityType.Error);
698 if (def.EnumeratedNotations.Count > 0)
699 if (!def.EnumeratedNotations.Contains (
701 HandleError (String.Format ("Attribute notation enumeration constraint error in attribute {0}, value {1}.",
702 reader.Name, attrValue), XmlSeverityType.Error);
704 // check type constraint
705 string normalized = null;
706 if (def.Datatype != null)
707 normalized = FilterNormalization (def.Name, attrValue);
709 normalized = attrValue;
710 DTDEntityDeclaration ent;
712 // Common process to get list value
713 string [] list = null;
714 switch (def.Datatype.TokenizedType) {
715 case XmlTokenizedType.IDREFS:
716 case XmlTokenizedType.ENTITIES:
717 case XmlTokenizedType.NMTOKENS:
719 list = def.Datatype.ParseValue (normalized, NameTable, null) as string [];
720 } catch (Exception) {
721 HandleError ("Attribute value is invalid against its data type.", XmlSeverityType.Error);
722 list = new string [0];
727 def.Datatype.ParseValue (normalized, NameTable, null);
728 } catch (Exception ex) {
729 HandleError (String.Format ("Attribute value is invalid against its data type '{0}'. {1}", def.Datatype, ex.Message), XmlSeverityType.Error);
734 switch (def.Datatype.TokenizedType) {
735 case XmlTokenizedType.ID:
736 if (this.idList.Contains (normalized)) {
737 HandleError (String.Format ("Node with ID {0} was already appeared.", attrValue),
738 XmlSeverityType.Error);
740 if (missingIDReferences.Contains (normalized))
741 missingIDReferences.Remove (normalized);
742 idList.Add (normalized);
745 case XmlTokenizedType.IDREF:
746 if (!idList.Contains (normalized))
747 missingIDReferences.Add (normalized);
749 case XmlTokenizedType.IDREFS:
750 for (int i = 0; i < list.Length; i++) {
751 string idref = list [i];
752 if (!idList.Contains (idref))
753 missingIDReferences.Add (idref);
756 case XmlTokenizedType.ENTITY:
757 ent = dtd.EntityDecls [normalized];
759 HandleError ("Reference to undeclared entity was found in attribute: " + reader.Name + ".", XmlSeverityType.Error);
760 else if (ent.NotationName == null)
761 HandleError ("The entity specified by entity type value must be an unparsed entity. The entity definition has no NDATA in attribute: " + reader.Name + ".", XmlSeverityType.Error);
763 case XmlTokenizedType.ENTITIES:
764 for (int i = 0; i < list.Length; i++) {
765 string entref = list [i];
766 ent = dtd.EntityDecls [FilterNormalization (reader.Name, entref)];
768 HandleError ("Reference to undeclared entity was found in attribute: " + reader.Name + ".", XmlSeverityType.Error);
769 else if (ent.NotationName == null)
770 HandleError ("The entity specified by ENTITIES type value must be an unparsed entity. The entity definition has no NDATA in attribute: " + reader.Name + ".", XmlSeverityType.Error);
773 // case XmlTokenizedType.NMTOKEN: nothing to do
774 // case XmlTokenizedType.NMTOKENS: nothing to do
777 if (isStandalone && !def.IsInternalSubset &&
778 attrValue != normalized)
779 HandleError ("In standalone document, attribute value characters must not be checked against external definition.", XmlSeverityType.Error);
781 if (def.OccurenceType ==
782 DTDAttributeOccurenceType.Fixed &&
783 attrValue != def.DefaultValue)
784 HandleError (String.Format ("Fixed attribute {0} in element {1} has invalid value {2}.",
785 def.Name, decl.Name, attrValue),
786 XmlSeverityType.Error);
790 VerifyDeclaredAttributes (decl);
799 IHasXmlParserContext ctx = reader as IHasXmlParserContext;
801 dtd = ctx.ParserContext.Dtd;
803 XmlTextReaderImpl xmlTextReader = new XmlTextReaderImpl ("", XmlNodeType.Document, null);
804 xmlTextReader.XmlResolver = resolver;
805 xmlTextReader.GenerateDTDObjectModel (reader.Name,
806 reader ["PUBLIC"], reader ["SYSTEM"], reader.Value);
807 dtd = xmlTextReader.DTD;
809 currentAutomata = dtd.RootAutomata;
811 // Validity Constraint Check.
812 for (int i = 0; i < DTD.Errors.Length; i++)
813 HandleError (DTD.Errors [i].Message, XmlSeverityType.Error);
815 // NData target exists.
816 foreach (DTDEntityDeclaration ent in dtd.EntityDecls.Values)
817 if (ent.NotationName != null && dtd.NotationDecls [ent.NotationName] == null)
818 this.HandleError ("Target notation was not found for NData in entity declaration " + ent.Name + ".",
819 XmlSeverityType.Error);
820 // NOTATION exists for attribute default values
821 foreach (DTDAttListDeclaration attListIter in dtd.AttListDecls.Values) {
822 foreach (DTDAttributeDefinition def in attListIter.Definitions) {
823 if (def.Datatype.TokenizedType != XmlTokenizedType.NOTATION)
825 foreach (string notation in def.EnumeratedNotations)
826 if (dtd.NotationDecls [notation] == null)
827 this.HandleError ("Target notation was not found for NOTATION typed attribute default " + def.Name + ".",
828 XmlSeverityType.Error);
833 void ProcessStartElement ()
836 popScope = reader.IsEmptyElement;
837 elementStack.Push (reader.Name);
839 currentElement = Name;
841 // If no DTD, skip validation.
842 if (currentAutomata == null) {
843 ValidateAttributes (null, false);
844 if (reader.IsEmptyElement)
845 ProcessEndElement ();
851 previousAutomata = currentAutomata;
852 currentAutomata = currentAutomata.TryStartElement (reader.Name);
853 if (currentAutomata == DTD.Invalid) {
854 HandleError (String.Format ("Invalid start element found: {0}", reader.Name),
855 XmlSeverityType.Error);
856 currentAutomata = previousAutomata;
859 DTDElementDeclaration elem =
860 DTD.ElementDecls [reader.Name];
862 HandleError (String.Format ("Element {0} is not declared.", reader.Name),
863 XmlSeverityType.Error);
864 currentAutomata = previousAutomata;
867 automataStack.Push (currentAutomata);
868 if (elem != null) // i.e. not invalid
869 currentAutomata = elem.ContentModel.GetAutomata ();
871 DTDAttListDeclaration attList = dtd.AttListDecls [currentElement];
872 if (attList != null) {
874 ValidateAttributes (attList, true);
875 currentAttribute = -1;
877 if (reader.HasAttributes) {
878 HandleError (String.Format (
879 "Attributes are found on element {0} while it has no attribute definitions.", currentElement),
880 XmlSeverityType.Error);
882 // SetupValidityIgnorantAttributes ();
883 ValidateAttributes (null, false);
885 // If it is empty element then directly check end element.
886 if (reader.IsEmptyElement)
887 ProcessEndElement ();
890 void ProcessEndElement ()
895 // If no schema specification, then skip validation.
896 if (currentAutomata == null)
900 DTDElementDeclaration elem =
901 DTD.ElementDecls [reader.Name];
903 HandleError (String.Format ("Element {0} is not declared.", reader.Name),
904 XmlSeverityType.Error);
907 previousAutomata = currentAutomata;
908 // Don't let currentAutomata
909 DTDAutomata tmpAutomata = currentAutomata.TryEndElement ();
910 if (tmpAutomata == DTD.Invalid) {
911 HandleError (String.Format ("Invalid end element found: {0}", reader.Name),
912 XmlSeverityType.Error);
913 currentAutomata = previousAutomata;
916 currentAutomata = automataStack.Pop () as DTDAutomata;
919 void VerifyDeclaredAttributes (DTDAttListDeclaration decl)
921 // Check if all required attributes exist, and/or
922 // if there is default values, then add them.
923 for (int i = 0; i < decl.Definitions.Count; i++) {
924 DTDAttributeDefinition def = (DTDAttributeDefinition) decl.Definitions [i];
926 for (int a = 0; a < attributeCount; a++) {
927 if (attributes [a].Name == def.Name) {
935 if (def.OccurenceType == DTDAttributeOccurenceType.Required) {
936 HandleError (String.Format ("Required attribute {0} in element {1} not found .",
937 def.Name, decl.Name),
938 XmlSeverityType.Error);
942 else if (def.DefaultValue == null)
945 if (this.isStandalone && !def.IsInternalSubset)
946 HandleError ("In standalone document, external default value definition must not be applied.", XmlSeverityType.Error);
948 switch (validatingReader.ValidationType) {
949 case ValidationType.Auto:
950 if (validatingReader.Schemas.Count == 0)
951 goto case ValidationType.DTD;
953 case ValidationType.DTD:
954 case ValidationType.None:
955 // Other than them, ignore DTD defaults.
956 AttributeSlot slot = GetAttributeSlot ();
957 slot.Name = def.Name;
958 int colonAt = def.Name.IndexOf (':');
959 slot.LocalName = colonAt < 0 ? def.Name :
960 def.Name.Substring (colonAt + 1);
961 string prefix = colonAt < 0 ?
963 def.Name.Substring (0, colonAt);
964 slot.Prefix = prefix;
965 slot.Value = def.DefaultValue;
966 slot.IsDefault = true;
972 public override bool ReadAttributeValue ()
974 if (consumedAttribute)
976 if (NodeType == XmlNodeType.Attribute &&
977 EntityHandling == EntityHandling.ExpandEntities) {
978 consumedAttribute = true;
981 else if (IsDefault) {
982 consumedAttribute = true;
986 return reader.ReadAttributeValue ();
989 public override void ResolveEntity ()
991 reader.ResolveEntity ();
994 public override int AttributeCount {
996 if (currentTextValue != null)
999 return attributeCount;
1003 public override string BaseURI {
1005 return reader.BaseURI;
1009 public override bool CanResolveEntity {
1010 get { return true; }
1013 public override int Depth {
1015 int baseNum = reader.Depth;
1016 if (currentTextValue != null && reader.NodeType == XmlNodeType.EndElement)
1019 return IsDefault ? baseNum + 1 : baseNum;
1023 public override bool EOF {
1024 get { return reader.EOF; }
1027 public override bool HasValue {
1029 return currentAttribute >= 0 ? true :
1030 currentTextValue != null ? true :
1035 public override bool IsDefault {
1037 if (currentTextValue != null)
1039 if (currentAttribute == -1)
1041 return attributes [currentAttribute].IsDefault;
1045 public override bool IsEmptyElement {
1047 if (currentTextValue != null)
1049 return reader.IsEmptyElement;
1053 public override string this [int i] {
1054 get { return GetAttribute (i); }
1057 public override string this [string name] {
1058 get { return GetAttribute (name); }
1061 public override string this [string name, string ns] {
1062 get { return GetAttribute (name, ns); }
1065 public int LineNumber {
1067 IXmlLineInfo info = reader as IXmlLineInfo;
1068 return (info != null) ? info.LineNumber : 0;
1072 public int LinePosition {
1074 IXmlLineInfo info = reader as IXmlLineInfo;
1075 return (info != null) ? info.LinePosition : 0;
1079 public override string LocalName {
1081 if (currentTextValue != null || consumedAttribute)
1082 return String.Empty;
1083 else if (NodeType == XmlNodeType.Attribute)
1084 return attributes [currentAttribute].LocalName;
1086 return reader.LocalName;
1090 public override string Name {
1092 if (currentTextValue != null || consumedAttribute)
1093 return String.Empty;
1094 else if (NodeType == XmlNodeType.Attribute)
1095 return attributes [currentAttribute].Name;
1101 public override string NamespaceURI {
1103 if (currentTextValue != null || consumedAttribute)
1104 return String.Empty;
1106 case XmlNodeType.Attribute:
1107 return (string) attributes [currentAttribute].NS;
1108 case XmlNodeType.Element:
1109 case XmlNodeType.EndElement:
1110 return nsmgr.LookupNamespace (Prefix);
1112 return String.Empty;
1117 public override XmlNameTable NameTable {
1118 get { return reader.NameTable; }
1121 public override XmlNodeType NodeType {
1123 if (currentTextValue != null)
1124 return isSignificantWhitespace ? XmlNodeType.SignificantWhitespace :
1125 isWhitespace ? XmlNodeType.Whitespace :
1128 // If consumedAttribute is true, then entities must be resolved.
1129 return consumedAttribute ? XmlNodeType.Text :
1130 IsDefault ? XmlNodeType.Attribute :
1135 public XmlParserContext ParserContext {
1136 get { return XmlSchemaUtil.GetParserContext (reader); }
1139 public override string Prefix {
1141 if (currentTextValue != null || consumedAttribute)
1142 return String.Empty;
1143 else if (NodeType == XmlNodeType.Attribute)
1144 return attributes [currentAttribute].Prefix;
1146 return reader.Prefix;
1150 public override char QuoteChar {
1152 // If it is not actually on an attribute, then it returns
1153 // undefined value or '"'.
1154 return reader.QuoteChar;
1158 public override ReadState ReadState {
1160 if (reader.ReadState == ReadState.EndOfFile && currentTextValue != null)
1161 return ReadState.Interactive;
1162 return reader.ReadState;
1166 public object SchemaType {
1168 if (DTD == null || currentAttribute == -1 ||
1169 currentElement == null)
1171 DTDAttListDeclaration decl =
1172 DTD.AttListDecls [currentElement];
1173 DTDAttributeDefinition def =
1174 decl != null ? decl [attributes [currentAttribute].Name] : null;
1175 return def != null ? def.Datatype : null;
1179 char [] whitespaceChars = new char [] {' '};
1180 private string FilterNormalization (string attrName, string rawValue)
1182 if (DTD == null || sourceTextReader == null ||
1183 !sourceTextReader.Normalization)
1186 DTDAttributeDefinition def =
1187 dtd.AttListDecls [currentElement].Get (attrName);
1188 valueBuilder.Append (rawValue);
1189 valueBuilder.Replace ('\r', ' ');
1190 valueBuilder.Replace ('\n', ' ');
1191 valueBuilder.Replace ('\t', ' ');
1193 if (def.Datatype.TokenizedType == XmlTokenizedType.CDATA)
1194 return valueBuilder.ToString ();
1195 for (int i=0; i < valueBuilder.Length; i++) {
1196 if (valueBuilder [i] != ' ')
1198 while (++i < valueBuilder.Length && valueBuilder [i] == ' ')
1199 valueBuilder.Remove (i, 1);
1201 return valueBuilder.ToString ().Trim (whitespaceChars);
1203 valueBuilder.Length = 0;
1207 // LAMESPEC: When source XmlTextReader.Normalize is true, then
1208 // every Attribute node is normalized. However, corresponding
1209 // Values of attribute value Text nodes are not.
1210 public override string Value {
1212 if (currentTextValue != null)
1213 return currentTextValue;
1214 // As to this property, MS.NET seems ignorant of EntityHandling...
1215 else if (NodeType == XmlNodeType.Attribute
1216 // It also covers default attribute text.
1217 || consumedAttribute)
1218 return attributes [currentAttribute].Value;
1220 return reader.Value;
1224 public override string XmlLang {
1226 string val = this ["xml:lang"];
1227 return val != null ? val : reader.XmlLang;
1231 internal XmlResolver Resolver {
1232 get { return resolver; }
1235 public XmlResolver XmlResolver {
1238 dtd.XmlResolver = value;
1243 public override XmlSpace XmlSpace {
1245 string val = this ["xml:space"];
1248 return XmlSpace.Preserve;
1250 return XmlSpace.Default;
1252 return reader.XmlSpace;