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 ()
417 switch (reader.ReadState) {
418 case ReadState.Closed:
419 case ReadState.Error:
420 case ReadState.EndOfFile:
426 if (elementStack.Count == 0)
427 // it reached to the end of document element,
428 // so reset to non-validating state.
429 currentAutomata = null;
432 bool b = !reader.EOF;
433 if (shouldResetCurrentTextValue) {
434 currentTextValue = null;
435 shouldResetCurrentTextValue = false;
441 if (elementStack.Count != 0)
442 throw new InvalidOperationException ("Unexpected end of XmlReader.");
446 return ProcessContent ();
449 bool ProcessContent ()
451 switch (reader.NodeType) {
452 case XmlNodeType.XmlDeclaration:
454 if (GetAttribute ("standalone") == "yes")
458 case XmlNodeType.DocumentType:
462 case XmlNodeType.Element:
463 if (constructingTextValue != null) {
464 currentTextValue = constructingTextValue;
465 constructingTextValue = null;
467 ValidateWhitespaceNode ();
470 ProcessStartElement ();
473 case XmlNodeType.EndElement:
474 if (constructingTextValue != null) {
475 currentTextValue = constructingTextValue;
476 constructingTextValue = null;
479 ProcessEndElement ();
482 case XmlNodeType.CDATA:
483 isSignificantWhitespace = isWhitespace = false;
488 if (currentTextValue != null) {
489 currentTextValue = constructingTextValue;
490 constructingTextValue = null;
494 case XmlNodeType.SignificantWhitespace:
496 isSignificantWhitespace = true;
497 isWhitespace = false;
498 goto case XmlNodeType.DocumentFragment;
499 case XmlNodeType.Text:
500 isWhitespace = isSignificantWhitespace = false;
502 goto case XmlNodeType.DocumentFragment;
503 case XmlNodeType.DocumentFragment:
504 // it should not happen, but in case if
505 // XmlReader really returns it, just ignore.
506 if (reader.NodeType == XmlNodeType.DocumentFragment)
512 case XmlNodeType.Whitespace:
513 if (!isText && !isSignificantWhitespace)
515 goto case XmlNodeType.DocumentFragment;
518 ValidateWhitespaceNode ();
519 currentTextValue = constructingTextValue;
520 constructingTextValue = null;
524 private void FillAttributes ()
526 if (reader.MoveToFirstAttribute ()) {
528 AttributeSlot slot = GetAttributeSlot ();
529 slot.Name = reader.Name;
530 slot.LocalName = reader.LocalName;
531 slot.Prefix = reader.Prefix;
532 slot.NS = reader.NamespaceURI;
533 slot.Value = reader.Value;
534 } while (reader.MoveToNextAttribute ());
535 reader.MoveToElement ();
539 private void ValidateText ()
541 if (currentAutomata == null)
544 DTDElementDeclaration elem = null;
545 if (elementStack.Count > 0)
546 elem = dtd.ElementDecls [elementStack.Peek () as string];
547 // Here element should have been already validated, so
548 // if no matching declaration is found, simply ignore.
549 if (elem != null && !elem.IsMixedContent && !elem.IsAny && !isWhitespace) {
550 HandleError (String.Format ("Current element {0} does not allow character data content.", elementStack.Peek () as string),
551 XmlSeverityType.Error);
552 currentAutomata = previousAutomata;
556 private void ValidateWhitespaceNode ()
558 // VC Standalone Document Declaration (2.9)
559 if (this.isStandalone && DTD != null && elementStack.Count > 0) {
560 DTDElementDeclaration elem = DTD.ElementDecls [elementStack.Peek () as string];
561 if (elem != null && !elem.IsInternalSubset && !elem.IsMixedContent && !elem.IsAny && !elem.IsEmpty)
562 HandleError ("In a standalone document, whitespace cannot appear in an element which is declared to contain only element children.", XmlSeverityType.Error);
566 private void HandleError (string message, XmlSeverityType severity)
568 if (validatingReader != null &&
569 validatingReader.ValidationType == ValidationType.None)
572 IXmlLineInfo info = this as IXmlLineInfo;
573 bool hasLine = info.HasLineInfo ();
574 XmlSchemaException ex = new XmlSchemaException (
576 hasLine ? info.LineNumber : 0,
577 hasLine ? info.LinePosition : 0,
581 HandleError (ex, severity);
584 private void HandleError (XmlSchemaException ex, XmlSeverityType severity)
586 if (validatingReader != null &&
587 validatingReader.ValidationType == ValidationType.None)
590 if (validatingReader != null)
591 this.validatingReader.OnValidationEvent (this,
592 new ValidationEventArgs (ex, ex.Message, severity));
593 else if (severity == XmlSeverityType.Error)
597 private void ValidateAttributes (DTDAttListDeclaration decl, bool validate)
599 DtdValidateAttributes (decl, validate);
601 for (int i = 0; i < attributeCount; i++) {
602 AttributeSlot slot = attributes [i];
603 if (slot.Name == "xmlns" || slot.Prefix == "xmlns")
605 slot.Prefix == "xmlns" ? slot.LocalName : String.Empty,
609 for (int i = 0; i < attributeCount; i++) {
610 AttributeSlot slot = attributes [i];
611 if (slot.Name == "xmlns")
612 slot.NS = XmlNamespaceManager.XmlnsXmlns;
613 else if (slot.Prefix.Length > 0)
614 slot.NS = LookupNamespace (slot.Prefix);
616 slot.NS = String.Empty;
620 AttributeSlot GetAttributeSlot ()
622 if (attributeCount == attributes.Length) {
623 AttributeSlot [] tmp = new AttributeSlot [attributeCount << 1];
624 Array.Copy (attributes, tmp, attributeCount);
627 if (attributes [attributeCount] == null)
628 attributes [attributeCount] = new AttributeSlot ();
629 AttributeSlot slot = attributes [attributeCount];
635 private void DtdValidateAttributes (DTDAttListDeclaration decl, bool validate)
637 while (reader.MoveToNextAttribute ()) {
638 string attrName = reader.Name;
639 AttributeSlot slot = GetAttributeSlot ();
640 slot.Name = reader.Name;
641 slot.LocalName = reader.LocalName;
642 slot.Prefix = reader.Prefix;
643 XmlReader targetReader = reader;
644 string attrValue = String.Empty;
645 // For attribute node, it always resolves
646 // entity references on attributes.
647 while (attributeValueEntityStack.Count >= 0) {
648 if (!targetReader.ReadAttributeValue ()) {
649 if (attributeValueEntityStack.Count > 0) {
650 targetReader = attributeValueEntityStack.Pop () as XmlReader;
655 switch (targetReader.NodeType) {
656 case XmlNodeType.EntityReference:
657 DTDEntityDeclaration edecl = DTD.EntityDecls [targetReader.Name];
659 HandleError (String.Format ("Referenced entity {0} is not declared.", targetReader.Name),
660 XmlSeverityType.Error);
662 XmlTextReader etr = new XmlTextReader (edecl.EntityValue, XmlNodeType.Attribute, ParserContext);
663 attributeValueEntityStack.Push (targetReader);
668 case XmlNodeType.EndEntity:
671 attrValue += targetReader.Value;
676 reader.MoveToElement ();
677 reader.MoveToAttribute (attrName);
678 slot.Value = FilterNormalization (attrName, attrValue);
685 DTDAttributeDefinition def = decl [reader.Name];
687 HandleError (String.Format ("Attribute {0} is not declared.", reader.Name),
688 XmlSeverityType.Error);
692 // check enumeration constraint
693 if (def.EnumeratedAttributeDeclaration.Count > 0)
694 if (!def.EnumeratedAttributeDeclaration.Contains (slot.Value))
695 HandleError (String.Format ("Attribute enumeration constraint error in attribute {0}, value {1}.",
696 reader.Name, attrValue), XmlSeverityType.Error);
697 if (def.EnumeratedNotations.Count > 0)
698 if (!def.EnumeratedNotations.Contains (
700 HandleError (String.Format ("Attribute notation enumeration constraint error in attribute {0}, value {1}.",
701 reader.Name, attrValue), XmlSeverityType.Error);
703 // check type constraint
704 string normalized = null;
705 if (def.Datatype != null)
706 normalized = FilterNormalization (def.Name, attrValue);
708 normalized = attrValue;
709 DTDEntityDeclaration ent;
711 // Common process to get list value
712 string [] list = null;
713 switch (def.Datatype.TokenizedType) {
714 case XmlTokenizedType.IDREFS:
715 case XmlTokenizedType.ENTITIES:
716 case XmlTokenizedType.NMTOKENS:
718 list = def.Datatype.ParseValue (normalized, NameTable, null) as string [];
719 } catch (Exception) {
720 HandleError ("Attribute value is invalid against its data type.", XmlSeverityType.Error);
721 list = new string [0];
726 def.Datatype.ParseValue (normalized, NameTable, null);
727 } catch (Exception ex) {
728 HandleError (String.Format ("Attribute value is invalid against its data type '{0}'. {1}", def.Datatype, ex.Message), XmlSeverityType.Error);
733 switch (def.Datatype.TokenizedType) {
734 case XmlTokenizedType.ID:
735 if (this.idList.Contains (normalized)) {
736 HandleError (String.Format ("Node with ID {0} was already appeared.", attrValue),
737 XmlSeverityType.Error);
739 if (missingIDReferences.Contains (normalized))
740 missingIDReferences.Remove (normalized);
741 idList.Add (normalized);
744 case XmlTokenizedType.IDREF:
745 if (!idList.Contains (normalized))
746 missingIDReferences.Add (normalized);
748 case XmlTokenizedType.IDREFS:
749 for (int i = 0; i < list.Length; i++) {
750 string idref = list [i];
751 if (!idList.Contains (idref))
752 missingIDReferences.Add (idref);
755 case XmlTokenizedType.ENTITY:
756 ent = dtd.EntityDecls [normalized];
758 HandleError ("Reference to undeclared entity was found in attribute: " + reader.Name + ".", XmlSeverityType.Error);
759 else if (ent.NotationName == null)
760 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);
762 case XmlTokenizedType.ENTITIES:
763 for (int i = 0; i < list.Length; i++) {
764 string entref = list [i];
765 ent = dtd.EntityDecls [FilterNormalization (reader.Name, entref)];
767 HandleError ("Reference to undeclared entity was found in attribute: " + reader.Name + ".", XmlSeverityType.Error);
768 else if (ent.NotationName == null)
769 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);
772 // case XmlTokenizedType.NMTOKEN: nothing to do
773 // case XmlTokenizedType.NMTOKENS: nothing to do
776 if (isStandalone && !def.IsInternalSubset &&
777 attrValue != normalized)
778 HandleError ("In standalone document, attribute value characters must not be checked against external definition.", XmlSeverityType.Error);
780 if (def.OccurenceType ==
781 DTDAttributeOccurenceType.Fixed &&
782 attrValue != def.DefaultValue)
783 HandleError (String.Format ("Fixed attribute {0} in element {1} has invalid value {2}.",
784 def.Name, decl.Name, attrValue),
785 XmlSeverityType.Error);
789 VerifyDeclaredAttributes (decl);
798 IHasXmlParserContext ctx = reader as IHasXmlParserContext;
800 dtd = ctx.ParserContext.Dtd;
802 XmlTextReaderImpl xmlTextReader = new XmlTextReaderImpl ("", XmlNodeType.Document, null);
803 xmlTextReader.XmlResolver = resolver;
804 xmlTextReader.GenerateDTDObjectModel (reader.Name,
805 reader ["PUBLIC"], reader ["SYSTEM"], reader.Value);
806 dtd = xmlTextReader.DTD;
808 currentAutomata = dtd.RootAutomata;
810 // Validity Constraint Check.
811 for (int i = 0; i < DTD.Errors.Length; i++)
812 HandleError (DTD.Errors [i].Message, XmlSeverityType.Error);
814 // NData target exists.
815 foreach (DTDEntityDeclaration ent in dtd.EntityDecls.Values)
816 if (ent.NotationName != null && dtd.NotationDecls [ent.NotationName] == null)
817 this.HandleError ("Target notation was not found for NData in entity declaration " + ent.Name + ".",
818 XmlSeverityType.Error);
819 // NOTATION exists for attribute default values
820 foreach (DTDAttListDeclaration attListIter in dtd.AttListDecls.Values) {
821 foreach (DTDAttributeDefinition def in attListIter.Definitions) {
822 if (def.Datatype.TokenizedType != XmlTokenizedType.NOTATION)
824 foreach (string notation in def.EnumeratedNotations)
825 if (dtd.NotationDecls [notation] == null)
826 this.HandleError ("Target notation was not found for NOTATION typed attribute default " + def.Name + ".",
827 XmlSeverityType.Error);
832 void ProcessStartElement ()
835 popScope = reader.IsEmptyElement;
836 elementStack.Push (reader.Name);
838 currentElement = Name;
840 // If no DTD, skip validation.
841 if (currentAutomata == null) {
842 ValidateAttributes (null, false);
843 if (reader.IsEmptyElement)
844 ProcessEndElement ();
850 previousAutomata = currentAutomata;
851 currentAutomata = currentAutomata.TryStartElement (reader.Name);
852 if (currentAutomata == DTD.Invalid) {
853 HandleError (String.Format ("Invalid start element found: {0}", reader.Name),
854 XmlSeverityType.Error);
855 currentAutomata = previousAutomata;
858 DTDElementDeclaration elem =
859 DTD.ElementDecls [reader.Name];
861 HandleError (String.Format ("Element {0} is not declared.", reader.Name),
862 XmlSeverityType.Error);
863 currentAutomata = previousAutomata;
866 automataStack.Push (currentAutomata);
867 if (elem != null) // i.e. not invalid
868 currentAutomata = elem.ContentModel.GetAutomata ();
870 DTDAttListDeclaration attList = dtd.AttListDecls [currentElement];
871 if (attList != null) {
873 ValidateAttributes (attList, true);
874 currentAttribute = -1;
876 if (reader.HasAttributes) {
877 HandleError (String.Format (
878 "Attributes are found on element {0} while it has no attribute definitions.", currentElement),
879 XmlSeverityType.Error);
881 // SetupValidityIgnorantAttributes ();
882 ValidateAttributes (null, false);
884 // If it is empty element then directly check end element.
885 if (reader.IsEmptyElement)
886 ProcessEndElement ();
889 void ProcessEndElement ()
894 // If no schema specification, then skip validation.
895 if (currentAutomata == null)
899 DTDElementDeclaration elem =
900 DTD.ElementDecls [reader.Name];
902 HandleError (String.Format ("Element {0} is not declared.", reader.Name),
903 XmlSeverityType.Error);
906 previousAutomata = currentAutomata;
907 // Don't let currentAutomata
908 DTDAutomata tmpAutomata = currentAutomata.TryEndElement ();
909 if (tmpAutomata == DTD.Invalid) {
910 HandleError (String.Format ("Invalid end element found: {0}", reader.Name),
911 XmlSeverityType.Error);
912 currentAutomata = previousAutomata;
915 currentAutomata = automataStack.Pop () as DTDAutomata;
918 void VerifyDeclaredAttributes (DTDAttListDeclaration decl)
920 // Check if all required attributes exist, and/or
921 // if there is default values, then add them.
922 for (int i = 0; i < decl.Definitions.Count; i++) {
923 DTDAttributeDefinition def = (DTDAttributeDefinition) decl.Definitions [i];
925 for (int a = 0; a < attributeCount; a++) {
926 if (attributes [a].Name == def.Name) {
934 if (def.OccurenceType == DTDAttributeOccurenceType.Required) {
935 HandleError (String.Format ("Required attribute {0} in element {1} not found .",
936 def.Name, decl.Name),
937 XmlSeverityType.Error);
941 else if (def.DefaultValue == null)
944 if (this.isStandalone && !def.IsInternalSubset)
945 HandleError ("In standalone document, external default value definition must not be applied.", XmlSeverityType.Error);
947 switch (validatingReader.ValidationType) {
948 case ValidationType.Auto:
949 if (validatingReader.Schemas.Count == 0)
950 goto case ValidationType.DTD;
952 case ValidationType.DTD:
953 case ValidationType.None:
954 // Other than them, ignore DTD defaults.
955 AttributeSlot slot = GetAttributeSlot ();
956 slot.Name = def.Name;
957 int colonAt = def.Name.IndexOf (':');
958 slot.LocalName = colonAt < 0 ? def.Name :
959 def.Name.Substring (colonAt + 1);
960 string prefix = colonAt < 0 ?
962 def.Name.Substring (0, colonAt);
963 slot.Prefix = prefix;
964 slot.Value = def.DefaultValue;
965 slot.IsDefault = true;
976 override bool ReadAttributeValue ()
978 if (consumedAttribute)
980 if (NodeType == XmlNodeType.Attribute &&
981 EntityHandling == EntityHandling.ExpandEntities) {
982 consumedAttribute = true;
985 else if (IsDefault) {
986 consumedAttribute = true;
990 return reader.ReadAttributeValue ();
998 override void ResolveEntity ()
1000 reader.ResolveEntity ();
1003 public override int AttributeCount {
1005 if (currentTextValue != null)
1008 return attributeCount;
1012 public override string BaseURI {
1014 return reader.BaseURI;
1018 public override bool CanResolveEntity {
1019 get { return true; }
1022 public override int Depth {
1024 int baseNum = reader.Depth;
1025 if (currentTextValue != null && reader.NodeType == XmlNodeType.EndElement)
1028 return IsDefault ? baseNum + 1 : baseNum;
1032 public override bool EOF {
1033 get { return reader.EOF; }
1041 override bool HasValue {
1043 return currentAttribute >= 0 ? true :
1044 currentTextValue != null ? true :
1049 public override bool IsDefault {
1051 if (currentTextValue != null)
1053 if (currentAttribute == -1)
1055 return attributes [currentAttribute].IsDefault;
1059 public override bool IsEmptyElement {
1061 if (currentTextValue != null)
1063 return reader.IsEmptyElement;
1067 public override string this [int i] {
1068 get { return GetAttribute (i); }
1071 public override string this [string name] {
1072 get { return GetAttribute (name); }
1075 public override string this [string name, string ns] {
1076 get { return GetAttribute (name, ns); }
1079 public int LineNumber {
1081 IXmlLineInfo info = reader as IXmlLineInfo;
1082 return (info != null) ? info.LineNumber : 0;
1086 public int LinePosition {
1088 IXmlLineInfo info = reader as IXmlLineInfo;
1089 return (info != null) ? info.LinePosition : 0;
1093 public override string LocalName {
1095 if (currentTextValue != null || consumedAttribute)
1096 return String.Empty;
1097 else if (NodeType == XmlNodeType.Attribute)
1098 return attributes [currentAttribute].LocalName;
1100 return reader.LocalName;
1104 public override string Name {
1106 if (currentTextValue != null || consumedAttribute)
1107 return String.Empty;
1108 else if (NodeType == XmlNodeType.Attribute)
1109 return attributes [currentAttribute].Name;
1115 public override string NamespaceURI {
1117 if (currentTextValue != null || consumedAttribute)
1118 return String.Empty;
1120 case XmlNodeType.Attribute:
1121 return (string) attributes [currentAttribute].NS;
1122 case XmlNodeType.Element:
1123 case XmlNodeType.EndElement:
1124 return nsmgr.LookupNamespace (Prefix);
1126 return String.Empty;
1131 public override XmlNameTable NameTable {
1132 get { return reader.NameTable; }
1135 public override XmlNodeType NodeType {
1137 if (currentTextValue != null)
1138 return isSignificantWhitespace ? XmlNodeType.SignificantWhitespace :
1139 isWhitespace ? XmlNodeType.Whitespace :
1142 // If consumedAttribute is true, then entities must be resolved.
1143 return consumedAttribute ? XmlNodeType.Text :
1144 IsDefault ? XmlNodeType.Attribute :
1149 public XmlParserContext ParserContext {
1150 get { return XmlSchemaUtil.GetParserContext (reader); }
1153 public override string Prefix {
1155 if (currentTextValue != null || consumedAttribute)
1156 return String.Empty;
1157 else if (NodeType == XmlNodeType.Attribute)
1158 return attributes [currentAttribute].Prefix;
1160 return reader.Prefix;
1164 public override char QuoteChar {
1166 // If it is not actually on an attribute, then it returns
1167 // undefined value or '"'.
1168 return reader.QuoteChar;
1172 public override ReadState ReadState {
1174 if (reader.ReadState == ReadState.EndOfFile && currentTextValue != null)
1175 return ReadState.Interactive;
1176 return reader.ReadState;
1180 public object SchemaType {
1182 if (DTD == null || currentAttribute == -1 ||
1183 currentElement == null)
1185 DTDAttListDeclaration decl =
1186 DTD.AttListDecls [currentElement];
1187 DTDAttributeDefinition def =
1188 decl != null ? decl [attributes [currentAttribute].Name] : null;
1189 return def != null ? def.Datatype : null;
1193 char [] whitespaceChars = new char [] {' '};
1194 private string FilterNormalization (string attrName, string rawValue)
1196 if (DTD == null || sourceTextReader == null ||
1197 !sourceTextReader.Normalization)
1200 DTDAttributeDefinition def =
1201 dtd.AttListDecls [currentElement].Get (attrName);
1202 valueBuilder.Append (rawValue);
1203 valueBuilder.Replace ('\r', ' ');
1204 valueBuilder.Replace ('\n', ' ');
1205 valueBuilder.Replace ('\t', ' ');
1207 if (def == null || def.Datatype.TokenizedType == XmlTokenizedType.CDATA)
1208 return valueBuilder.ToString ();
1209 for (int i=0; i < valueBuilder.Length; i++) {
1210 if (valueBuilder [i] != ' ')
1212 while (++i < valueBuilder.Length && valueBuilder [i] == ' ')
1213 valueBuilder.Remove (i, 1);
1215 return valueBuilder.ToString ().Trim (whitespaceChars);
1217 valueBuilder.Length = 0;
1221 // LAMESPEC: When source XmlTextReader.Normalize is true, then
1222 // every Attribute node is normalized. However, corresponding
1223 // Values of attribute value Text nodes are not.
1224 public override string Value {
1226 if (currentTextValue != null)
1227 return currentTextValue;
1228 // As to this property, MS.NET seems ignorant of EntityHandling...
1229 else if (NodeType == XmlNodeType.Attribute
1230 // It also covers default attribute text.
1231 || consumedAttribute)
1232 return attributes [currentAttribute].Value;
1234 return reader.Value;
1238 public override string XmlLang {
1240 string val = this ["xml:lang"];
1241 return val != null ? val : reader.XmlLang;
1245 internal XmlResolver Resolver {
1246 get { return resolver; }
1249 public XmlResolver XmlResolver {
1252 dtd.XmlResolver = value;
1257 public override XmlSpace XmlSpace {
1259 string val = this ["xml:space"];
1262 return XmlSpace.Preserve;
1264 return XmlSpace.Default;
1266 return reader.XmlSpace;