diff options
author | Atsushi Eno <atsushieno@gmail.com> | 2003-07-06 20:17:31 +0400 |
---|---|---|
committer | Atsushi Eno <atsushieno@gmail.com> | 2003-07-06 20:17:31 +0400 |
commit | d6b7b632e3fa96bd4b2d773dda6103af7de9b763 (patch) | |
tree | 0ea09b5e3e03bd58376df26d6bfac0e36bc04d57 | |
parent | 3f7e68b2751de7db455425dfcffb49bab4ece088 (diff) |
2003-07-06 Atsushi Enomoto <ginga@kit.hi-ho.ne.jp>
* XmlDocument.cs : Load(string filename) should close its stream.
Small change for the latest DTDObjectModel change.
* XmlTextReader.cs : Changed for the latest DTDObjectModel change (all
changed methods are only related to DTD stuff).
Now uses XmlSchemaDatatype for attribute type definition.
* XmlValidatingReader : initial (limited) support for DTD validation.
It can handle only XmlTextReader.
* DTDObjectModel.cs : changed radically for initial validation support.
* added DTDAutomata.cs and DTDValidatingReader.cs.
svn path=/trunk/mcs/; revision=15983
-rw-r--r-- | mcs/class/System.XML/System.Xml/ChangeLog | 12 | ||||
-rw-r--r-- | mcs/class/System.XML/System.Xml/DTDAutomata.cs | 322 | ||||
-rw-r--r-- | mcs/class/System.XML/System.Xml/DTDObjectModel.cs | 438 | ||||
-rw-r--r-- | mcs/class/System.XML/System.Xml/DTDValidatingReader.cs | 527 | ||||
-rw-r--r-- | mcs/class/System.XML/System.Xml/XmlDocument.cs | 10 | ||||
-rw-r--r-- | mcs/class/System.XML/System.Xml/XmlTextReader.cs | 72 | ||||
-rw-r--r-- | mcs/class/System.XML/System.Xml/XmlValidatingReader.cs | 172 |
7 files changed, 1401 insertions, 152 deletions
diff --git a/mcs/class/System.XML/System.Xml/ChangeLog b/mcs/class/System.XML/System.Xml/ChangeLog index 4f85c77b5df..7f7226eeb67 100644 --- a/mcs/class/System.XML/System.Xml/ChangeLog +++ b/mcs/class/System.XML/System.Xml/ChangeLog @@ -1,5 +1,17 @@ 2003-07-06 Atsushi Enomoto <ginga@kit.hi-ho.ne.jp> + * XmlDocument.cs : Load(string filename) should close its stream. + Small change for the latest DTDObjectModel change. + * XmlTextReader.cs : Changed for the latest DTDObjectModel change (all + changed methods are only related to DTD stuff). + Now uses XmlSchemaDatatype for attribute type definition. + * XmlValidatingReader : initial (limited) support for DTD validation. + It can handle only XmlTextReader. + * DTDObjectModel.cs : changed radically for initial validation support. + * added DTDAutomata.cs and DTDValidatingReader.cs. + +2003-07-06 Atsushi Enomoto <ginga@kit.hi-ho.ne.jp> + * XmlElement.cs : Removed extraneous xmlns output support (it should be done by XmlTextWriter). * XmlNode.cs : InsertBefore() now checks validity of the newChild (and diff --git a/mcs/class/System.XML/System.Xml/DTDAutomata.cs b/mcs/class/System.XML/System.Xml/DTDAutomata.cs new file mode 100644 index 00000000000..2b5dd6a9c73 --- /dev/null +++ b/mcs/class/System.XML/System.Xml/DTDAutomata.cs @@ -0,0 +1,322 @@ +// +// Mono.Xml.DTDAutomata +// +// Author: +// Atsushi Enomoto (ginga@kit.hi-ho.ne.jp) +// +// (C)2003 Atsushi Enomoto +// +using System; +using System.Collections; +using System.Text; +using System.Xml; +using System.Xml.Schema; +using Mono.Xml.Schema; + +namespace Mono.Xml +{ + public class DTDAutomataFactory + { + public DTDAutomataFactory (DTDObjectModel root) + { + this.root = root; + } + + DTDObjectModel root; + Hashtable choiceTable = new Hashtable (); + Hashtable sequenceTable = new Hashtable (); + + public DTDChoiceAutomata Choice (DTDAutomata left, DTDAutomata right) + { + Hashtable rightPool = choiceTable [left] as Hashtable; + if (rightPool == null) { + rightPool = new Hashtable (); + choiceTable [left] = rightPool; + } + DTDChoiceAutomata result = rightPool [right] as DTDChoiceAutomata; + if (result == null) { + result = new DTDChoiceAutomata (root, left, right); + rightPool [right] = result; + } + return result; + } + + public DTDSequenceAutomata Sequence (DTDAutomata left, DTDAutomata right) + { + Hashtable rightPool = sequenceTable [left] as Hashtable; + if (rightPool == null) { + rightPool = new Hashtable (); + sequenceTable [left] = rightPool; + } + DTDSequenceAutomata result = rightPool [right] as DTDSequenceAutomata; + if (result == null) { + result = new DTDSequenceAutomata (root, left, right); + rightPool [right] = result; + } + return result; + } + } + + public abstract class DTDAutomata + { + public DTDAutomata (DTDObjectModel root) + { + this.root = root; + } + + private DTDObjectModel root; + + public DTDObjectModel Root { + get { return root; } + } + + public DTDAutomata MakeChoice (DTDAutomata other) + { + if (this == Root.Invalid) + return other; + if (other == Root.Invalid) + return this; + if (this == Root.Empty && other == Root.Empty) + return this; + if (this == Root.Any && other == Root.Any) + return this; + else if (other == Root.Empty) + return Root.Factory.Choice (other, this); + else + return Root.Factory.Choice (this, other); + } + + public DTDAutomata MakeSequence (DTDAutomata other) + { + if (this == Root.Invalid || other == Root.Invalid) + return Root.Invalid; + if (this == Root.Empty) + return other; + if (other == Root.Empty) + return this; + else + return Root.Factory.Sequence (this, other); + } + + public abstract DTDAutomata TryStartElement (string name); + public virtual DTDAutomata TryEndElement () + { + return Root.Invalid; + } + + public virtual bool Emptiable { + get { return false; } + } + } + + public class DTDElementAutomata : DTDAutomata + { + public DTDElementAutomata (DTDObjectModel root, string name) + : base (root) + { + this.name = name; + } + + private string name; + + public string Name { + get { return name; } + } + + public override DTDAutomata TryStartElement (string name) + { + if (name == Name) + return Root.Empty; + else + return Root.Invalid; + } + } + + public class DTDChoiceAutomata : DTDAutomata + { + public DTDChoiceAutomata (DTDObjectModel root, + DTDAutomata left, DTDAutomata right) + : base (root) + { + this.left = left; + this.right = right; + } + + private DTDAutomata left; + private DTDAutomata right; + + public DTDAutomata Left { + get { return left; } + } + + public DTDAutomata Right { + get { return right; } + } + + public override DTDAutomata TryStartElement (string name) + { + return left.TryStartElement (name).MakeChoice ( + right.TryStartElement (name)); + } + + public override DTDAutomata TryEndElement () + { + if (left == Root.Empty) + return right; + if (right == Root.Empty) + return left; + else + return Root.Invalid; + } + + bool hasComputedEmptiable; + bool cachedEmptiable; + public override bool Emptiable { + get { + if (!hasComputedEmptiable) { + cachedEmptiable = left.Emptiable || + right.Emptiable; + hasComputedEmptiable = true; + } + return cachedEmptiable; + } + } + } + + public class DTDSequenceAutomata : DTDAutomata + { + public DTDSequenceAutomata (DTDObjectModel root, + DTDAutomata left, DTDAutomata right) + : base (root) + { + this.left = left; + this.right = right; + } + + private DTDAutomata left; + private DTDAutomata right; + + public DTDAutomata Left { + get { return left; } + } + + public DTDAutomata Right { + get { return right; } + } + + public override DTDAutomata TryStartElement (string name) + { + DTDAutomata afterL = left.TryStartElement (name); + DTDAutomata afterR = right.TryStartElement (name); + if (afterL == Root.Invalid) + return (afterL.Emptiable) ? afterR : afterL; + // else + DTDAutomata whenLeftConsumed = afterL.MakeSequence (right); + if (left.Emptiable) + return afterR.MakeChoice (whenLeftConsumed); + else + return whenLeftConsumed; + } + + bool hasComputedEmptiable; + bool cachedEmptiable; + public override bool Emptiable { + get { + if (!hasComputedEmptiable) { + cachedEmptiable = left.Emptiable && + right.Emptiable; + hasComputedEmptiable = true; + } + return cachedEmptiable; + } + } + } + + public class DTDOneOrMoreAutomata : DTDAutomata + { + public DTDOneOrMoreAutomata (DTDObjectModel root, + DTDAutomata children) + : base (root) + { + this.children = children; + } + + private DTDAutomata children; + + public DTDAutomata Children { + get { return children; } + } + + public override DTDAutomata TryStartElement (string name) + { + DTDAutomata afterC = children.TryStartElement (name); + if (afterC != Root.Invalid) + return afterC.MakeSequence ( + Root.Empty.MakeChoice (this)); + else + return Root.Invalid; + } + } + + public class DTDEmptyAutomata : DTDAutomata + { + public DTDEmptyAutomata (DTDObjectModel root) + : base (root) + { + } + + public override DTDAutomata TryEndElement () + { + return this; + } + + public override DTDAutomata TryStartElement (string name) + { + return Root.Invalid; + } + + public override bool Emptiable { + get { return true; } + } + } + + public class DTDAnyAutomata : DTDAutomata + { + public DTDAnyAutomata (DTDObjectModel root) + : base (root) + { + } + + public override DTDAutomata TryEndElement () + { + return this; + } + + public override DTDAutomata TryStartElement (string name) + { + return this; + } + + public override bool Emptiable { + get { return true; } + } + } + + public class DTDInvalidAutomata : DTDAutomata + { + public DTDInvalidAutomata (DTDObjectModel root) + : base (root) + { + } + + public override DTDAutomata TryEndElement () + { + return this; + } + + public override DTDAutomata TryStartElement (string name) + { + return this; + } + } +}
\ No newline at end of file diff --git a/mcs/class/System.XML/System.Xml/DTDObjectModel.cs b/mcs/class/System.XML/System.Xml/DTDObjectModel.cs index f0acbf75d45..23267400737 100644 --- a/mcs/class/System.XML/System.Xml/DTDObjectModel.cs +++ b/mcs/class/System.XML/System.Xml/DTDObjectModel.cs @@ -8,25 +8,25 @@ // using System; using System.Collections; +using System.Text; using System.Xml; +using System.Xml.Schema; +using Mono.Xml.Schema; namespace Mono.Xml { - public class DTDObjectModel { - public DTDObjectModel () - { - } - - internal Hashtable ElementDecls = new Hashtable (); - internal Hashtable AttListDecls = new Hashtable (); + internal DTDElementDeclarationCollection elementDecls; + internal DTDAttListDeclarationCollection attListDecls; internal Hashtable EntityDecls = new Hashtable (); internal Hashtable NotationDecls = new Hashtable (); - public string BaseURI { - // XmlStreamParser.BaseURI - get { return baseURI; } + public DTDObjectModel () + { + elementDecls = new DTDElementDeclarationCollection (this); + attListDecls = new DTDAttListDeclarationCollection (this); + factory = new DTDAutomataFactory (this); } public string Name; @@ -37,69 +37,312 @@ namespace Mono.Xml public string InternalSubset; - string baseURI; - } + public string ResolveEntity (string name) + { + DTDEntityDeclaration decl = EntityDecls [name] + as DTDEntityDeclaration; + return decl.EntityValue; + } - public enum DTDContentOrderType - { - None, - Seq, - Or + private DTDAutomataFactory factory; + public DTDAutomataFactory Factory { + get { return factory; } + } + + public DTDElementDeclaration RootElement { + get { return ElementDecls [Name]; } + } + + public DTDElementDeclarationCollection ElementDecls { + get { return elementDecls; } + } + + public DTDAttListDeclarationCollection AttListDecls { + get { return attListDecls; } + } + + DTDElementAutomata rootAutomata; + public DTDAutomata RootAutomata { + get { + if (rootAutomata == null) + rootAutomata = new DTDElementAutomata (this, this.Name); + return rootAutomata; + } + } + + DTDEmptyAutomata emptyAutomata; + public DTDEmptyAutomata Empty { + get { + if (emptyAutomata == null) + emptyAutomata = new DTDEmptyAutomata (this); + return emptyAutomata; + } + } + + DTDAnyAutomata anyAutomata; + public DTDAnyAutomata Any { + get { + if (anyAutomata == null) + anyAutomata = new DTDAnyAutomata (this); + return anyAutomata; + } + } + + DTDInvalidAutomata invalidAutomata; + public DTDInvalidAutomata Invalid { + get { + if (invalidAutomata == null) + invalidAutomata = new DTDInvalidAutomata (this); + return invalidAutomata; + } + } } - public enum DTDAttributeType + public class DTDElementDeclarationCollection { - None, - CData, - Id, - IdRef, - IdRefs, - Entity, - Entities, - NmToken, - NmTokens, - Notation + Hashtable elementDecls = new Hashtable (); + DTDObjectModel root; + + public DTDElementDeclarationCollection (DTDObjectModel root) + { + this.root = root; + } + + public DTDElementDeclaration this [string name] { + get { return elementDecls [name] as DTDElementDeclaration; } + } + + public void Add (string name, DTDElementDeclaration decl) + { + if (elementDecls [name] != null) + throw new InvalidOperationException (String.Format ( + "Element declaration for {0} was already added.", + name)); + decl.SetRoot (root); + elementDecls.Add (name, decl); + } + + public ICollection Keys { + get { return elementDecls.Keys; } + } + + public ICollection Values { + get { return elementDecls.Values; } + } } - public enum DTDAttributeOccurenceType + public class DTDAttListDeclarationCollection { - None, - Required, - Optional, - Fixed + Hashtable attListDecls = new Hashtable (); + DTDObjectModel root; + + public DTDAttListDeclarationCollection (DTDObjectModel root) + { + this.root = root; + } + + public DTDAttListDeclaration this [string name] { + get { return attListDecls [name] as DTDAttListDeclaration; } + } + + public void Add (string name, DTDAttListDeclaration decl) + { + if (attListDecls [name] != null) + throw new InvalidOperationException (String.Format ( + "AttList declaration for {0} was already added.", + name)); + decl.SetRoot (root); + attListDecls.Add (name, decl); + } + + public ICollection Keys { + get { return attListDecls.Keys; } + } + + public ICollection Values { + get { return attListDecls.Values; } + } } public class DTDContentModel { + private DTDObjectModel root; + DTDAutomata compiledAutomata; + + private string ownerElementName; public string ElementName; public DTDContentOrderType OrderType = DTDContentOrderType.None; - public ArrayList ChildModels = new ArrayList (); - public decimal MinOccurs = 1; - public decimal MaxOccurs = 1; + public DTDContentModelCollection ChildModels + = new DTDContentModelCollection (); + public DTDOccurence Occurence = DTDOccurence.One; + + internal DTDContentModel (DTDObjectModel root, string ownerElementName) + { + this.root = root; + this.ownerElementName = ownerElementName; + } + + public DTDElementDeclaration ElementDecl { + get { + return root.ElementDecls [ownerElementName]; + } + } + + public DTDAutomata GetAutomata () + { + if (compiledAutomata == null) + Compile (); + return compiledAutomata; + } + + public DTDAutomata Compile () + { + compiledAutomata = CompileInternal (); + return compiledAutomata; + } + + private DTDAutomata CompileInternal () + { + if (ElementDecl.IsAny) + return root.Any; + if (ElementDecl.IsEmpty) + return root.Empty; + + DTDAutomata basis = GetBasicContentAutomata (); + switch (Occurence) { + case DTDOccurence.One: + return basis; + case DTDOccurence.Optional: + return Choice (root.Empty, basis); + case DTDOccurence.OneOrMore: + return new DTDOneOrMoreAutomata (root, basis); + case DTDOccurence.ZeroOrMore: + return Choice (root.Empty, new DTDOneOrMoreAutomata (root, basis)); + } + throw new InvalidOperationException (); + } + + private DTDAutomata GetBasicContentAutomata () + { + if (ElementName != null) + return new DTDElementAutomata (root, ElementName); + switch (ChildModels.Count) { + case 0: + return root.Empty; + case 1: + return ChildModels [0].GetAutomata (); + } + + DTDAutomata current = null; + int childCount = ChildModels.Count; + switch (OrderType) { + case DTDContentOrderType.Seq: + current = Sequence ( + ChildModels [childCount - 2].GetAutomata (), + ChildModels [childCount - 1].GetAutomata ()); + for (int i = childCount - 2; i > 0; i--) + current = Sequence ( + ChildModels [i - 1].GetAutomata (), current); + return current; + case DTDContentOrderType.Or: + current = Choice ( + ChildModels [childCount - 2].GetAutomata (), + ChildModels [childCount - 1].GetAutomata ()); + for (int i = childCount - 2; i > 0; i--) + current = Choice ( + ChildModels [i - 1].GetAutomata (), current); + return current; + default: + throw new InvalidOperationException ("Invalid pattern specification"); + } + } + + private DTDAutomata Sequence (DTDAutomata l, DTDAutomata r) + { + return root.Factory.Sequence (l, r); + } + + private DTDAutomata Choice (DTDAutomata l, DTDAutomata r) + { + return l.MakeChoice (r); + } + + } + + public class DTDContentModelCollection + { + ArrayList contentModel = new ArrayList (); + + public DTDContentModelCollection () + { + } + + public DTDContentModel this [int i] { + get { return contentModel [i] as DTDContentModel; } + } + + public int Count { + get { return contentModel.Count; } + } - internal DTDContentModel () {} + public void Add (DTDContentModel model) + { + contentModel.Add (model); + } } - public class DTDElementDeclaration : ICloneable + public abstract class DTDNode + { + private DTDObjectModel root; + + internal void SetRoot (DTDObjectModel root) + { + this.root = root; + } + + protected DTDObjectModel Root { + get { return root; } + } + } + + public class DTDElementDeclaration : DTDNode // : ICloneable { public string Name; public bool IsEmpty; public bool IsAny; public bool IsMixedContent; - public DTDContentModel ContentModel = new DTDContentModel (); + public DTDContentModel contentModel; + DTDObjectModel root; - internal DTDElementDeclaration () {} - - public object Clone () + internal DTDElementDeclaration (DTDObjectModel root) { - return this.MemberwiseClone (); + this.root = root; } + + public DTDContentModel ContentModel { + get { + if (contentModel == null) + contentModel = new DTDContentModel (root, Name); + return contentModel; + } + } + + public DTDAttListDeclaration Attributes { + get { + return Root.AttListDecls [Name]; + } + } + +// public object Clone () +// { +// return this.MemberwiseClone (); +// } } - public class DTDAttributeDefinition : ICloneable + public class DTDAttributeDefinition : DTDNode// : ICloneable { public string Name; - public DTDAttributeType AttributeType = DTDAttributeType.None; + public XmlSchemaDatatype Datatype; // entity reference inside enumerated values are not allowed, // but on the other hand, they are allowed inside default value. // Then I decided to use string ArrayList for enumerated values, @@ -108,29 +351,93 @@ namespace Mono.Xml public string UnresolvedDefaultValue = null; public ArrayList EnumeratedNotations = new ArrayList(); public DTDAttributeOccurenceType OccurenceType = DTDAttributeOccurenceType.None; + private string resolvedDefaultValue; internal DTDAttributeDefinition () {} - public object Clone () + public string DefaultValue { + get { + if (resolvedDefaultValue == null) + resolvedDefaultValue = ComputeDefaultValue (); + return resolvedDefaultValue; + } + } + + private string ComputeDefaultValue () { - return this.MemberwiseClone (); + StringBuilder sb = new StringBuilder (); + int pos = 0; + int next = 0; + while ((next = this.UnresolvedDefaultValue.IndexOf ('&', pos)) >= 0) { + sb.Append (this.UnresolvedDefaultValue.Substring (pos, next - 1)); + int semicolon = this.UnresolvedDefaultValue.IndexOf (';', next); + string name = this.UnresolvedDefaultValue.Substring (pos + 1, semicolon - 1); + sb.Append (Root.ResolveEntity (name)); + } + sb.Append (this.UnresolvedDefaultValue.Substring (pos)); + string ret = sb.ToString (); + sb.Length = 0; + return ret; } + +// public object Clone () +// { +// return this.MemberwiseClone (); +// } } - public class DTDAttListDeclaration : ICloneable + public class DTDAttListDeclaration : DTDNode// : ICloneable { public string Name; - public Hashtable AttributeDefinitions = new Hashtable (); internal DTDAttListDeclaration () {} + private Hashtable attributeOrders = new Hashtable (); + private Hashtable attributes = new Hashtable (); + + public DTDAttributeDefinition this [int i] { + get { return Get (i); } + } + + public DTDAttributeDefinition this [string name] { + get { return Get (name); } + } + + public DTDAttributeDefinition Get (int i) + { + return attributes [i] as DTDAttributeDefinition; + } - public object Clone () + public DTDAttributeDefinition Get (string name) { - return this.MemberwiseClone (); + return attributes [name] as DTDAttributeDefinition; } + + public ICollection Definitions { + get { return attributes.Values; } + } + + public void Add (DTDAttributeDefinition def) + { + if (attributes [def.Name] != null) + throw new InvalidOperationException (String.Format ( + "Attribute definition for {0} was already added at element {1}.", + def.Name, this.Name)); + def.SetRoot (Root); + attributes.Add (def.Name, def); + attributeOrders.Add (def.Name, attributeOrders.Count); + } + + public int Count { + get { return attributeOrders.Count; } + } + +// public object Clone () +// { +// return this.MemberwiseClone (); +// } } - public class DTDEntityDeclaration + public class DTDEntityDeclaration : DTDNode { public string Name; public string PublicId; @@ -142,7 +449,7 @@ namespace Mono.Xml internal DTDEntityDeclaration () {} } - public class DTDNotationDeclaration + public class DTDNotationDeclaration : DTDNode { public string Name; public string LocalName; @@ -153,7 +460,7 @@ namespace Mono.Xml internal DTDNotationDeclaration () {} } - public class DTDParameterEntityDeclaration + public class DTDParameterEntityDeclaration : DTDNode { public string Name; public string PublicId; @@ -161,4 +468,27 @@ namespace Mono.Xml public string BaseURI; public string Value; } + + public enum DTDContentOrderType + { + None, + Seq, + Or + } + + public enum DTDAttributeOccurenceType + { + None, + Required, + Optional, + Fixed + } + + public enum DTDOccurence + { + One, + Optional, + ZeroOrMore, + OneOrMore + } } diff --git a/mcs/class/System.XML/System.Xml/DTDValidatingReader.cs b/mcs/class/System.XML/System.Xml/DTDValidatingReader.cs new file mode 100644 index 00000000000..8a8bfc157ca --- /dev/null +++ b/mcs/class/System.XML/System.Xml/DTDValidatingReader.cs @@ -0,0 +1,527 @@ +using System; +using System.Collections; +using System.Xml; +using System.Xml.Schema; + +namespace Mono.Xml +{ + public class DTDValidatingReader : XmlValidatingReader, IXmlLineInfo + { + public DTDValidatingReader (XmlReader reader) + : base (reader) + { + this.reader = reader; + elementStack = new Stack (); + automataStack = new Stack (); + } + + XmlReader reader; + DTDObjectModel dtd; + Stack elementStack; + Stack automataStack; + string currentAttribute; + + public DTDObjectModel DTD { + get { return dtd; } + } + + public override void Close () + { + reader.Close (); + } + + // We had already done attribute validation, so can ignore name. + public override string GetAttribute (int i) + { + if (dtd == null) + return reader.GetAttribute (i); + + // It should access attributes by *defined* order. + if (elementStack.Count == 0) + return String.Empty; + DTDAttributeDefinition def = dtd.ElementDecls [elementStack.Peek () as string] + .Attributes [i] as DTDAttributeDefinition; + string specified = reader.GetAttribute (def.Name); + return (specified != null) ? specified : def.DefaultValue; + } + + public override string GetAttribute (string name) + { + if (dtd == null) + return reader.GetAttribute (name); + + if (elementStack.Count == 0) + return String.Empty; + string specified = reader.GetAttribute (name); + if (specified != null) + return specified; + + DTDAttributeDefinition def = dtd.ElementDecls [elementStack.Peek () as string] + .Attributes [name] as DTDAttributeDefinition; + return def.DefaultValue; + } + + public override string GetAttribute (string name, string ns) + { + if (dtd == null) + return reader.GetAttribute (name, ns); + + if (ns != String.Empty) + throw new InvalidOperationException ("DTD validating reader does not support namespace."); + return GetAttribute (name); + } + + bool IXmlLineInfo.HasLineInfo () + { + IXmlLineInfo ixli = reader as IXmlLineInfo; + if (ixli != null) + return ixli.HasLineInfo (); + else + return false; + } + + public override string LookupNamespace (string prefix) + { + // Does it mean anything with DTD? + return reader.LookupNamespace (prefix); + } + + public override void MoveToAttribute (int i) + { + if (dtd == null) { + reader.MoveToAttribute (i); + currentAttribute = reader.Name; + return; + } + + // It should access attributes by *defined* order. + if (elementStack.Count == 0) + return; + + DTDAttListDeclaration decl = dtd.ElementDecls [elementStack.Peek () as string].Attributes; + if (decl.Count <= i) + throw new ArgumentOutOfRangeException ("i"); + DTDAttributeDefinition def = decl [i] as DTDAttributeDefinition; + currentAttribute = def.Name; + // We can ignore return value here. + reader.MoveToAttribute (def.Name); + } + + public override bool MoveToAttribute (string name) + { + if (dtd == null) { + bool b = reader.MoveToAttribute (name); + if (b) + currentAttribute = reader.Name; + return b; + } + + if (elementStack.Count == 0) + return false; + + DTDAttributeDefinition def = dtd.ElementDecls [elementStack.Peek () as string] + .Attributes [name] as DTDAttributeDefinition; + if (def == null) + return false; + reader.MoveToAttribute (name); + currentAttribute = name; + return true; + } + + public override bool MoveToAttribute (string name, string ns) + { + if (dtd == null) { + bool b = reader.MoveToAttribute (name, ns); + if (b) + currentAttribute = reader.Name; + return b; + } + + if (ns != String.Empty) + throw new InvalidOperationException ("DTD validating reader does not support namespace."); + return MoveToAttribute (name); + } + + public override bool MoveToElement () + { + bool b = reader.MoveToElement (); + if (!b) + return false; + currentAttribute = null; + return true; + } + + public override bool MoveToFirstAttribute () + { + if (dtd == null) { + bool b = reader.MoveToFirstAttribute (); + if (b) + currentAttribute = reader.Name; + return b; + } + + // It should access attributes by *defined* order. + if (elementStack.Count == 0) + return false; + + DTDAttListDeclaration decl = dtd.ElementDecls [elementStack.Peek () as string].Attributes; + if (decl.Count == 0) + return false; + return reader.MoveToAttribute (decl [0].Name); + } + + public override bool MoveToNextAttribute () + { + if (dtd == null) { + bool b = reader.MoveToNextAttribute (); + if (b) + currentAttribute = reader.Name; + return b; + } + + if (currentAttribute == null) + return false; + + DTDAttListDeclaration decl = dtd.ElementDecls [elementStack.Peek () as string].Attributes; + int pos = 0; + for (; pos < decl.Count; pos++) { + if (decl [pos].Name == currentAttribute) + break; + } + if (pos == decl.Count) + return false; + + currentAttribute = decl [pos].Name; + reader.MoveToAttribute (currentAttribute); + return true; + } + + bool inContent; + DTDAutomata currentAutomata; + DTDAutomata previousAutomata; + bool isStandalone; + + [MonoTODO] + public override bool Read () + { + MoveToElement (); + + bool b = reader.Read (); + + if (!inContent && reader.NodeType == XmlNodeType.Element) { + inContent = true; + if (dtd == null) + currentAutomata = null; + else + currentAutomata = dtd.RootAutomata; + } + + if (!b) { + if (elementStack.Count != 0) + throw new InvalidOperationException ("Unexpected end of XmlReader."); + return false; + } + + switch (reader.NodeType) { + case XmlNodeType.XmlDeclaration: + if (GetAttribute ("standalone") == "yes") + isStandalone = true; + break; + + case XmlNodeType.DocumentType: +#if true + XmlTextReader xmlTextReader = reader as XmlTextReader; + this.dtd = xmlTextReader.currentSubset; +#else + // It will support external DTD reader in the future. + this.dtd = new DTDReader (reader).DTD; +#endif + break; + + case XmlNodeType.Element: // startElementDeriv + // If no schema specification, then skip validation. + if (currentAutomata == null) + break; + + previousAutomata = currentAutomata; + currentAutomata = currentAutomata.TryStartElement (reader.Name); + if (currentAutomata == DTD.Invalid) + throw new XmlException (reader as IXmlLineInfo, + String.Format ("Invalid start element found: {0}", reader.Name)); + DTDElementDeclaration decl = DTD.ElementDecls [reader.Name]; + if (decl == null) + throw new XmlException (reader as IXmlLineInfo, + String.Format ("Element {0} is not declared.", reader.Name)); + elementStack.Push (reader.Name); + automataStack.Push (currentAutomata); + currentAutomata = decl.ContentModel.GetAutomata (); + + // TODO: check attributes + if (decl.Attributes == null) { + if (reader.HasAttributes) + throw new XmlException (reader as IXmlLineInfo, + String.Format ("Attributes are found on element {0} while it has no attribute definitions.", + decl.Name)); + } + else + ValidateAttributes (decl); + + // If it is empty element then directly check end element. + if (reader.IsEmptyElement) + goto case XmlNodeType.EndElement; + break; + + case XmlNodeType.EndElement: // endTagDeriv + // If no schema specification, then skip validation. + if (currentAutomata == null) + break; + + decl = DTD.ElementDecls [reader.Name]; + if (decl == null) + throw new XmlException (reader as IXmlLineInfo, + String.Format ("Element {0} is not declared.", reader.Name)); + + previousAutomata = currentAutomata; + // Don't let currentAutomata + DTDAutomata tmpAutomata = currentAutomata.TryEndElement (); + if (tmpAutomata == DTD.Invalid) + throw new XmlException (reader as IXmlLineInfo, + String.Format ("Invalid end element found: {0}", reader.Name)); + + elementStack.Pop (); + currentAutomata = automataStack.Pop () as DTDAutomata; + break; + + case XmlNodeType.CDATA: + case XmlNodeType.SignificantWhitespace: + case XmlNodeType.Text: + // If no schema specification, then skip validation. + if (currentAutomata == null) + break; + + DTDElementDeclaration elem = dtd.ElementDecls [elementStack.Peek () as string]; + if (!elem.IsMixedContent) + throw new XmlException (reader as IXmlLineInfo, + String.Format ("Current element {0} does not allow character data content.", elementStack.Peek ())); + break; + } + return true; + } + + private void ValidateAttributes (DTDElementDeclaration decl) + { + Hashtable atts = new Hashtable (); + if (reader.MoveToFirstAttribute ()) { + do { + atts.Add (reader.Name, reader.Value); + } while (reader.MoveToNextAttribute ()); + } + foreach (DTDAttributeDefinition def in decl.Attributes.Definitions) { + string value = atts [def.Name] as string; + switch (def.OccurenceType) { + case DTDAttributeOccurenceType.Required: + if (value == null) + throw new XmlException (reader as IXmlLineInfo, + String.Format ("Required attribute {0} in element {1} not found .", + def.Name, decl.Name)); + break; + case DTDAttributeOccurenceType.Fixed: + if (value != def.DefaultValue) + throw new XmlException (reader as IXmlLineInfo, + String.Format ("Fixed attribute {0} in element {1} has invalid value {2}.", + def.Name, decl.Name, reader.Value)); + break; + } + atts.Remove (def.Name); + } + if (atts.Count > 0) { + string [] extraneous = new string [atts.Count]; + int i=0; + foreach (string attribute in atts.Keys) + extraneous [i++] = attribute; + throw new XmlException (reader as IXmlLineInfo, + String.Format ("These attributes are not declared in element {0}: {1}", + decl.Name, String.Join (",", extraneous))); + } + reader.MoveToElement (); + } + + public override bool ReadAttributeValue () + { + return reader.ReadAttributeValue (); + } + + public override string ReadInnerXml () + { + // MS.NET 1.0 has a serious bug here. It skips validation. + return reader.ReadInnerXml (); + } + + public override string ReadOuterXml () + { + // MS.NET 1.0 has a serious bug here. It skips validation. + return reader.ReadOuterXml (); + } + + public override string ReadString () + { + // It seems to be the same as ReadInnerXml(). + return reader.ReadString (); + } + +// public override void ResolveEntity () +// { +// } + + public override int AttributeCount { + get { + if (dtd == null || !inContent) + return reader.AttributeCount; + + if (elementStack.Count == 0) + return 0; + return dtd.ElementDecls [elementStack.Peek () as string] + .Attributes.Count; + } + } + + [MonoTODO ("Should consider general entities.")] + public override string BaseURI { + get { + return reader.BaseURI; + } + } + + public override bool CanResolveEntity { + get { return true; } + } + + [MonoTODO ("Should consider general entities' depth")] + public override int Depth { + get { + return (currentAttribute != null + || reader.NodeType != XmlNodeType.Attribute) ? + reader.Depth : reader.Depth + 1; + } + } + + [MonoTODO] + public override bool EOF { + get { return reader.EOF; } + } + + public override bool HasValue { + get { + return (currentAttribute != null + || reader.NodeType != XmlNodeType.Attribute) ? + reader.HasValue : true; + } + } + + public override bool IsDefault { + get { + if (currentAttribute == null) + return false; + return reader.GetAttribute (currentAttribute) != null; + } + } + + public override bool IsEmptyElement { + get { return reader.IsEmptyElement; } + } + + public override string this [int i] { + get { return GetAttribute (i); } + } + + public override string this [string name] { + get { return GetAttribute (name); } + } + + public override string this [string name, string ns] { + get { return GetAttribute (name, ns); } + } + + public override string LocalName { + get { + return (currentAttribute != null + || reader.NodeType != XmlNodeType.Attribute) ? + reader.LocalName : currentAttribute; + } + } + + public override string Name { + get { + return (currentAttribute != null + || reader.NodeType != XmlNodeType.Attribute) ? + reader.Name : currentAttribute; + } + } + + public override string NamespaceURI { + get { + if (currentAttribute != null) + return String.Empty; + return reader.NamespaceURI; + } + } + + public override XmlNameTable NameTable { + get { return reader.NameTable; } + } + + public override XmlNodeType NodeType { + get { + return (currentAttribute != null + || reader.NodeType != XmlNodeType.Attribute) ? + reader.NodeType : XmlNodeType.Attribute; + } + } + + public override string Prefix { + get { + if (currentAttribute != null) { + int colon = currentAttribute.IndexOf (':'); + return colon < 0 ? + currentAttribute : + currentAttribute.Substring (0, colon - 1); + } + else + return reader.Prefix; + } + } + + public override char QuoteChar { + get { + // If it is not actually on an attribute, then it returns + // undefined value or '"'. + return reader.QuoteChar; + } + } + + public override ReadState ReadState { + get { + return reader.ReadState; + } + } + + public override string Value { + get { + if (currentAttribute != null || reader.NodeType != XmlNodeType.Attribute) + return reader.Value; + return reader.GetAttribute (currentAttribute); + } + } + + [MonoTODO ("Should consider default xml:lang values.")] + public override string XmlLang { + get { return reader.XmlLang; } + } + + [MonoTODO ("Should consider default xml:space values.")] + public override XmlSpace XmlSpace { + get { return reader.XmlSpace; } + } + + } +} diff --git a/mcs/class/System.XML/System.Xml/XmlDocument.cs b/mcs/class/System.XML/System.Xml/XmlDocument.cs index 3d555860527..8b710ac813e 100644 --- a/mcs/class/System.XML/System.Xml/XmlDocument.cs +++ b/mcs/class/System.XML/System.Xml/XmlDocument.cs @@ -284,7 +284,7 @@ namespace System.Xml return new XmlEntityReference (name, this); } - internal virtual XPathNavigator CreateNavigator (XmlNode node) + protected internal virtual XPathNavigator CreateNavigator (XmlNode node) { return new XmlDocumentNavigator (node); } @@ -547,7 +547,9 @@ namespace System.Xml public virtual void Load (string filename) { - Load (new XmlTextReader (filename)); + XmlReader xr = new XmlTextReader (filename); + Load (xr); + xr.Close (); } public virtual void Load (TextReader txtReader) @@ -849,10 +851,10 @@ namespace System.Xml doctype.notations.Nodes.Add (n); } foreach (DTDElementDeclaration decl in subset.ElementDecls.Values) { - doctype.elementDecls.Add (decl.Name, decl.Clone ()); + doctype.elementDecls.Add (decl.Name, decl); } foreach (DTDAttListDeclaration decl in subset.AttListDecls.Values) { - doctype.attListDecls.Add (decl.Name, decl.Clone ()); + doctype.attListDecls.Add (decl.Name, decl); } return doctype; } diff --git a/mcs/class/System.XML/System.Xml/XmlTextReader.cs b/mcs/class/System.XML/System.Xml/XmlTextReader.cs index 697e7a601b1..33e4aa5ae5d 100644 --- a/mcs/class/System.XML/System.Xml/XmlTextReader.cs +++ b/mcs/class/System.XML/System.Xml/XmlTextReader.cs @@ -25,6 +25,7 @@ using System; using System.Collections; using System.IO; using System.Text; +using System.Xml.Schema; using Mono.Xml; using Mono.Xml.Native; @@ -1563,6 +1564,7 @@ namespace System.Xml // now compile DTD currentSubset = new DTDObjectModel (); // merges both internal and external subsets in the meantime, + currentSubset.Name = doctypeName; int originalParserDepth = parserInputStack.Count; if (intSubsetStartLine > 0) { XmlParserInput original = currentInput; @@ -1900,7 +1902,7 @@ namespace System.Xml case 'A': Expect ("TTLIST"); DTDAttListDeclaration atl = ReadAttListDecl (); - if (currentSubset.AttListDecls.ContainsKey (atl.Name)) +// if (currentSubset.AttListDecls.ContainsKey (atl.Name)) currentSubset.AttListDecls.Add (atl.Name, atl); break; case 'N': @@ -1962,7 +1964,7 @@ namespace System.Xml // The reader is positioned on the head of the name. private DTDElementDeclaration ReadElementDecl () { - DTDElementDeclaration decl = new DTDElementDeclaration (); + DTDElementDeclaration decl = new DTDElementDeclaration (currentSubset); SkipWhitespace (); TryExpandPERef (); decl.Name = ReadName (); @@ -1993,7 +1995,7 @@ namespace System.Xml SkipWhitespace (); TryExpandPERef (); if(PeekChar () == '#') { - // Mixed Contents + // Mixed Contents. "#PCDATA" must appear first. decl.IsMixedContent = true; Expect ("#PCDATA"); SkipWhitespace (); @@ -2004,16 +2006,20 @@ namespace System.Xml SkipWhitespace (); TryExpandPERef (); SkipWhitespace (); - model.ChildModels.Add (ReadName ()); + DTDContentModel elem = new DTDContentModel (currentSubset, decl.Name); + model.ElementName = ReadName (); + model.ChildModels.Add (elem); SkipWhitespace (); TryExpandPERef (); } Expect (')'); - if(PeekChar () == '*') - ReadChar (); // ZeroOrMore + if (model.ChildModels.Count > 0) { + Expect ('*'); + model.Occurence = DTDOccurence.ZeroOrMore; + } } else { // Non-Mixed Contents - model.ChildModels.Add (ReadCP ()); + model.ChildModels.Add (ReadCP (decl)); SkipWhitespace (); do { // copied from ReadCP() ...;-) @@ -2024,7 +2030,7 @@ namespace System.Xml model.OrderType = DTDContentOrderType.Or; ReadChar (); SkipWhitespace (); - model.ChildModels.Add (ReadCP ()); + model.ChildModels.Add (ReadCP (decl)); SkipWhitespace (); } else if(PeekChar () == ',') @@ -2033,7 +2039,7 @@ namespace System.Xml model.OrderType = DTDContentOrderType.Seq; ReadChar (); SkipWhitespace (); - model.ChildModels.Add (ReadCP ()); + model.ChildModels.Add (ReadCP (decl)); SkipWhitespace (); } else @@ -2045,16 +2051,15 @@ namespace System.Xml switch(PeekChar ()) { case '?': - model.MinOccurs = 0; + model.Occurence = DTDOccurence.Optional; ReadChar (); break; case '*': - model.MinOccurs = 0; - model.MaxOccurs = decimal.MaxValue; + model.Occurence = DTDOccurence.ZeroOrMore; ReadChar (); break; case '+': - model.MaxOccurs = decimal.MaxValue; + model.Occurence = DTDOccurence.OneOrMore; ReadChar (); break; } @@ -2066,14 +2071,15 @@ namespace System.Xml } // Read 'cp' (BNF) of contentdecl (BNF) - private DTDContentModel ReadCP () + private DTDContentModel ReadCP (DTDElementDeclaration elem) { - DTDContentModel model = new DTDContentModel (); + DTDContentModel model = null; TryExpandPERef (); if(PeekChar () == '(') { + model = new DTDContentModel (currentSubset, elem.Name); ReadChar (); SkipWhitespace (); - model.ChildModels.Add (ReadCP ()); + model.ChildModels.Add (ReadCP (elem)); SkipWhitespace (); do { TryExpandPERef (); @@ -2083,7 +2089,7 @@ namespace System.Xml model.OrderType = DTDContentOrderType.Or; ReadChar (); SkipWhitespace (); - model.ChildModels.Add (ReadCP ()); + model.ChildModels.Add (ReadCP (elem)); SkipWhitespace (); } else if(PeekChar () == ',') { @@ -2091,7 +2097,7 @@ namespace System.Xml model.OrderType = DTDContentOrderType.Seq; ReadChar (); SkipWhitespace (); - model.ChildModels.Add (ReadCP ()); + model.ChildModels.Add (ReadCP (elem)); SkipWhitespace (); } else @@ -2103,21 +2109,21 @@ namespace System.Xml } else { TryExpandPERef (); + model = new DTDContentModel (currentSubset, elem.Name); model.ElementName = ReadName (); } switch(PeekChar ()) { case '?': - model.MinOccurs = 0; + model.Occurence = DTDOccurence.Optional; ReadChar (); break; case '*': - model.MinOccurs = 0; - model.MaxOccurs = decimal.MaxValue; + model.Occurence = DTDOccurence.ZeroOrMore; ReadChar (); break; case '+': - model.MaxOccurs = decimal.MaxValue; + model.Occurence = DTDOccurence.OneOrMore; ReadChar (); break; } @@ -2290,8 +2296,8 @@ namespace System.Xml while (XmlConstructs.IsName ((char) PeekChar ())) { DTDAttributeDefinition def = ReadAttributeDefinition (); - if (decl.AttributeDefinitions [def.Name] == null) - decl.AttributeDefinitions.Add (def.Name, def); + if (decl [def.Name] == null) + decl.Add (def); SkipWhitespace (); TryExpandPERef (); SkipWhitespace (); @@ -2315,7 +2321,7 @@ namespace System.Xml switch(PeekChar ()) { case 'C': // CDATA Expect ("CDATA"); - def.AttributeType = DTDAttributeType.CData; + def.Datatype = XmlSchemaDatatype.FromName ("normalizedString"); break; case 'I': // ID, IDREF, IDREFS Expect ("ID"); @@ -2324,23 +2330,23 @@ namespace System.Xml if(PeekChar () == 'S') { // IDREFS ReadChar (); - def.AttributeType = DTDAttributeType.IdRefs; + def.Datatype = XmlSchemaDatatype.FromName ("IDREFS"); } else // IDREF - def.AttributeType = DTDAttributeType.IdRef; + def.Datatype = XmlSchemaDatatype.FromName ("IDREF"); } else // ID - def.AttributeType = DTDAttributeType.Id; + def.Datatype = XmlSchemaDatatype.FromName ("ID"); break; case 'E': // ENTITY, ENTITIES Expect ("ENTIT"); switch(ReadChar ()) { case 'Y': // ENTITY - def.AttributeType = DTDAttributeType.Entity; + def.Datatype = XmlSchemaDatatype.FromName ("ENTITY"); break; case 'I': // ENTITIES Expect ("ES"); - def.AttributeType = DTDAttributeType.Entities; + def.Datatype = XmlSchemaDatatype.FromName ("ENTITIES"); break; } break; @@ -2351,14 +2357,14 @@ namespace System.Xml Expect ("MTOKEN"); if(PeekChar ()=='S') { // NMTOKENS ReadChar (); - def.AttributeType = DTDAttributeType.NmTokens; + def.Datatype = XmlSchemaDatatype.FromName ("NMTOKENS"); } else // NMTOKEN - def.AttributeType = DTDAttributeType.NmToken; + def.Datatype = XmlSchemaDatatype.FromName ("NMTOKEN"); break; case 'O': Expect ("OTATION"); - def.AttributeType = DTDAttributeType.Notation; + def.Datatype = XmlSchemaDatatype.FromName ("NOTATION"); SkipWhitespace (); Expect ('('); SkipWhitespace (); diff --git a/mcs/class/System.XML/System.Xml/XmlValidatingReader.cs b/mcs/class/System.XML/System.Xml/XmlValidatingReader.cs index 330793f55ad..45b8b4e14d3 100644 --- a/mcs/class/System.XML/System.Xml/XmlValidatingReader.cs +++ b/mcs/class/System.XML/System.Xml/XmlValidatingReader.cs @@ -3,13 +3,16 @@ // // Author: // Tim Coleman (tim@timcoleman.com) +// Atsushi Enomoto (ginga@kit.hi-ho.ne.jp) // // Copyright (C) Tim Coleman, 2002 +// (C)2003 Atsushi Enomoto // using System.IO; using System.Text; using System.Xml.Schema; +using Mono.Xml; namespace System.Xml { public class XmlValidatingReader : XmlReader, IXmlLineInfo { @@ -17,8 +20,9 @@ namespace System.Xml { #region Fields EntityHandling entityHandling; - bool namespaces; - XmlReader reader; + XmlReader sourceReader; + XmlReader validatingReader; + XmlResolver resolver; ValidationType validationType; #endregion // Fields @@ -29,23 +33,18 @@ namespace System.Xml { public XmlValidatingReader (XmlReader reader) : base () { - if (!(reader is XmlTextReader)) - throw new ArgumentException (); - - this.reader = reader; + this.sourceReader = reader; entityHandling = EntityHandling.ExpandEntities; - namespaces = true; validationType = ValidationType.Auto; } - [MonoTODO] public XmlValidatingReader (Stream xmlFragment, XmlNodeType fragType, XmlParserContext context) - : this (new XmlTextReader (xmlFragment)) + : this (new XmlTextReader (xmlFragment, fragType, context)) { } public XmlValidatingReader (string xmlFragment, XmlNodeType fragType, XmlParserContext context) - : this (new XmlTextReader (xmlFragment)) + : this (new XmlTextReader (xmlFragment, fragType, context)) { } @@ -55,21 +54,21 @@ namespace System.Xml { public override int AttributeCount { [MonoTODO] - get { throw new NotImplementedException (); } + get { return validatingReader == null ? 0 : validatingReader.AttributeCount; } } public override string BaseURI { [MonoTODO] - get { throw new NotImplementedException (); } + get { return validatingReader == null ? String.Empty : validatingReader.BaseURI; } } public override bool CanResolveEntity { - get { return true; } + get { return validatingReader == null ? false : validatingReader.CanResolveEntity; } } public override int Depth { [MonoTODO] - get { throw new NotImplementedException (); } + get { return validatingReader == null ? 0 : validatingReader.Depth; } } public Encoding Encoding { @@ -77,103 +76,129 @@ namespace System.Xml { get { throw new NotImplementedException (); } } + [MonoTODO] public EntityHandling EntityHandling { get { return entityHandling; } - set { entityHandling = value; } + set { + throw new NotImplementedException (); +// entityHandling = value; + } } public override bool EOF { [MonoTODO] - get { throw new NotImplementedException (); } + get { return validatingReader == null ? false : validatingReader.EOF; } } public override bool HasValue { [MonoTODO] - get { throw new NotImplementedException (); } + get { return validatingReader == null ? false : validatingReader.HasValue; } } public override bool IsDefault { [MonoTODO] - get { throw new NotImplementedException (); } + get { return validatingReader == null ? false : validatingReader.IsDefault; } } public override bool IsEmptyElement { [MonoTODO] - get { throw new NotImplementedException (); } + get { return validatingReader == null ? false : validatingReader.IsEmptyElement; } } public override string this [int i] { [MonoTODO] - get { throw new NotImplementedException (); } + get { return validatingReader [i]; } } public override string this [string name] { [MonoTODO] - get { throw new NotImplementedException (); } + get { return validatingReader == null ? String.Empty : validatingReader [name]; } } public override string this [string localName, string namespaceName] { [MonoTODO] - get { throw new NotImplementedException (); } + get { return validatingReader == null ? String.Empty : validatingReader [localName, namespaceName]; } } int IXmlLineInfo.LineNumber { - [MonoTODO] - get { throw new NotImplementedException (); } + get { + IXmlLineInfo info = validatingReader as IXmlLineInfo; + return info != null ? info.LineNumber : 0; + } } int IXmlLineInfo.LinePosition { - [MonoTODO] - get { throw new NotImplementedException (); } + get { + IXmlLineInfo info = validatingReader as IXmlLineInfo; + return info != null ? info.LinePosition : 0; + } } public override string LocalName { [MonoTODO] - get { throw new NotImplementedException (); } + get { return validatingReader == null ? String.Empty : validatingReader.LocalName; } } public override string Name { [MonoTODO] - get { throw new NotImplementedException (); } + get { return validatingReader == null ? String.Empty : validatingReader.Name; } } + [MonoTODO] public bool Namespaces { - get { return namespaces; } - set { namespaces = value; } + get { + XmlTextReader xtr = sourceReader as XmlTextReader; + if (xtr != null) + return xtr.Namespaces; + else + throw new NotImplementedException (); + } + set { + XmlTextReader xtr = sourceReader as XmlTextReader; + if (xtr != null) + xtr.Namespaces = value; + else + throw new NotImplementedException (); + } } public override string NamespaceURI { [MonoTODO] - get { throw new NotImplementedException (); } + get { return validatingReader == null ? String.Empty : validatingReader.NamespaceURI; } } public override XmlNameTable NameTable { [MonoTODO] - get { throw new NotImplementedException (); } + get { return validatingReader == null ? null : validatingReader.NameTable; } } public override XmlNodeType NodeType { [MonoTODO] - get { throw new NotImplementedException (); } + get { return validatingReader == null ? XmlNodeType.None : validatingReader.NodeType; } } public override string Prefix { [MonoTODO] - get { throw new NotImplementedException (); } + get { return validatingReader == null ? String.Empty : validatingReader.Prefix; } } public override char QuoteChar { [MonoTODO] - get { throw new NotImplementedException (); } + get { return validatingReader == null ? '"' : validatingReader.QuoteChar; } } + [MonoTODO ("confirm which reader should be returned.")] public XmlReader Reader { - get { return reader; } + get { return sourceReader; } } public override ReadState ReadState { [MonoTODO] - get { throw new NotImplementedException (); } + get { + if (validatingReader == null) + return ReadState.Initial; + return validatingReader.ReadState; + } } public XmlSchemaCollection Schemas { @@ -186,30 +211,43 @@ namespace System.Xml { get { throw new NotImplementedException (); } } + [MonoTODO] public ValidationType ValidationType { get { return validationType; } - [MonoTODO ("Need to check for exception.")] - set { validationType = value; } + set { + if (ReadState != ReadState.Initial) + throw new InvalidOperationException ("ValidationType cannot be set after the first call to Read method."); + switch (validationType) { + case ValidationType.Auto: + case ValidationType.DTD: + validationType = value; + break; + case ValidationType.None: + case ValidationType.Schema: + case ValidationType.XDR: + throw new NotImplementedException (); + } + } } public override string Value { [MonoTODO] - get { throw new NotImplementedException (); } + get { return validatingReader == null ? String.Empty : validatingReader.Value; } } public override string XmlLang { [MonoTODO] - get { throw new NotImplementedException (); } + get { return validatingReader == null ? null : validatingReader.XmlLang; } } public XmlResolver XmlResolver { [MonoTODO] - set { throw new NotImplementedException (); } + set { resolver = value; } } public override XmlSpace XmlSpace { [MonoTODO] - get { throw new NotImplementedException (); } + get { return validatingReader == null ? XmlSpace.None : validatingReader.XmlSpace; } } #endregion // Properties @@ -219,103 +257,115 @@ namespace System.Xml { [MonoTODO] public override void Close () { - throw new NotImplementedException (); + validatingReader.Close (); } [MonoTODO] public override string GetAttribute (int i) { - throw new NotImplementedException (); + return validatingReader.GetAttribute (i); } [MonoTODO] public override string GetAttribute (string name) { - throw new NotImplementedException (); + return validatingReader.GetAttribute (name); } [MonoTODO] public override string GetAttribute (string localName, string namespaceName) { - throw new NotImplementedException (); + return validatingReader.GetAttribute (localName, namespaceName); } - [MonoTODO] bool IXmlLineInfo.HasLineInfo () { - throw new NotImplementedException (); + IXmlLineInfo info = validatingReader as IXmlLineInfo; + return info != null ? info.HasLineInfo () : false; } [MonoTODO] public override string LookupNamespace (string prefix) { - throw new NotImplementedException (); + return validatingReader.LookupNamespace (prefix); } [MonoTODO] public override void MoveToAttribute (int i) { - throw new NotImplementedException (); + validatingReader.MoveToAttribute (i); } [MonoTODO] public override bool MoveToAttribute (string name) { - throw new NotImplementedException (); + return validatingReader.MoveToAttribute (name); } [MonoTODO] public override bool MoveToAttribute (string localName, string namespaceName) { - throw new NotImplementedException (); + return validatingReader.MoveToAttribute (localName, namespaceName); } [MonoTODO] public override bool MoveToElement () { - throw new NotImplementedException (); + return validatingReader.MoveToElement (); } [MonoTODO] public override bool MoveToFirstAttribute () { - throw new NotImplementedException (); + return validatingReader.MoveToFirstAttribute (); } [MonoTODO] public override bool MoveToNextAttribute () { - throw new NotImplementedException (); + return validatingReader.MoveToNextAttribute (); } [MonoTODO] public override bool Read () { - throw new NotImplementedException (); + if (ReadState == ReadState.Initial) { + switch (ValidationType) { + case ValidationType.Auto: + case ValidationType.DTD: + validatingReader = new DTDValidatingReader (sourceReader); + break; + case ValidationType.None: + case ValidationType.Schema: + case ValidationType.XDR: + throw new NotImplementedException (); + } + } + return validatingReader.Read (); } [MonoTODO] public override bool ReadAttributeValue () { - throw new NotImplementedException (); + return validatingReader.ReadAttributeValue (); } [MonoTODO] public override string ReadInnerXml () { - throw new NotImplementedException (); + return validatingReader.ReadInnerXml (); } [MonoTODO] public override string ReadOuterXml () { - throw new NotImplementedException (); + return validatingReader.ReadOuterXml (); } [MonoTODO] public override string ReadString () { - throw new NotImplementedException (); + return validatingReader.ReadString (); } [MonoTODO] |