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 this.reader = new EntityResolvingXmlReader (reader);
99 this.sourceTextReader = reader as XmlTextReader;
100 elementStack = new Stack ();
101 automataStack = new Stack ();
102 attributes = new AttributeSlot [10];
103 nsmgr = new XmlNamespaceManager (reader.NameTable);
104 this.validatingReader = validatingReader;
105 valueBuilder = new StringBuilder ();
106 idList = new ArrayList ();
107 missingIDReferences = new ArrayList ();
108 XmlTextReader xtReader = reader as XmlTextReader;
109 if (xtReader != null) {
110 resolver = xtReader.Resolver;
113 resolver = new XmlUrlResolver ();
116 // The primary xml source
117 EntityResolvingXmlReader reader;
119 // This is used to acquire "Normalization" property which
120 // could be dynamically changed.
121 XmlTextReader sourceTextReader;
123 // This field is used to get properties (such as
124 // EntityHandling) and to raise events.
125 XmlValidatingReader validatingReader;
127 // We hold DTDObjectModel for such case that the source
128 // XmlReader does not implement IHasXmlParerContext
129 // (especially for non-sys.xml.dll readers).
132 // Used to resolve entities (as expected)
133 XmlResolver resolver;
135 // mainly used to retrieve DTDElementDeclaration
136 string currentElement;
137 AttributeSlot [] attributes;
140 // Holds MoveTo*Attribute()/ReadAttributeValue() status.
141 int currentAttribute = -1;
142 bool consumedAttribute;
144 // Ancestor and current node context for each depth.
149 // Validation context.
151 DTDAutomata currentAutomata;
152 DTDAutomata previousAutomata;
154 ArrayList missingIDReferences;
156 // Holds namespace context. It must not be done in source
157 // XmlReader because default attributes could affect on it.
158 XmlNamespaceManager nsmgr;
160 // Those fields are used to store on-constructing text value.
161 // They are required to support entity-mixed text, so they
162 // are likely to be moved to EntityResolvingXmlReader.
163 string currentTextValue;
164 string constructingTextValue;
165 bool shouldResetCurrentTextValue;
166 bool isSignificantWhitespace;
171 Stack attributeValueEntityStack = new Stack ();
172 StringBuilder valueBuilder;
177 public string LocalName;
179 public string Prefix;
180 public string Value; // normalized
181 public bool IsDefault;
185 Prefix = String.Empty;
186 LocalName = String.Empty;
188 Value = String.Empty;
193 internal EntityResolvingXmlReader Source {
194 // we cannot return EntityResolvingXmlReader.source
195 // since it must check non-wellformedness error
196 // (undeclared entity in use).
197 get { return reader; }
200 public DTDObjectModel DTD {
204 public EntityHandling EntityHandling {
205 get { return reader.EntityHandling; }
206 set { reader.EntityHandling = value; }
209 public override void Close ()
214 int GetAttributeIndex (string name)
216 for (int i = 0; i < attributeCount; i++)
217 if (attributes [i].Name == name)
222 int GetAttributeIndex (string localName, string ns)
224 for (int i = 0; i < attributeCount; i++)
225 if (attributes [i].LocalName == localName &&
226 attributes [i].NS == ns)
231 // We had already done attribute validation, so can ignore name.
232 public override string GetAttribute (int i)
234 if (currentTextValue != null)
235 throw new IndexOutOfRangeException ("Specified index is out of range: " + i);
237 if (attributeCount <= i)
238 throw new IndexOutOfRangeException ("Specified index is out of range: " + i);
239 return attributes [i].Value;
242 public override string GetAttribute (string name)
244 if (currentTextValue != null)
247 int i = GetAttributeIndex (name);
248 return i < 0 ? null : attributes [i].Value;
251 public override string GetAttribute (string name, string ns)
253 if (currentTextValue != null)
256 int i = GetAttributeIndex (name, ns);
257 return i < 0 ? null : attributes [i].Value;
261 IDictionary<string, string> IXmlNamespaceResolver.GetNamespacesInScope (XmlNamespaceScope scope)
263 IXmlNamespaceResolver res = reader as IXmlNamespaceResolver;
264 return res != null ? res.GetNamespacesInScope (scope) : new Dictionary<string, string> ();
268 bool IXmlLineInfo.HasLineInfo ()
270 IXmlLineInfo ixli = reader as IXmlLineInfo;
272 return ixli.HasLineInfo ();
277 public override string LookupNamespace (string prefix)
279 string s = nsmgr.LookupNamespace (NameTable.Get (prefix));
280 return s == String.Empty ? null : s;
284 string IXmlNamespaceResolver.LookupPrefix (string ns)
286 IXmlNamespaceResolver res = reader as IXmlNamespaceResolver;
287 return res != null ? res.LookupPrefix (ns) : null;
291 public override void MoveToAttribute (int i)
293 if (currentTextValue != null)
294 throw new IndexOutOfRangeException ("The index is out of range.");
296 if (attributeCount <= i)
297 throw new IndexOutOfRangeException ("The index is out of range.");
299 if (i < reader.AttributeCount) // non-default attribute
300 reader.MoveToAttribute (i);
301 currentAttribute = i;
302 consumedAttribute = false;
306 public override bool MoveToAttribute (string name)
308 if (currentTextValue != null)
311 int i = GetAttributeIndex (name);
314 if (i < reader.AttributeCount)
315 reader.MoveToAttribute (i);
316 currentAttribute = i;
317 consumedAttribute = false;
321 public override bool MoveToAttribute (string name, string ns)
323 if (currentTextValue != null)
326 int i = GetAttributeIndex (name, ns);
329 if (i < reader.AttributeCount)
330 reader.MoveToAttribute (i);
331 currentAttribute = i;
332 consumedAttribute = false;
336 public override bool MoveToElement ()
338 if (currentTextValue != null)
341 bool b = reader.MoveToElement ();
342 if (!b && !IsDefault)
344 currentAttribute = -1;
345 consumedAttribute = false;
349 public override bool MoveToFirstAttribute ()
351 if (currentTextValue != null)
354 if (attributeCount == 0)
356 currentAttribute = 0;
357 reader.MoveToFirstAttribute ();
358 consumedAttribute = false;
362 public override bool MoveToNextAttribute ()
364 if (currentTextValue != null)
367 if (currentAttribute == -1)
368 return MoveToFirstAttribute ();
369 if (++currentAttribute == attributeCount) {
374 if (currentAttribute < reader.AttributeCount)
375 reader.MoveToAttribute (currentAttribute);
376 consumedAttribute = false;
380 public override bool Read ()
382 if (currentTextValue != null)
383 shouldResetCurrentTextValue = true;
385 if (currentAttribute >= 0)
388 currentElement = null;
389 currentAttribute = -1;
390 consumedAttribute = false;
392 isWhitespace = false;
393 isSignificantWhitespace = false;
396 bool b = ReadContent () || currentTextValue != null;
399 (Settings == null || (Settings.ValidationFlags & XmlSchemaValidationFlags.ProcessIdentityConstraints) == 0) &&
401 this.missingIDReferences.Count > 0) {
402 this.HandleError ("Missing ID reference was found: " +
403 String.Join (",", missingIDReferences.ToArray (typeof (string)) as string []),
404 XmlSeverityType.Error);
405 // Don't output the same errors so many times.
406 this.missingIDReferences.Clear ();
408 if (validatingReader != null)
409 EntityHandling = validatingReader.EntityHandling;
413 private bool ReadContent ()
415 switch (reader.ReadState) {
416 case ReadState.Closed:
417 case ReadState.Error:
418 case ReadState.EndOfFile:
424 if (elementStack.Count == 0)
425 // it reached to the end of document element,
426 // so reset to non-validating state.
427 currentAutomata = null;
430 bool b = !reader.EOF;
431 if (shouldResetCurrentTextValue) {
432 currentTextValue = null;
433 shouldResetCurrentTextValue = false;
439 if (elementStack.Count != 0)
440 throw new InvalidOperationException ("Unexpected end of XmlReader.");
444 return ProcessContent ();
447 bool ProcessContent ()
449 switch (reader.NodeType) {
450 case XmlNodeType.XmlDeclaration:
452 if (GetAttribute ("standalone") == "yes")
456 case XmlNodeType.DocumentType:
460 case XmlNodeType.Element:
461 if (constructingTextValue != null) {
462 currentTextValue = constructingTextValue;
463 constructingTextValue = null;
465 ValidateWhitespaceNode ();
468 ProcessStartElement ();
471 case XmlNodeType.EndElement:
472 if (constructingTextValue != null) {
473 currentTextValue = constructingTextValue;
474 constructingTextValue = null;
477 ProcessEndElement ();
480 case XmlNodeType.CDATA:
481 isSignificantWhitespace = isWhitespace = false;
486 if (currentTextValue != null) {
487 currentTextValue = constructingTextValue;
488 constructingTextValue = null;
492 case XmlNodeType.SignificantWhitespace:
494 isSignificantWhitespace = true;
495 isWhitespace = false;
496 goto case XmlNodeType.DocumentFragment;
497 case XmlNodeType.Text:
498 isWhitespace = isSignificantWhitespace = false;
500 goto case XmlNodeType.DocumentFragment;
501 case XmlNodeType.DocumentFragment:
502 // it should not happen, but in case if
503 // XmlReader really returns it, just ignore.
504 if (reader.NodeType == XmlNodeType.DocumentFragment)
510 case XmlNodeType.Whitespace:
511 if (!isText && !isSignificantWhitespace)
513 goto case XmlNodeType.DocumentFragment;
516 ValidateWhitespaceNode ();
517 currentTextValue = constructingTextValue;
518 constructingTextValue = null;
522 private void FillAttributes ()
524 if (reader.MoveToFirstAttribute ()) {
526 AttributeSlot slot = GetAttributeSlot ();
527 slot.Name = reader.Name;
528 slot.LocalName = reader.LocalName;
529 slot.Prefix = reader.Prefix;
530 slot.NS = reader.NamespaceURI;
531 slot.Value = reader.Value;
532 } while (reader.MoveToNextAttribute ());
533 reader.MoveToElement ();
537 private void ValidateText ()
539 if (currentAutomata == null)
542 DTDElementDeclaration elem = null;
543 if (elementStack.Count > 0)
544 elem = dtd.ElementDecls [elementStack.Peek () as string];
545 // Here element should have been already validated, so
546 // if no matching declaration is found, simply ignore.
547 if (elem != null && !elem.IsMixedContent && !elem.IsAny && !isWhitespace) {
548 HandleError (String.Format ("Current element {0} does not allow character data content.", elementStack.Peek () as string),
549 XmlSeverityType.Error);
550 currentAutomata = previousAutomata;
554 private void ValidateWhitespaceNode ()
556 // VC Standalone Document Declaration (2.9)
557 if (this.isStandalone && DTD != null && elementStack.Count > 0) {
558 DTDElementDeclaration elem = DTD.ElementDecls [elementStack.Peek () as string];
559 if (elem != null && !elem.IsInternalSubset && !elem.IsMixedContent && !elem.IsAny && !elem.IsEmpty)
560 HandleError ("In a standalone document, whitespace cannot appear in an element which is declared to contain only element children.", XmlSeverityType.Error);
564 private void HandleError (string message, XmlSeverityType severity)
566 if (validatingReader != null &&
567 validatingReader.ValidationType == ValidationType.None)
570 IXmlLineInfo info = this as IXmlLineInfo;
571 bool hasLine = info.HasLineInfo ();
572 XmlSchemaException ex = new XmlSchemaException (
574 hasLine ? info.LineNumber : 0,
575 hasLine ? info.LinePosition : 0,
579 HandleError (ex, severity);
582 private void HandleError (XmlSchemaException ex, XmlSeverityType severity)
584 if (validatingReader != null &&
585 validatingReader.ValidationType == ValidationType.None)
588 if (validatingReader != null)
589 this.validatingReader.OnValidationEvent (this,
590 new ValidationEventArgs (ex, ex.Message, severity));
591 else if (severity == XmlSeverityType.Error)
595 private void ValidateAttributes (DTDAttListDeclaration decl, bool validate)
597 DtdValidateAttributes (decl, validate);
599 for (int i = 0; i < attributeCount; i++) {
600 AttributeSlot slot = attributes [i];
601 if (slot.Name == "xmlns" || slot.Prefix == "xmlns")
603 slot.Prefix == "xmlns" ? slot.LocalName : String.Empty,
607 for (int i = 0; i < attributeCount; i++) {
608 AttributeSlot slot = attributes [i];
609 if (slot.Name == "xmlns")
610 slot.NS = XmlNamespaceManager.XmlnsXmlns;
611 else if (slot.Prefix.Length > 0)
612 slot.NS = LookupNamespace (slot.Prefix);
614 slot.NS = String.Empty;
618 AttributeSlot GetAttributeSlot ()
620 if (attributeCount == attributes.Length) {
621 AttributeSlot [] tmp = new AttributeSlot [attributeCount << 1];
622 Array.Copy (attributes, tmp, attributeCount);
625 if (attributes [attributeCount] == null)
626 attributes [attributeCount] = new AttributeSlot ();
627 AttributeSlot slot = attributes [attributeCount];
633 private void DtdValidateAttributes (DTDAttListDeclaration decl, bool validate)
635 while (reader.MoveToNextAttribute ()) {
636 string attrName = reader.Name;
637 AttributeSlot slot = GetAttributeSlot ();
638 slot.Name = reader.Name;
639 slot.LocalName = reader.LocalName;
640 slot.Prefix = reader.Prefix;
641 XmlReader targetReader = reader;
642 string attrValue = String.Empty;
643 // For attribute node, it always resolves
644 // entity references on attributes.
645 while (attributeValueEntityStack.Count >= 0) {
646 if (!targetReader.ReadAttributeValue ()) {
647 if (attributeValueEntityStack.Count > 0) {
648 targetReader = attributeValueEntityStack.Pop () as XmlReader;
653 switch (targetReader.NodeType) {
654 case XmlNodeType.EntityReference:
655 DTDEntityDeclaration edecl = DTD.EntityDecls [targetReader.Name];
657 HandleError (String.Format ("Referenced entity {0} is not declared.", targetReader.Name),
658 XmlSeverityType.Error);
660 XmlTextReader etr = new XmlTextReader (edecl.EntityValue, XmlNodeType.Attribute, ParserContext);
661 attributeValueEntityStack.Push (targetReader);
666 case XmlNodeType.EndEntity:
669 attrValue += targetReader.Value;
674 reader.MoveToElement ();
675 reader.MoveToAttribute (attrName);
676 slot.Value = FilterNormalization (attrName, attrValue);
683 DTDAttributeDefinition def = decl [reader.Name];
685 HandleError (String.Format ("Attribute {0} is not declared.", reader.Name),
686 XmlSeverityType.Error);
690 // check enumeration constraint
691 if (def.EnumeratedAttributeDeclaration.Count > 0)
692 if (!def.EnumeratedAttributeDeclaration.Contains (slot.Value))
693 HandleError (String.Format ("Attribute enumeration constraint error in attribute {0}, value {1}.",
694 reader.Name, attrValue), XmlSeverityType.Error);
695 if (def.EnumeratedNotations.Count > 0)
696 if (!def.EnumeratedNotations.Contains (
698 HandleError (String.Format ("Attribute notation enumeration constraint error in attribute {0}, value {1}.",
699 reader.Name, attrValue), XmlSeverityType.Error);
701 // check type constraint
702 string normalized = null;
703 if (def.Datatype != null)
704 normalized = FilterNormalization (def.Name, attrValue);
706 normalized = attrValue;
707 DTDEntityDeclaration ent;
709 // Common process to get list value
710 string [] list = null;
711 switch (def.Datatype.TokenizedType) {
712 case XmlTokenizedType.IDREFS:
713 case XmlTokenizedType.ENTITIES:
714 case XmlTokenizedType.NMTOKENS:
716 list = def.Datatype.ParseValue (normalized, NameTable, null) as string [];
717 } catch (Exception) {
718 HandleError ("Attribute value is invalid against its data type.", XmlSeverityType.Error);
719 list = new string [0];
724 def.Datatype.ParseValue (normalized, NameTable, null);
725 } catch (Exception ex) {
726 HandleError (String.Format ("Attribute value is invalid against its data type '{0}'. {1}", def.Datatype, ex.Message), XmlSeverityType.Error);
731 switch (def.Datatype.TokenizedType) {
732 case XmlTokenizedType.ID:
733 if (this.idList.Contains (normalized)) {
734 HandleError (String.Format ("Node with ID {0} was already appeared.", attrValue),
735 XmlSeverityType.Error);
737 if (missingIDReferences.Contains (normalized))
738 missingIDReferences.Remove (normalized);
739 idList.Add (normalized);
742 case XmlTokenizedType.IDREF:
743 if (!idList.Contains (normalized))
744 missingIDReferences.Add (normalized);
746 case XmlTokenizedType.IDREFS:
747 for (int i = 0; i < list.Length; i++) {
748 string idref = list [i];
749 if (!idList.Contains (idref))
750 missingIDReferences.Add (idref);
753 case XmlTokenizedType.ENTITY:
754 ent = dtd.EntityDecls [normalized];
756 HandleError ("Reference to undeclared entity was found in attribute: " + reader.Name + ".", XmlSeverityType.Error);
757 else if (ent.NotationName == null)
758 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);
760 case XmlTokenizedType.ENTITIES:
761 for (int i = 0; i < list.Length; i++) {
762 string entref = list [i];
763 ent = dtd.EntityDecls [FilterNormalization (reader.Name, entref)];
765 HandleError ("Reference to undeclared entity was found in attribute: " + reader.Name + ".", XmlSeverityType.Error);
766 else if (ent.NotationName == null)
767 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);
770 // case XmlTokenizedType.NMTOKEN: nothing to do
771 // case XmlTokenizedType.NMTOKENS: nothing to do
774 if (isStandalone && !def.IsInternalSubset &&
775 attrValue != normalized)
776 HandleError ("In standalone document, attribute value characters must not be checked against external definition.", XmlSeverityType.Error);
778 if (def.OccurenceType ==
779 DTDAttributeOccurenceType.Fixed &&
780 attrValue != def.DefaultValue)
781 HandleError (String.Format ("Fixed attribute {0} in element {1} has invalid value {2}.",
782 def.Name, decl.Name, attrValue),
783 XmlSeverityType.Error);
787 VerifyDeclaredAttributes (decl);
796 IHasXmlParserContext ctx = reader as IHasXmlParserContext;
798 dtd = ctx.ParserContext.Dtd;
800 XmlTextReaderImpl xmlTextReader = new XmlTextReaderImpl ("", XmlNodeType.Document, null);
801 xmlTextReader.XmlResolver = resolver;
802 xmlTextReader.GenerateDTDObjectModel (reader.Name,
803 reader ["PUBLIC"], reader ["SYSTEM"], reader.Value);
804 dtd = xmlTextReader.DTD;
806 currentAutomata = dtd.RootAutomata;
808 // Validity Constraint Check.
809 for (int i = 0; i < DTD.Errors.Length; i++)
810 HandleError (DTD.Errors [i].Message, XmlSeverityType.Error);
812 // NData target exists.
813 foreach (DTDEntityDeclaration ent in dtd.EntityDecls.Values)
814 if (ent.NotationName != null && dtd.NotationDecls [ent.NotationName] == null)
815 this.HandleError ("Target notation was not found for NData in entity declaration " + ent.Name + ".",
816 XmlSeverityType.Error);
817 // NOTATION exists for attribute default values
818 foreach (DTDAttListDeclaration attListIter in dtd.AttListDecls.Values) {
819 foreach (DTDAttributeDefinition def in attListIter.Definitions) {
820 if (def.Datatype.TokenizedType != XmlTokenizedType.NOTATION)
822 foreach (string notation in def.EnumeratedNotations)
823 if (dtd.NotationDecls [notation] == null)
824 this.HandleError ("Target notation was not found for NOTATION typed attribute default " + def.Name + ".",
825 XmlSeverityType.Error);
830 void ProcessStartElement ()
833 popScope = reader.IsEmptyElement;
834 elementStack.Push (reader.Name);
836 currentElement = Name;
838 // If no DTD, skip validation.
839 if (currentAutomata == null) {
840 ValidateAttributes (null, false);
841 if (reader.IsEmptyElement)
842 ProcessEndElement ();
848 previousAutomata = currentAutomata;
849 currentAutomata = currentAutomata.TryStartElement (reader.Name);
850 if (currentAutomata == DTD.Invalid) {
851 HandleError (String.Format ("Invalid start element found: {0}", reader.Name),
852 XmlSeverityType.Error);
853 currentAutomata = previousAutomata;
856 DTDElementDeclaration elem =
857 DTD.ElementDecls [reader.Name];
859 HandleError (String.Format ("Element {0} is not declared.", reader.Name),
860 XmlSeverityType.Error);
861 currentAutomata = previousAutomata;
864 automataStack.Push (currentAutomata);
865 if (elem != null) // i.e. not invalid
866 currentAutomata = elem.ContentModel.GetAutomata ();
868 DTDAttListDeclaration attList = dtd.AttListDecls [currentElement];
869 if (attList != null) {
871 ValidateAttributes (attList, true);
872 currentAttribute = -1;
874 if (reader.HasAttributes) {
875 HandleError (String.Format (
876 "Attributes are found on element {0} while it has no attribute definitions.", currentElement),
877 XmlSeverityType.Error);
879 // SetupValidityIgnorantAttributes ();
880 ValidateAttributes (null, false);
882 // If it is empty element then directly check end element.
883 if (reader.IsEmptyElement)
884 ProcessEndElement ();
887 void ProcessEndElement ()
892 // If no schema specification, then skip validation.
893 if (currentAutomata == null)
897 DTDElementDeclaration elem =
898 DTD.ElementDecls [reader.Name];
900 HandleError (String.Format ("Element {0} is not declared.", reader.Name),
901 XmlSeverityType.Error);
904 previousAutomata = currentAutomata;
905 // Don't let currentAutomata
906 DTDAutomata tmpAutomata = currentAutomata.TryEndElement ();
907 if (tmpAutomata == DTD.Invalid) {
908 HandleError (String.Format ("Invalid end element found: {0}", reader.Name),
909 XmlSeverityType.Error);
910 currentAutomata = previousAutomata;
913 currentAutomata = automataStack.Pop () as DTDAutomata;
916 void VerifyDeclaredAttributes (DTDAttListDeclaration decl)
918 // Check if all required attributes exist, and/or
919 // if there is default values, then add them.
920 for (int i = 0; i < decl.Definitions.Count; i++) {
921 DTDAttributeDefinition def = (DTDAttributeDefinition) decl.Definitions [i];
923 for (int a = 0; a < attributeCount; a++) {
924 if (attributes [a].Name == def.Name) {
932 if (def.OccurenceType == DTDAttributeOccurenceType.Required) {
933 HandleError (String.Format ("Required attribute {0} in element {1} not found .",
934 def.Name, decl.Name),
935 XmlSeverityType.Error);
939 else if (def.DefaultValue == null)
942 if (this.isStandalone && !def.IsInternalSubset)
943 HandleError ("In standalone document, external default value definition must not be applied.", XmlSeverityType.Error);
945 switch (validatingReader.ValidationType) {
946 case ValidationType.Auto:
947 if (validatingReader.Schemas.Count == 0)
948 goto case ValidationType.DTD;
950 case ValidationType.DTD:
951 case ValidationType.None:
952 // Other than them, ignore DTD defaults.
953 AttributeSlot slot = GetAttributeSlot ();
954 slot.Name = def.Name;
955 int colonAt = def.Name.IndexOf (':');
956 slot.LocalName = colonAt < 0 ? def.Name :
957 def.Name.Substring (colonAt + 1);
958 string prefix = colonAt < 0 ?
960 def.Name.Substring (0, colonAt);
961 slot.Prefix = prefix;
962 slot.Value = def.DefaultValue;
963 slot.IsDefault = true;
969 #if NET_2_1 && !MONOTOUCH
974 override bool ReadAttributeValue ()
976 if (consumedAttribute)
978 if (NodeType == XmlNodeType.Attribute &&
979 EntityHandling == EntityHandling.ExpandEntities) {
980 consumedAttribute = true;
983 else if (IsDefault) {
984 consumedAttribute = true;
988 return reader.ReadAttributeValue ();
991 #if NET_2_1 && !MONOTOUCH
996 override void ResolveEntity ()
998 reader.ResolveEntity ();
1001 public override int AttributeCount {
1003 if (currentTextValue != null)
1006 return attributeCount;
1010 public override string BaseURI {
1012 return reader.BaseURI;
1016 public override bool CanResolveEntity {
1017 get { return true; }
1020 public override int Depth {
1022 int baseNum = reader.Depth;
1023 if (currentTextValue != null && reader.NodeType == XmlNodeType.EndElement)
1026 return IsDefault ? baseNum + 1 : baseNum;
1030 public override bool EOF {
1031 get { return reader.EOF; }
1034 #if NET_2_1 && !MONOTOUCH
1039 override bool HasValue {
1041 return currentAttribute >= 0 ? true :
1042 currentTextValue != null ? true :
1047 public override bool IsDefault {
1049 if (currentTextValue != null)
1051 if (currentAttribute == -1)
1053 return attributes [currentAttribute].IsDefault;
1057 public override bool IsEmptyElement {
1059 if (currentTextValue != null)
1061 return reader.IsEmptyElement;
1065 public override string this [int i] {
1066 get { return GetAttribute (i); }
1069 public override string this [string name] {
1070 get { return GetAttribute (name); }
1073 public override string this [string name, string ns] {
1074 get { return GetAttribute (name, ns); }
1077 public int LineNumber {
1079 IXmlLineInfo info = reader as IXmlLineInfo;
1080 return (info != null) ? info.LineNumber : 0;
1084 public int LinePosition {
1086 IXmlLineInfo info = reader as IXmlLineInfo;
1087 return (info != null) ? info.LinePosition : 0;
1091 public override string LocalName {
1093 if (currentTextValue != null || consumedAttribute)
1094 return String.Empty;
1095 else if (NodeType == XmlNodeType.Attribute)
1096 return attributes [currentAttribute].LocalName;
1098 return reader.LocalName;
1102 public override string Name {
1104 if (currentTextValue != null || consumedAttribute)
1105 return String.Empty;
1106 else if (NodeType == XmlNodeType.Attribute)
1107 return attributes [currentAttribute].Name;
1113 public override string NamespaceURI {
1115 if (currentTextValue != null || consumedAttribute)
1116 return String.Empty;
1118 case XmlNodeType.Attribute:
1119 return (string) attributes [currentAttribute].NS;
1120 case XmlNodeType.Element:
1121 case XmlNodeType.EndElement:
1122 return nsmgr.LookupNamespace (Prefix);
1124 return String.Empty;
1129 public override XmlNameTable NameTable {
1130 get { return reader.NameTable; }
1133 public override XmlNodeType NodeType {
1135 if (currentTextValue != null)
1136 return isSignificantWhitespace ? XmlNodeType.SignificantWhitespace :
1137 isWhitespace ? XmlNodeType.Whitespace :
1140 // If consumedAttribute is true, then entities must be resolved.
1141 return consumedAttribute ? XmlNodeType.Text :
1142 IsDefault ? XmlNodeType.Attribute :
1147 public XmlParserContext ParserContext {
1148 get { return XmlSchemaUtil.GetParserContext (reader); }
1151 public override string Prefix {
1153 if (currentTextValue != null || consumedAttribute)
1154 return String.Empty;
1155 else if (NodeType == XmlNodeType.Attribute)
1156 return attributes [currentAttribute].Prefix;
1158 return reader.Prefix;
1162 public override char QuoteChar {
1164 // If it is not actually on an attribute, then it returns
1165 // undefined value or '"'.
1166 return reader.QuoteChar;
1170 public override ReadState ReadState {
1172 if (reader.ReadState == ReadState.EndOfFile && currentTextValue != null)
1173 return ReadState.Interactive;
1174 return reader.ReadState;
1178 public object SchemaType {
1180 if (DTD == null || currentAttribute == -1 ||
1181 currentElement == null)
1183 DTDAttListDeclaration decl =
1184 DTD.AttListDecls [currentElement];
1185 DTDAttributeDefinition def =
1186 decl != null ? decl [attributes [currentAttribute].Name] : null;
1187 return def != null ? def.Datatype : null;
1191 char [] whitespaceChars = new char [] {' '};
1192 private string FilterNormalization (string attrName, string rawValue)
1194 if (DTD == null || sourceTextReader == null ||
1195 !sourceTextReader.Normalization)
1198 DTDAttributeDefinition def =
1199 dtd.AttListDecls [currentElement].Get (attrName);
1200 valueBuilder.Append (rawValue);
1201 valueBuilder.Replace ('\r', ' ');
1202 valueBuilder.Replace ('\n', ' ');
1203 valueBuilder.Replace ('\t', ' ');
1205 if (def == null || def.Datatype.TokenizedType == XmlTokenizedType.CDATA)
1206 return valueBuilder.ToString ();
1207 for (int i=0; i < valueBuilder.Length; i++) {
1208 if (valueBuilder [i] != ' ')
1210 while (++i < valueBuilder.Length && valueBuilder [i] == ' ')
1211 valueBuilder.Remove (i, 1);
1213 return valueBuilder.ToString ().Trim (whitespaceChars);
1215 valueBuilder.Length = 0;
1219 // LAMESPEC: When source XmlTextReader.Normalize is true, then
1220 // every Attribute node is normalized. However, corresponding
1221 // Values of attribute value Text nodes are not.
1222 public override string Value {
1224 if (currentTextValue != null)
1225 return currentTextValue;
1226 // As to this property, MS.NET seems ignorant of EntityHandling...
1227 else if (NodeType == XmlNodeType.Attribute
1228 // It also covers default attribute text.
1229 || consumedAttribute)
1230 return attributes [currentAttribute].Value;
1232 return reader.Value;
1236 public override string XmlLang {
1238 string val = this ["xml:lang"];
1239 return val != null ? val : reader.XmlLang;
1243 internal XmlResolver Resolver {
1244 get { return resolver; }
1247 public XmlResolver XmlResolver {
1250 dtd.XmlResolver = value;
1255 public override XmlSpace XmlSpace {
1257 string val = this ["xml:space"];
1260 return XmlSpace.Preserve;
1262 return XmlSpace.Default;
1264 return reader.XmlSpace;