XsdValidatingReader.cs 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805
  1. //
  2. // Mono.Xml.Schema.XsdValidatingReader.cs
  3. //
  4. // Author:
  5. // Atsushi Enomoto ([email protected])
  6. //
  7. // (C)2003 Atsushi Enomoto
  8. //
  9. // Note:
  10. //
  11. // This class doesn't support set_XmlResolver, since it isn't common to XmlReader interface.
  12. // Try to set that of xml reader which is used to construct this object.
  13. //
  14. //
  15. // Permission is hereby granted, free of charge, to any person obtaining
  16. // a copy of this software and associated documentation files (the
  17. // "Software"), to deal in the Software without restriction, including
  18. // without limitation the rights to use, copy, modify, merge, publish,
  19. // distribute, sublicense, and/or sell copies of the Software, and to
  20. // permit persons to whom the Software is furnished to do so, subject to
  21. // the following conditions:
  22. //
  23. // The above copyright notice and this permission notice shall be
  24. // included in all copies or substantial portions of the Software.
  25. //
  26. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  27. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  28. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  29. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  30. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  31. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  32. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  33. //
  34. using System;
  35. using System.Collections;
  36. using System.Collections.Specialized;
  37. using System.Text;
  38. using System.Xml;
  39. using System.Xml.Schema;
  40. using Mono.Xml;
  41. namespace Mono.Xml.Schema
  42. {
  43. internal class XsdValidatingReader : XmlReader, IXmlLineInfo, IHasXmlSchemaInfo, IHasXmlParserContext, IXmlNamespaceResolver
  44. {
  45. static char [] wsChars = new char [] {' ', '\t', '\n', '\r'};
  46. XmlReader reader;
  47. XmlValidatingReader xvReader;
  48. XmlResolver resolver;
  49. IHasXmlSchemaInfo sourceReaderSchemaInfo;
  50. IXmlLineInfo readerLineInfo;
  51. bool laxElementValidation = true;
  52. bool reportNoValidationError;
  53. XmlSchemaSet schemas = new XmlSchemaSet ();
  54. bool namespaces = true;
  55. Hashtable idList = new Hashtable ();
  56. ArrayList missingIDReferences = new ArrayList ();
  57. string thisElementId;
  58. ArrayList keyTables = new ArrayList ();
  59. ArrayList currentKeyFieldConsumers = new ArrayList ();
  60. XsdValidationStateManager stateManager = new XsdValidationStateManager ();
  61. XsdValidationContext context = new XsdValidationContext ();
  62. XsdValidationState childParticleState;
  63. int xsiNilDepth = -1;
  64. StringBuilder storedCharacters = new StringBuilder ();
  65. bool shouldValidateCharacters;
  66. int skipValidationDepth = -1;
  67. XmlSchemaAttribute [] defaultAttributes = new XmlSchemaAttribute [0];
  68. int currentDefaultAttribute = -1;
  69. XmlQualifiedName currentQName;
  70. ArrayList elementQNameStack = new ArrayList ();
  71. bool popContext;
  72. // Property Cache.
  73. int nonDefaultAttributeCount;
  74. bool defaultAttributeConsumed;
  75. // Validation engine cached object
  76. ArrayList defaultAttributesCache = new ArrayList ();
  77. ArrayList tmpKeyrefPool = new ArrayList ();
  78. #region .ctor
  79. public XsdValidatingReader (XmlReader reader)
  80. : this (reader, null)
  81. {
  82. }
  83. public XsdValidatingReader (XmlReader reader, XmlReader validatingReader)
  84. {
  85. this.reader = reader;
  86. xvReader = validatingReader as XmlValidatingReader;
  87. if (xvReader != null) {
  88. if (xvReader.ValidationType == ValidationType.None)
  89. reportNoValidationError = true;
  90. }
  91. readerLineInfo = reader as IXmlLineInfo;
  92. sourceReaderSchemaInfo = reader as IHasXmlSchemaInfo;
  93. }
  94. #endregion
  95. // Provate Properties
  96. private XmlQualifiedName CurrentQName {
  97. get {
  98. if (currentQName == null)
  99. currentQName = new XmlQualifiedName (LocalName, NamespaceURI);
  100. return currentQName;
  101. }
  102. }
  103. internal ArrayList CurrentKeyFieldConsumers {
  104. get { return currentKeyFieldConsumers; }
  105. }
  106. // Public Non-overrides
  107. public int XsiNilDepth {
  108. get { return xsiNilDepth; }
  109. }
  110. public bool Namespaces {
  111. get { return namespaces; }
  112. set { namespaces = value; }
  113. }
  114. public XmlReader Reader {
  115. get { return reader; }
  116. }
  117. // This is required to resolve xsi:schemaLocation
  118. public XmlResolver XmlResolver {
  119. set {
  120. resolver = value;
  121. }
  122. }
  123. // This should be changed before the first Read() call.
  124. public XmlSchemaSet Schemas {
  125. get { return schemas; }
  126. set {
  127. if (ReadState != ReadState.Initial)
  128. throw new InvalidOperationException ("Schemas must be set before the first call to Read().");
  129. schemas = value;
  130. }
  131. }
  132. public object SchemaType {
  133. get {
  134. if (ReadState != ReadState.Interactive)
  135. return null;
  136. switch (NodeType) {
  137. case XmlNodeType.Element:
  138. if (context.ActualType != null)
  139. return context.ActualType;
  140. else if (context.Element != null)
  141. return context.Element.ElementType;
  142. else
  143. return SourceReaderSchemaType;
  144. case XmlNodeType.Attribute:
  145. XmlSchemaComplexType ct = context.ActualType as XmlSchemaComplexType;
  146. if (ct != null) {
  147. XmlSchemaAttribute attdef = ct.AttributeUses [CurrentQName] as XmlSchemaAttribute;
  148. if (attdef != null)
  149. return attdef.AttributeType;
  150. }
  151. return SourceReaderSchemaType;
  152. default:
  153. return SourceReaderSchemaType;
  154. }
  155. }
  156. }
  157. private object SourceReaderSchemaType {
  158. get { return this.sourceReaderSchemaInfo != null ? sourceReaderSchemaInfo.SchemaType : null; }
  159. }
  160. // This property is never used in Mono.
  161. public ValidationType ValidationType {
  162. get {
  163. if (reportNoValidationError)
  164. return ValidationType.None;
  165. else
  166. return ValidationType.Schema;
  167. }
  168. }
  169. IDictionary IXmlNamespaceResolver.GetNamespacesInScope (XmlNamespaceScope scope)
  170. {
  171. IXmlNamespaceResolver resolver = reader as IXmlNamespaceResolver;
  172. if (resolver == null)
  173. throw new NotSupportedException ("The input XmlReader does not implement IXmlNamespaceResolver and thus this validating reader cannot collect in-scope namespaces.");
  174. return resolver.GetNamespacesInScope (scope);
  175. }
  176. string IXmlNamespaceResolver.LookupPrefix (string ns)
  177. {
  178. return ((IXmlNamespaceResolver) this).LookupPrefix (ns, false);
  179. }
  180. string IXmlNamespaceResolver.LookupPrefix (string ns, bool atomizedNames)
  181. {
  182. IXmlNamespaceResolver resolver = reader as IXmlNamespaceResolver;
  183. if (resolver == null)
  184. throw new NotSupportedException ("The input XmlReader does not implement IXmlNamespaceResolver and thus this validating reader cannot execute namespace prefix lookup.");
  185. return resolver.LookupPrefix (ns, atomizedNames);
  186. }
  187. // It is used only for independent XmlReader use, not for XmlValidatingReader.
  188. #if NET_2_0
  189. public override object ReadTypedValue ()
  190. #else
  191. public object ReadTypedValue ()
  192. #endif
  193. {
  194. XmlSchemaDatatype dt = SchemaType as XmlSchemaDatatype;
  195. XmlSchemaSimpleType st = SchemaType as XmlSchemaSimpleType;
  196. if (st != null)
  197. dt = st.Datatype;
  198. if (dt == null)
  199. return null;
  200. switch (NodeType) {
  201. case XmlNodeType.Element:
  202. if (IsEmptyElement)
  203. return null;
  204. storedCharacters.Length = 0;
  205. bool loop = true;
  206. do {
  207. Read ();
  208. switch (NodeType) {
  209. case XmlNodeType.SignificantWhitespace:
  210. case XmlNodeType.Text:
  211. case XmlNodeType.CDATA:
  212. storedCharacters.Append (Value);
  213. break;
  214. case XmlNodeType.Comment:
  215. break;
  216. default:
  217. loop = false;
  218. break;
  219. }
  220. } while (loop && !EOF && ReadState == ReadState.Interactive);
  221. return dt.ParseValue (storedCharacters.ToString (), NameTable, ParserContext.NamespaceManager);
  222. case XmlNodeType.Attribute:
  223. return dt.ParseValue (Value, NameTable, ParserContext.NamespaceManager);
  224. }
  225. return null;
  226. }
  227. public ValidationEventHandler ValidationEventHandler;
  228. // Public Overrided Properties
  229. public override int AttributeCount {
  230. get {
  231. return nonDefaultAttributeCount + defaultAttributes.Length;
  232. }
  233. }
  234. public override string BaseURI {
  235. get { return reader.BaseURI; }
  236. }
  237. // If this class is used to implement XmlValidatingReader,
  238. // it should be left to DTDValidatingReader. In other cases,
  239. // it depends on the reader's ability.
  240. public override bool CanResolveEntity {
  241. get { return reader.CanResolveEntity; }
  242. }
  243. public override int Depth {
  244. get {
  245. if (currentDefaultAttribute < 0)
  246. return reader.Depth;
  247. if (this.defaultAttributeConsumed)
  248. return reader.Depth + 2;
  249. return reader.Depth + 1;
  250. }
  251. }
  252. public override bool EOF {
  253. get { return reader.EOF; }
  254. }
  255. public override bool HasValue {
  256. get {
  257. if (currentDefaultAttribute < 0)
  258. return reader.HasValue;
  259. return true;
  260. }
  261. }
  262. public override bool IsDefault {
  263. get {
  264. if (currentDefaultAttribute < 0)
  265. return reader.IsDefault;
  266. return true;
  267. }
  268. }
  269. public override bool IsEmptyElement {
  270. get {
  271. if (currentDefaultAttribute < 0)
  272. return reader.IsEmptyElement;
  273. return false;
  274. }
  275. }
  276. public override string this [int i] {
  277. get { return GetAttribute (i); }
  278. }
  279. public override string this [string name] {
  280. get { return GetAttribute (name); }
  281. }
  282. public override string this [string localName, string ns] {
  283. get { return GetAttribute (localName, ns); }
  284. }
  285. int IXmlLineInfo.LineNumber {
  286. get { return readerLineInfo != null ? readerLineInfo.LineNumber : 0; }
  287. }
  288. int IXmlLineInfo.LinePosition {
  289. get { return readerLineInfo != null ? readerLineInfo.LinePosition : 0; }
  290. }
  291. public override string LocalName {
  292. get {
  293. if (currentDefaultAttribute < 0)
  294. return reader.LocalName;
  295. if (defaultAttributeConsumed)
  296. return String.Empty;
  297. return defaultAttributes [currentDefaultAttribute].QualifiedName.Name;
  298. }
  299. }
  300. public override string Name {
  301. get {
  302. if (currentDefaultAttribute < 0)
  303. return reader.Name;
  304. if (defaultAttributeConsumed)
  305. return String.Empty;
  306. XmlQualifiedName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
  307. string prefix = Prefix;
  308. if (prefix == String.Empty)
  309. return qname.Name;
  310. else
  311. return String.Concat (prefix, ":", qname.Name);
  312. }
  313. }
  314. public override string NamespaceURI {
  315. get {
  316. if (currentDefaultAttribute < 0)
  317. return reader.NamespaceURI;
  318. if (defaultAttributeConsumed)
  319. return String.Empty;
  320. return defaultAttributes [currentDefaultAttribute].QualifiedName.Namespace;
  321. }
  322. }
  323. public override XmlNameTable NameTable {
  324. get { return reader.NameTable; }
  325. }
  326. public override XmlNodeType NodeType {
  327. get {
  328. if (currentDefaultAttribute < 0)
  329. return reader.NodeType;
  330. if (defaultAttributeConsumed)
  331. return XmlNodeType.Text;
  332. return XmlNodeType.Attribute;
  333. }
  334. }
  335. public XmlParserContext ParserContext {
  336. get { return XmlSchemaUtil.GetParserContext (reader); }
  337. }
  338. public override string Prefix {
  339. get {
  340. if (currentDefaultAttribute < 0)
  341. return reader.Prefix;
  342. if (defaultAttributeConsumed)
  343. return String.Empty;
  344. XmlQualifiedName qname = defaultAttributes [currentDefaultAttribute].QualifiedName;
  345. string prefix = this.ParserContext.NamespaceManager.LookupPrefix (qname.Namespace, false);
  346. if (prefix == null)
  347. return String.Empty;
  348. else
  349. return prefix;
  350. }
  351. }
  352. public override char QuoteChar {
  353. get { return reader.QuoteChar; }
  354. }
  355. public override ReadState ReadState {
  356. get { return reader.ReadState; }
  357. }
  358. public override string Value {
  359. get {
  360. if (currentDefaultAttribute < 0)
  361. return reader.Value;
  362. string value = defaultAttributes [currentDefaultAttribute].ValidatedDefaultValue;
  363. if (value == null)
  364. value = defaultAttributes [currentDefaultAttribute].ValidatedFixedValue;
  365. return value;
  366. }
  367. }
  368. XmlQualifiedName qnameXmlLang = new XmlQualifiedName ("lang", XmlNamespaceManager.XmlnsXml);
  369. public override string XmlLang {
  370. get {
  371. string xmlLang = reader.XmlLang;
  372. if (xmlLang != null)
  373. return xmlLang;
  374. int idx = this.FindDefaultAttribute ("lang", XmlNamespaceManager.XmlnsXml);
  375. if (idx < 0)
  376. return null;
  377. xmlLang = defaultAttributes [idx].ValidatedDefaultValue;
  378. if (xmlLang == null)
  379. xmlLang = defaultAttributes [idx].ValidatedFixedValue;
  380. return xmlLang;
  381. }
  382. }
  383. public override XmlSpace XmlSpace {
  384. get {
  385. XmlSpace space = reader.XmlSpace;
  386. if (space != XmlSpace.None)
  387. return space;
  388. int idx = this.FindDefaultAttribute ("space", XmlNamespaceManager.XmlnsXml);
  389. if (idx < 0)
  390. return XmlSpace.None;
  391. string spaceSpec = defaultAttributes [idx].ValidatedDefaultValue;
  392. if (spaceSpec == null)
  393. spaceSpec = defaultAttributes [idx].ValidatedFixedValue;
  394. return (XmlSpace) Enum.Parse (typeof (XmlSpace), spaceSpec, false);
  395. }
  396. }
  397. // Private Methods
  398. private XmlQualifiedName QualifyName (string name)
  399. {
  400. return XmlQualifiedName.Parse (name, this);
  401. }
  402. private void HandleError (string error)
  403. {
  404. HandleError (error, null);
  405. }
  406. private void HandleError (string error, Exception innerException)
  407. {
  408. HandleError (error, innerException, false);
  409. }
  410. private void HandleError (string error, Exception innerException, bool isWarning)
  411. {
  412. if (reportNoValidationError) // extra quick check
  413. return;
  414. XmlSchemaException schemaException = new XmlSchemaException (error,
  415. this, this.BaseURI, null, innerException);
  416. HandleError (schemaException, isWarning);
  417. }
  418. private void HandleError (XmlSchemaException schemaException)
  419. {
  420. HandleError (schemaException, false);
  421. }
  422. private void HandleError (XmlSchemaException schemaException, bool isWarning)
  423. {
  424. if (reportNoValidationError)
  425. return;
  426. ValidationEventArgs e = new ValidationEventArgs (schemaException,
  427. schemaException.Message, isWarning ? XmlSeverityType.Warning : XmlSeverityType.Error);
  428. if (this.ValidationEventHandler != null)
  429. this.ValidationEventHandler (this, e);
  430. else if (xvReader != null)
  431. xvReader.OnValidationEvent (this, e);
  432. else if (e.Severity == XmlSeverityType.Error)
  433. #if NON_MONO_ENV
  434. this.xvReader.OnValidationEvent (this, e);
  435. #else
  436. throw e.Exception;
  437. #endif
  438. }
  439. private XmlSchemaElement FindElement (string name, string ns)
  440. {
  441. return (XmlSchemaElement) schemas.GlobalElements [new XmlQualifiedName (name, ns)];
  442. }
  443. private XmlSchemaType FindType (XmlQualifiedName qname)
  444. {
  445. return (XmlSchemaType) schemas.GlobalTypes [qname];
  446. }
  447. private void ValidateStartElementParticle ()
  448. {
  449. stateManager.CurrentElement = null;
  450. context.ParticleState = context.ParticleState.EvaluateStartElement (reader.LocalName, reader.NamespaceURI);
  451. if (context.ParticleState == XsdValidationState.Invalid)
  452. HandleError ("Invalid start element: " + reader.NamespaceURI + ":" + reader.LocalName);
  453. context.Element = stateManager.CurrentElement;
  454. if (context.Element != null)
  455. context.SchemaType = context.Element.ElementType;
  456. }
  457. private void ValidateEndElementParticle ()
  458. {
  459. if (childParticleState != null) {
  460. if (!childParticleState.EvaluateEndElement ()) {
  461. HandleError ("Invalid end element: " + reader.Name);
  462. }
  463. }
  464. context.PopScope (reader.Depth);
  465. }
  466. // Utility for missing validation completion related to child items.
  467. private void ValidateCharacters ()
  468. {
  469. if (xsiNilDepth >= 0 && xsiNilDepth < reader.Depth)
  470. HandleError ("Element item appeared, while current element context is nil.");
  471. storedCharacters.Append (reader.Value);
  472. }
  473. // Utility for missing validation completion related to child items.
  474. private void ValidateEndCharacters ()
  475. {
  476. if (context.ActualType == null)
  477. return;
  478. string value = storedCharacters.ToString ();
  479. if (storedCharacters.Length == 0) {
  480. // 3.3.4 Element Locally Valid (Element) 5.1.2
  481. if (context.Element != null) {
  482. if (context.Element.ValidatedDefaultValue != null)
  483. value = context.Element.ValidatedDefaultValue;
  484. }
  485. }
  486. XmlSchemaDatatype dt = context.ActualType as XmlSchemaDatatype;
  487. XmlSchemaSimpleType st = context.ActualType as XmlSchemaSimpleType;
  488. if (dt == null) {
  489. if (st != null) {
  490. dt = st.Datatype;
  491. } else {
  492. XmlSchemaComplexType ct = context.ActualType as XmlSchemaComplexType;
  493. dt = ct.Datatype;
  494. switch (ct.ContentType) {
  495. case XmlSchemaContentType.ElementOnly:
  496. case XmlSchemaContentType.Empty:
  497. if (storedCharacters.Length > 0)
  498. HandleError ("Character content not allowed.");
  499. break;
  500. }
  501. }
  502. }
  503. if (dt != null) {
  504. // 3.3.4 Element Locally Valid (Element) :: 5.2.2.2. Fixed value constraints
  505. if (context.Element != null && context.Element.ValidatedFixedValue != null)
  506. if (value != context.Element.ValidatedFixedValue)
  507. HandleError ("Fixed value constraint was not satisfied.");
  508. AssessStringValid (st, dt, value);
  509. }
  510. // Identity field value
  511. while (this.currentKeyFieldConsumers.Count > 0) {
  512. XsdKeyEntryField field = this.currentKeyFieldConsumers [0] as XsdKeyEntryField;
  513. if (field.Identity != null)
  514. HandleError ("Two or more identical field was found. Former value is '" + field.Identity + "' .");
  515. object identity = null; // This means empty value
  516. if (dt != null) {
  517. try {
  518. identity = dt.ParseValue (value, NameTable, ParserContext.NamespaceManager);
  519. } catch (Exception ex) { // FIXME: (wishlist) This is bad manner ;-(
  520. HandleError ("Identity value is invalid against its data type " + dt.TokenizedType, ex);
  521. }
  522. }
  523. if (identity == null)
  524. identity = value;
  525. if (!field.SetIdentityField (identity, reader.Depth == xsiNilDepth, dt as XsdAnySimpleType, this))
  526. HandleError ("Two or more identical key value was found: '" + value + "' .");
  527. this.currentKeyFieldConsumers.RemoveAt (0);
  528. }
  529. shouldValidateCharacters = false;
  530. }
  531. // 3.14.4 String Valid
  532. private void AssessStringValid (XmlSchemaSimpleType st,
  533. XmlSchemaDatatype dt, string value)
  534. {
  535. XmlSchemaDatatype validatedDatatype = dt;
  536. if (st != null) {
  537. string normalized = validatedDatatype.Normalize (value);
  538. string [] values;
  539. XmlSchemaDatatype itemDatatype;
  540. XmlSchemaSimpleType itemSimpleType;
  541. switch (st.DerivedBy) {
  542. case XmlSchemaDerivationMethod.List:
  543. XmlSchemaSimpleTypeList listContent = st.Content as XmlSchemaSimpleTypeList;
  544. values = normalized.Split (wsChars);
  545. itemDatatype = listContent.ValidatedListItemType as XmlSchemaDatatype;
  546. itemSimpleType = listContent.ValidatedListItemType as XmlSchemaSimpleType;
  547. for (int vi = 0; vi < values.Length; vi++) {
  548. string each = values [vi];
  549. if (each == String.Empty)
  550. continue;
  551. // validate against ValidatedItemType
  552. if (itemDatatype != null) {
  553. try {
  554. itemDatatype.ParseValue (each, NameTable, ParserContext.NamespaceManager);
  555. } catch (Exception ex) { // FIXME: (wishlist) better exception handling ;-(
  556. HandleError ("List type value contains one or more invalid values.", ex);
  557. break;
  558. }
  559. }
  560. else
  561. AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
  562. }
  563. break;
  564. case XmlSchemaDerivationMethod.Union:
  565. XmlSchemaSimpleTypeUnion union = st.Content as XmlSchemaSimpleTypeUnion;
  566. {
  567. string each = normalized;
  568. // validate against ValidatedItemType
  569. bool passed = false;
  570. foreach (object eachType in union.ValidatedTypes) {
  571. itemDatatype = eachType as XmlSchemaDatatype;
  572. itemSimpleType = eachType as XmlSchemaSimpleType;
  573. if (itemDatatype != null) {
  574. try {
  575. itemDatatype.ParseValue (each, NameTable, ParserContext.NamespaceManager);
  576. } catch (Exception) { // FIXME: (wishlist) better exception handling ;-(
  577. continue;
  578. }
  579. }
  580. else {
  581. try {
  582. AssessStringValid (itemSimpleType, itemSimpleType.Datatype, each);
  583. } catch (XmlSchemaException) {
  584. continue;
  585. }
  586. }
  587. passed = true;
  588. break;
  589. }
  590. if (!passed) {
  591. HandleError ("Union type value contains one or more invalid values.");
  592. break;
  593. }
  594. }
  595. break;
  596. case XmlSchemaDerivationMethod.Restriction:
  597. XmlSchemaSimpleTypeRestriction str = st.Content as XmlSchemaSimpleTypeRestriction;
  598. // facet validation
  599. if (str != null) {
  600. /* Don't forget to validate against inherited type's facets
  601. * Could we simplify this by assuming that the basetype will also
  602. * be restriction?
  603. * */
  604. // mmm, will check later.
  605. XmlSchemaSimpleType baseType = st.BaseXmlSchemaType as XmlSchemaSimpleType;
  606. if (baseType != null) {
  607. AssessStringValid(baseType, dt, normalized);
  608. }
  609. if (!str.ValidateValueWithFacets (normalized, NameTable)) {
  610. HandleError ("Specified value was invalid against the facets.");
  611. break;
  612. }
  613. }
  614. validatedDatatype = st.Datatype;
  615. break;
  616. }
  617. }
  618. if (validatedDatatype != null) {
  619. try {
  620. validatedDatatype.ParseValue (value, NameTable, ParserContext.NamespaceManager);
  621. } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
  622. HandleError ("Invalidly typed data was specified.", ex);
  623. }
  624. }
  625. }
  626. private object GetLocalTypeDefinition (string name)
  627. {
  628. object xsiType = null;
  629. XmlQualifiedName typeQName = QualifyName (name);
  630. if (typeQName == XmlSchemaComplexType.AnyTypeName)
  631. xsiType = XmlSchemaComplexType.AnyType;
  632. else if (XmlSchemaUtil.IsBuiltInDatatypeName (typeQName))
  633. xsiType = XmlSchemaDatatype.FromName (typeQName);
  634. else
  635. xsiType = FindType (typeQName);
  636. return xsiType;
  637. }
  638. // It is common to ElementLocallyValid::4 and SchemaValidityAssessment::1.2.1.2.4
  639. private void AssessLocalTypeDerivationOK (object xsiType, object baseType, XmlSchemaDerivationMethod flag)
  640. {
  641. XmlSchemaType xsiSchemaType = xsiType as XmlSchemaType;
  642. XmlSchemaComplexType baseComplexType = baseType as XmlSchemaComplexType;
  643. XmlSchemaComplexType xsiComplexType = xsiSchemaType as XmlSchemaComplexType;
  644. if (xsiType != baseType) {
  645. // Extracted (not extraneous) check for 3.4.6 TypeDerivationOK.
  646. if (baseComplexType != null)
  647. flag |= baseComplexType.BlockResolved;
  648. if (flag == XmlSchemaDerivationMethod.All) {
  649. HandleError ("Prohibited element type substitution.");
  650. return;
  651. } else if (xsiSchemaType != null && (flag & xsiSchemaType.DerivedBy) != 0) {
  652. HandleError ("Prohibited element type substitution.");
  653. return;
  654. }
  655. }
  656. if (xsiComplexType != null)
  657. try {
  658. xsiComplexType.ValidateTypeDerivationOK (baseType, null, null);
  659. } catch (XmlSchemaException ex) {
  660. // HandleError ("Locally specified schema complex type derivation failed. " + ex.Message, ex);
  661. HandleError (ex);
  662. }
  663. else {
  664. XmlSchemaSimpleType xsiSimpleType = xsiType as XmlSchemaSimpleType;
  665. if (xsiSimpleType != null) {
  666. try {
  667. xsiSimpleType.ValidateTypeDerivationOK (baseType, null, null, true);
  668. } catch (XmlSchemaException ex) {
  669. // HandleError ("Locally specified schema simple type derivation failed. " + ex.Message, ex);
  670. HandleError (ex);
  671. }
  672. }
  673. else if (xsiType is XmlSchemaDatatype) {
  674. // do nothing
  675. }
  676. else
  677. HandleError ("Primitive data type cannot be derived type using xsi:type specification.");
  678. }
  679. }
  680. // Section 3.3.4 of the spec.
  681. private void AssessStartElementSchemaValidity ()
  682. {
  683. // If the reader is inside xsi:nil (and failed on validation),
  684. // then simply skip its content.
  685. if (xsiNilDepth >= 0 && xsiNilDepth < reader.Depth)
  686. HandleError ("Element item appeared, while current element context is nil.");
  687. context.Load (reader.Depth);
  688. if (childParticleState != null) {
  689. context.ParticleState = childParticleState;
  690. childParticleState = null;
  691. }
  692. // If validation state exists, then first assess particle validity.
  693. context.SchemaType = null;
  694. if (context.ParticleState != null) {
  695. ValidateStartElementParticle ();
  696. }
  697. string xsiNilValue = reader.GetAttribute ("nil", XmlSchema.InstanceNamespace);
  698. if (xsiNilValue != null)
  699. xsiNilValue = xsiNilValue.Trim (XmlChar.WhitespaceChars);
  700. bool isXsiNil = xsiNilValue == "true";
  701. if (isXsiNil && this.xsiNilDepth < 0)
  702. xsiNilDepth = reader.Depth;
  703. // [Schema Validity Assessment (Element) 1.2]
  704. // Evaluate "local type definition" from xsi:type.
  705. // (See spec 3.3.4 Schema Validity Assessment (Element) 1.2.1.2.3.
  706. // Note that Schema Validity Assessment(Element) 1.2 takes
  707. // precedence than 1.1 of that.
  708. string xsiTypeName = reader.GetAttribute ("type", XmlSchema.InstanceNamespace);
  709. if (xsiTypeName != null) {
  710. xsiTypeName = xsiTypeName.Trim (XmlChar.WhitespaceChars);
  711. object xsiType = GetLocalTypeDefinition (xsiTypeName);
  712. if (xsiType == null)
  713. HandleError ("The instance type was not found: " + xsiTypeName + " .");
  714. else {
  715. XmlSchemaType xsiSchemaType = xsiType as XmlSchemaType;
  716. if (xsiSchemaType != null && this.context.Element != null) {
  717. XmlSchemaType elemBaseType = context.Element.ElementType as XmlSchemaType;
  718. if (elemBaseType != null && (xsiSchemaType.DerivedBy & elemBaseType.FinalResolved) != 0)
  719. HandleError ("The instance type is prohibited by the type of the context element.");
  720. if (elemBaseType != xsiType && (xsiSchemaType.DerivedBy & this.context.Element.BlockResolved) != 0)
  721. HandleError ("The instance type is prohibited by the context element.");
  722. }
  723. XmlSchemaComplexType xsiComplexType = xsiType as XmlSchemaComplexType;
  724. if (xsiComplexType != null && xsiComplexType.IsAbstract)
  725. HandleError ("The instance type is abstract: " + xsiTypeName + " .");
  726. else {
  727. // If current schema type exists, then this xsi:type must be
  728. // valid extension of that type. See 1.2.1.2.4.
  729. if (context.Element != null) {
  730. AssessLocalTypeDerivationOK (xsiType, context.Element.ElementType, context.Element.BlockResolved);
  731. }
  732. AssessStartElementLocallyValidType (xsiType); // 1.2.2:
  733. context.LocalTypeDefinition = xsiType;
  734. }
  735. }
  736. }
  737. else
  738. context.LocalTypeDefinition = null;
  739. // Create Validation Root, if not exist.
  740. // [Schema Validity Assessment (Element) 1.1]
  741. if (context.Element == null)
  742. context.Element = FindElement (reader.LocalName, reader.NamespaceURI);
  743. if (context.Element != null) {
  744. if (xsiTypeName == null) {
  745. context.SchemaType = context.Element.ElementType;
  746. AssessElementLocallyValidElement (context.Element, xsiNilValue); // 1.1.2
  747. }
  748. } else {
  749. XmlSchema schema;
  750. switch (stateManager.ProcessContents) {
  751. case XmlSchemaContentProcessing.Skip:
  752. break;
  753. case XmlSchemaContentProcessing.Lax:
  754. /*
  755. schema = schemas [reader.NamespaceURI];
  756. if (schema != null && !schema.missedSubComponents)
  757. HandleError ("Element declaration for " + reader.LocalName + " is missing.");
  758. */
  759. break;
  760. default:
  761. if (xsiTypeName == null &&
  762. (schemas.Contains (reader.NamespaceURI) ||
  763. !schemas.MissedSubComponents (reader.NamespaceURI)))
  764. HandleError ("Element declaration for " + reader.LocalName + " is missing.");
  765. break;
  766. }
  767. }
  768. if (stateManager.ProcessContents == XmlSchemaContentProcessing.Skip)
  769. skipValidationDepth = reader.Depth;
  770. // Finally, create child particle state.
  771. XmlSchemaComplexType xsComplexType = SchemaType as XmlSchemaComplexType;
  772. if (xsComplexType != null)
  773. childParticleState = stateManager.Create (xsComplexType.ValidatableParticle);
  774. else if (stateManager.ProcessContents == XmlSchemaContentProcessing.Lax)
  775. childParticleState = stateManager.Create (XmlSchemaAny.AnyTypeContent);
  776. else
  777. childParticleState = stateManager.Create (XmlSchemaParticle.Empty);
  778. AssessStartIdentityConstraints ();
  779. context.PushScope (reader.Depth);
  780. }
  781. // 3.3.4 Element Locally Valid (Element)
  782. private void AssessElementLocallyValidElement (XmlSchemaElement element, string xsiNilValue)
  783. {
  784. XmlQualifiedName qname = new XmlQualifiedName (reader.LocalName, reader.NamespaceURI);
  785. // 1.
  786. if (element == null)
  787. HandleError ("Element declaration is required for " + qname);
  788. // 2.
  789. if (element.ActualIsAbstract)
  790. HandleError ("Abstract element declaration was specified for " + qname);
  791. // 3.1.
  792. if (!element.ActualIsNillable && xsiNilValue != null)
  793. HandleError ("This element declaration is not nillable: " + qname);
  794. // 3.2.
  795. // Note that 3.2.1 xsi:nil constraints are to be validated in
  796. else if (xsiNilValue == "true") {
  797. // AssessElementSchemaValidity() and ValidateCharacters()
  798. if (element.ValidatedFixedValue != null)
  799. HandleError ("Schema instance nil was specified, where the element declaration for " + qname + "has fixed value constraints.");
  800. }
  801. // 4.
  802. string xsiType = reader.GetAttribute ("type", XmlSchema.InstanceNamespace);
  803. if (xsiType != null) {
  804. context.LocalTypeDefinition = GetLocalTypeDefinition (xsiType);
  805. AssessLocalTypeDerivationOK (context.LocalTypeDefinition, element.ElementType, element.BlockResolved);
  806. }
  807. else
  808. context.LocalTypeDefinition = null;
  809. // 5 Not all things cannot be assessed here.
  810. // It is common to 5.1 and 5.2
  811. if (element.ElementType != null)
  812. AssessStartElementLocallyValidType (SchemaType);
  813. // 6. should be out from here.
  814. // See invokation of AssessStartIdentityConstraints().
  815. // 7 is going to be validated in Read() (in case of xmlreader's EOF).
  816. }
  817. // 3.3.4 Element Locally Valid (Type)
  818. private void AssessStartElementLocallyValidType (object schemaType)
  819. {
  820. if (schemaType == null) { // 1.
  821. HandleError ("Schema type does not exist.");
  822. return;
  823. }
  824. XmlSchemaComplexType cType = schemaType as XmlSchemaComplexType;
  825. XmlSchemaSimpleType sType = schemaType as XmlSchemaSimpleType;
  826. if (sType != null) {
  827. // 3.1.1.
  828. while (reader.MoveToNextAttribute ()) {
  829. if (reader.NamespaceURI == XmlNamespaceManager.XmlnsXmlns)
  830. continue;
  831. if (reader.NamespaceURI != XmlSchema.InstanceNamespace)
  832. HandleError ("Current simple type cannot accept attributes other than schema instance namespace.");
  833. switch (reader.LocalName) {
  834. case "type":
  835. case "nil":
  836. case "schemaLocation":
  837. case "noNamespaceSchemaLocation":
  838. break;
  839. default:
  840. HandleError ("Unknown schema instance namespace attribute: " + reader.LocalName);
  841. break;
  842. }
  843. }
  844. reader.MoveToElement ();
  845. // 3.1.2 and 3.1.3 cannot be assessed here.
  846. } else if (cType != null) {
  847. if (cType.IsAbstract) { // 2.
  848. HandleError ("Target complex type is abstract.");
  849. return;
  850. }
  851. // 3.2
  852. AssessElementLocallyValidComplexType (cType);
  853. }
  854. }
  855. // 3.4.4 Element Locally Valid (Complex Type)
  856. private void AssessElementLocallyValidComplexType (XmlSchemaComplexType cType)
  857. {
  858. // 1.
  859. if (cType.IsAbstract)
  860. HandleError ("Target complex type is abstract.");
  861. // 2 (xsi:nil and content prohibition)
  862. // See AssessStartElementSchemaValidity() and ValidateCharacters()
  863. string elementNs = reader.NamespaceURI;
  864. // 3. attribute uses and
  865. // 5. wild IDs
  866. while (reader.MoveToNextAttribute ()) {
  867. if (reader.NamespaceURI == "http://www.w3.org/2000/xmlns/")
  868. continue;
  869. else if (reader.NamespaceURI == XmlSchema.InstanceNamespace)
  870. continue;
  871. XmlQualifiedName qname = new XmlQualifiedName (reader.LocalName, reader.NamespaceURI);
  872. XmlSchemaObject attMatch = FindAttributeDeclaration (cType, qname, elementNs);
  873. if (attMatch == null)
  874. HandleError ("Attribute declaration was not found for " + qname);
  875. else {
  876. XmlSchemaAttribute attdecl = attMatch as XmlSchemaAttribute;
  877. if (attdecl == null) { // i.e. anyAttribute
  878. XmlSchemaAnyAttribute anyAttrMatch = attMatch as XmlSchemaAnyAttribute;
  879. } else {
  880. AssessAttributeLocallyValidUse (attdecl);
  881. AssessAttributeLocallyValid (attdecl, true);
  882. }
  883. }
  884. }
  885. reader.MoveToElement ();
  886. // Collect default attributes.
  887. // 4.
  888. foreach (DictionaryEntry entry in cType.AttributeUses) {
  889. XmlSchemaAttribute attr = (XmlSchemaAttribute) entry.Value;
  890. if (reader [attr.QualifiedName.Name, attr.QualifiedName.Namespace] == null) {
  891. if (attr.ValidatedUse == XmlSchemaUse.Required &&
  892. attr.ValidatedFixedValue == null)
  893. HandleError ("Required attribute " + attr.QualifiedName + " was not found.");
  894. else if (attr.ValidatedDefaultValue != null)
  895. defaultAttributesCache.Add (attr);
  896. else if (attr.ValidatedFixedValue != null)
  897. defaultAttributesCache.Add (attr);
  898. }
  899. }
  900. defaultAttributes = (XmlSchemaAttribute [])
  901. defaultAttributesCache.ToArray (typeof (XmlSchemaAttribute));
  902. context.DefaultAttributes = defaultAttributes;
  903. defaultAttributesCache.Clear ();
  904. // 5. wild IDs was already checked above.
  905. }
  906. // Spec 3.10.4 Item Valid (Wildcard)
  907. private bool AttributeWildcardItemValid (XmlSchemaAnyAttribute anyAttr, XmlQualifiedName qname)
  908. {
  909. if (anyAttr.HasValueAny)
  910. return true;
  911. if (anyAttr.HasValueOther && (anyAttr.TargetNamespace == "" || reader.NamespaceURI != anyAttr.TargetNamespace))
  912. return true;
  913. if (anyAttr.HasValueTargetNamespace && reader.NamespaceURI == anyAttr.TargetNamespace)
  914. return true;
  915. if (anyAttr.HasValueLocal && reader.NamespaceURI == "")
  916. return true;
  917. for (int i = 0; i < anyAttr.ResolvedNamespaces.Count; i++)
  918. if (anyAttr.ResolvedNamespaces [i] == reader.NamespaceURI)
  919. return true;
  920. return false;
  921. }
  922. private XmlSchemaObject FindAttributeDeclaration (
  923. XmlSchemaComplexType cType,
  924. XmlQualifiedName qname,
  925. string elementNs)
  926. {
  927. XmlSchemaObject result = cType.AttributeUses [qname];
  928. if (result != null)
  929. return result;
  930. if (cType.AttributeWildcard == null)
  931. return null;
  932. if (!AttributeWildcardItemValid (cType.AttributeWildcard, qname))
  933. return null;
  934. if (cType.AttributeWildcard.ResolvedProcessContents == XmlSchemaContentProcessing.Skip)
  935. return cType.AttributeWildcard;
  936. XmlSchemaAttribute attr = schemas.GlobalAttributes [qname] as XmlSchemaAttribute;
  937. if (attr != null)
  938. return attr;
  939. if (cType.AttributeWildcard.ResolvedProcessContents == XmlSchemaContentProcessing.Lax)
  940. return cType.AttributeWildcard;
  941. else
  942. return null;
  943. }
  944. // 3.2.4 Attribute Locally Valid and 3.4.4 - 5.wildIDs
  945. private void AssessAttributeLocallyValid (XmlSchemaAttribute attr, bool checkWildIDs)
  946. {
  947. // 1.
  948. switch (reader.NamespaceURI) {
  949. case XmlNamespaceManager.XmlnsXml:
  950. case XmlNamespaceManager.XmlnsXmlns:
  951. case XmlSchema.InstanceNamespace:
  952. break;
  953. }
  954. // 2. - 4.
  955. if (attr.AttributeType == null)
  956. HandleError ("Attribute type is missing for " + attr.QualifiedName);
  957. XmlSchemaDatatype dt = attr.AttributeType as XmlSchemaDatatype;
  958. if (dt == null)
  959. dt = ((XmlSchemaSimpleType) attr.AttributeType).Datatype;
  960. // It is a bit heavy process, so let's omit as long as possible ;-)
  961. if (dt != XmlSchemaSimpleType.AnySimpleType || attr.ValidatedFixedValue != null) {
  962. string normalized = dt.Normalize (reader.Value);
  963. object parsedValue = null;
  964. try {
  965. parsedValue = dt.ParseValue (normalized, reader.NameTable, this.ParserContext.NamespaceManager);
  966. } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
  967. HandleError ("Attribute value is invalid against its data type " + dt.TokenizedType, ex);
  968. }
  969. if (attr.ValidatedFixedValue != null && attr.ValidatedFixedValue != normalized)
  970. HandleError ("The value of the attribute " + attr.QualifiedName + " does not match with its fixed value.");
  971. if (checkWildIDs)
  972. AssessEachAttributeIdentityConstraint (dt, normalized, parsedValue);
  973. }
  974. }
  975. private void AssessEachAttributeIdentityConstraint (XmlSchemaDatatype dt,
  976. string normalized, object parsedValue)
  977. {
  978. // Get normalized value and (if required) parsedValue if missing.
  979. switch (dt.TokenizedType) {
  980. case XmlTokenizedType.IDREFS:
  981. if (normalized == null)
  982. normalized = dt.Normalize (reader.Value);
  983. if (parsedValue == null)
  984. parsedValue = dt.ParseValue (normalized, reader.NameTable, ParserContext.NamespaceManager);
  985. break;
  986. case XmlTokenizedType.ID:
  987. case XmlTokenizedType.IDREF:
  988. if (normalized == null)
  989. normalized = dt.Normalize (reader.Value);
  990. break;
  991. }
  992. // Validate identity constraints.
  993. switch (dt.TokenizedType) {
  994. case XmlTokenizedType.ID:
  995. if (thisElementId != null)
  996. HandleError ("ID type attribute was already assigned in the containing element.");
  997. thisElementId = normalized;
  998. if (idList.Contains (normalized))
  999. HandleError ("Duplicate ID value was found.");
  1000. else
  1001. idList.Add (normalized, normalized);
  1002. if (missingIDReferences.Contains (normalized))
  1003. missingIDReferences.Remove (normalized);
  1004. break;
  1005. case XmlTokenizedType.IDREF:
  1006. if (!idList.Contains (normalized))
  1007. missingIDReferences.Add (normalized);
  1008. break;
  1009. case XmlTokenizedType.IDREFS:
  1010. string [] idrefs = (string []) parsedValue;
  1011. for (int i = 0; i < idrefs.Length; i++) {
  1012. string id = idrefs [i];
  1013. if (!idList.Contains (id))
  1014. missingIDReferences.Add (id);
  1015. }
  1016. break;
  1017. }
  1018. }
  1019. private void AssessAttributeLocallyValidUse (XmlSchemaAttribute attr)
  1020. {
  1021. // This is extra check than spec 3.5.4
  1022. if (attr.ValidatedUse == XmlSchemaUse.Prohibited)
  1023. HandleError ("Attribute " + attr.QualifiedName + " is prohibited in this context.");
  1024. }
  1025. private void AssessEndElementSchemaValidity ()
  1026. {
  1027. if (childParticleState == null)
  1028. childParticleState = context.ParticleState;
  1029. ValidateEndElementParticle (); // validate against childrens' state.
  1030. if (shouldValidateCharacters) {
  1031. ValidateEndCharacters ();
  1032. shouldValidateCharacters = false;
  1033. }
  1034. // 3.3.4 Assess ElementLocallyValidElement 5: value constraints.
  1035. // 3.3.4 Assess ElementLocallyValidType 3.1.3. = StringValid(3.14.4)
  1036. // => ValidateEndCharacters().
  1037. // Reset Identity constraints.
  1038. for (int i = 0; i < keyTables.Count; i++) {
  1039. XsdKeyTable keyTable = this.keyTables [i] as XsdKeyTable;
  1040. if (keyTable.StartDepth == reader.Depth) {
  1041. EndIdentityValidation (keyTable);
  1042. } else {
  1043. for (int k = 0; k < keyTable.Entries.Count; k++) {
  1044. XsdKeyEntry entry = keyTable.Entries [k] as XsdKeyEntry;
  1045. // Remove finished (maybe key not found) entries.
  1046. if (entry.StartDepth == reader.Depth) {
  1047. if (entry.KeyFound)
  1048. keyTable.FinishedEntries.Add (entry);
  1049. else if (entry.KeySequence.SourceSchemaIdentity is XmlSchemaKey)
  1050. HandleError ("Key sequence is missing.");
  1051. keyTable.Entries.RemoveAt (k);
  1052. k--;
  1053. }
  1054. // Pop validated key depth to find two or more fields.
  1055. else {
  1056. for (int j = 0; j < entry.KeyFields.Count; j++) {
  1057. XsdKeyEntryField kf = entry.KeyFields [j];
  1058. if (!kf.FieldFound && kf.FieldFoundDepth == reader.Depth) {
  1059. kf.FieldFoundDepth = 0;
  1060. kf.FieldFoundPath = null;
  1061. }
  1062. }
  1063. }
  1064. }
  1065. }
  1066. }
  1067. for (int i = 0; i < keyTables.Count; i++) {
  1068. XsdKeyTable keyseq = this.keyTables [i] as XsdKeyTable;
  1069. if (keyseq.StartDepth == reader.Depth) {
  1070. keyTables.RemoveAt (i);
  1071. i--;
  1072. }
  1073. }
  1074. // Reset xsi:nil, if required.
  1075. if (xsiNilDepth == reader.Depth)
  1076. xsiNilDepth = -1;
  1077. }
  1078. // 3.11.4 Identity Constraint Satisfied
  1079. private void AssessStartIdentityConstraints ()
  1080. {
  1081. tmpKeyrefPool.Clear ();
  1082. if (context.Element != null && context.Element.Constraints.Count > 0) {
  1083. // (a) Create new key sequences, if required.
  1084. for (int i = 0; i < context.Element.Constraints.Count; i++) {
  1085. XmlSchemaIdentityConstraint ident = (XmlSchemaIdentityConstraint) context.Element.Constraints [i];
  1086. XsdKeyTable seq = CreateNewKeyTable (ident);
  1087. if (ident is XmlSchemaKeyref)
  1088. tmpKeyrefPool.Add (seq);
  1089. }
  1090. }
  1091. // (b) Evaluate current key sequences.
  1092. for (int i = 0; i < keyTables.Count; i++) {
  1093. XsdKeyTable seq = (XsdKeyTable) keyTables [i];
  1094. if (seq.SelectorMatches (this.elementQNameStack, reader) != null) {
  1095. // creates and registers new entry.
  1096. XsdKeyEntry entry = new XsdKeyEntry (seq, reader);
  1097. seq.Entries.Add (entry);
  1098. }
  1099. }
  1100. // (c) Evaluate field paths.
  1101. for (int i = 0; i < keyTables.Count; i++) {
  1102. XsdKeyTable seq = (XsdKeyTable) keyTables [i];
  1103. // If possible, create new field entry candidates.
  1104. for (int j = 0; j < seq.Entries.Count; j++) {
  1105. XsdKeyEntry entry = seq.Entries [j] as XsdKeyEntry;
  1106. try {
  1107. entry.FieldMatches (this.elementQNameStack, this);
  1108. } catch (Exception ex) { // FIXME: (wishlist) It is bad manner ;-(
  1109. HandleError ("Identity field value is invalid against its data type.", ex);
  1110. }
  1111. }
  1112. }
  1113. }
  1114. private XsdKeyTable CreateNewKeyTable (XmlSchemaIdentityConstraint ident)
  1115. {
  1116. XsdKeyTable seq = new XsdKeyTable (ident, this);
  1117. seq.StartDepth = reader.Depth;
  1118. XmlSchemaKeyref keyref = ident as XmlSchemaKeyref;
  1119. this.keyTables.Add (seq);
  1120. return seq;
  1121. }
  1122. private void EndIdentityValidation (XsdKeyTable seq)
  1123. {
  1124. ArrayList errors = new ArrayList ();
  1125. for (int i = 0; i < seq.Entries.Count; i++) {
  1126. XsdKeyEntry entry = (XsdKeyEntry) seq.Entries [i];
  1127. if (entry.KeyFound)
  1128. continue;
  1129. if (seq.SourceSchemaIdentity is XmlSchemaKey)
  1130. errors.Add ("line " + entry.SelectorLineNumber + "position " + entry.SelectorLinePosition);
  1131. }
  1132. if (errors.Count > 0)
  1133. HandleError ("Invalid identity constraints were found. Key was not found. "
  1134. + String.Join (", ", errors.ToArray (typeof (string)) as string []));
  1135. errors.Clear ();
  1136. // Find reference target
  1137. XmlSchemaKeyref xsdKeyref = seq.SourceSchemaIdentity as XmlSchemaKeyref;
  1138. if (xsdKeyref != null) {
  1139. for (int i = this.keyTables.Count - 1; i >= 0; i--) {
  1140. XsdKeyTable target = this.keyTables [i] as XsdKeyTable;
  1141. if (target.SourceSchemaIdentity == xsdKeyref.Target) {
  1142. seq.ReferencedKey = target;
  1143. for (int j = 0; j < seq.FinishedEntries.Count; j++) {
  1144. XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [j];
  1145. for (int k = 0; k < target.FinishedEntries.Count; k++) {
  1146. XsdKeyEntry targetEntry = (XsdKeyEntry) target.FinishedEntries [k];
  1147. if (entry.CompareIdentity (targetEntry)) {
  1148. entry.KeyRefFound = true;
  1149. break;
  1150. }
  1151. }
  1152. }
  1153. }
  1154. }
  1155. if (seq.ReferencedKey == null)
  1156. HandleError ("Target key was not found.");
  1157. for (int i = 0; i < seq.FinishedEntries.Count; i++) {
  1158. XsdKeyEntry entry = (XsdKeyEntry) seq.FinishedEntries [i];
  1159. if (!entry.KeyRefFound)
  1160. errors.Add (" line " + entry.SelectorLineNumber + ", position " + entry.SelectorLinePosition);
  1161. }
  1162. if (errors.Count > 0)
  1163. HandleError ("Invalid identity constraints were found. Referenced key was not found: "
  1164. + String.Join (" / ", errors.ToArray (typeof (string)) as string []));
  1165. }
  1166. }
  1167. // Overrided Methods
  1168. public override void Close ()
  1169. {
  1170. reader.Close ();
  1171. }
  1172. public override string GetAttribute (int i)
  1173. {
  1174. switch (reader.NodeType) {
  1175. case XmlNodeType.XmlDeclaration:
  1176. case XmlNodeType.DocumentType:
  1177. return reader.GetAttribute (i);
  1178. }
  1179. if (reader.AttributeCount > i)
  1180. reader.GetAttribute (i);
  1181. int defIdx = i - nonDefaultAttributeCount;
  1182. if (i < AttributeCount)
  1183. return defaultAttributes [defIdx].DefaultValue;
  1184. throw new ArgumentOutOfRangeException ("i", i, "Specified attribute index is out of range.");
  1185. }
  1186. public override string GetAttribute (string name)
  1187. {
  1188. switch (reader.NodeType) {
  1189. case XmlNodeType.XmlDeclaration:
  1190. case XmlNodeType.DocumentType:
  1191. return reader.GetAttribute (name);
  1192. }
  1193. string value = reader.GetAttribute (name);
  1194. if (value != null)
  1195. return value;
  1196. XmlQualifiedName qname = SplitQName (name);
  1197. return GetDefaultAttribute (qname.Name, qname.Namespace);
  1198. }
  1199. private XmlQualifiedName SplitQName (string name)
  1200. {
  1201. if (!XmlChar.IsName (name))
  1202. throw new ArgumentException ("Invalid name was specified.", "name");
  1203. Exception ex = null;
  1204. XmlQualifiedName qname = XmlSchemaUtil.ToQName (reader, name, out ex);
  1205. if (ex != null)
  1206. return XmlQualifiedName.Empty;
  1207. else
  1208. return qname;
  1209. }
  1210. public override string GetAttribute (string localName, string ns)
  1211. {
  1212. switch (reader.NodeType) {
  1213. case XmlNodeType.XmlDeclaration:
  1214. case XmlNodeType.DocumentType:
  1215. return reader.GetAttribute (localName, ns);
  1216. }
  1217. string value = reader.GetAttribute (localName, ns);
  1218. if (value != null)
  1219. return value;
  1220. return GetDefaultAttribute (localName, ns);
  1221. }
  1222. private string GetDefaultAttribute (string localName, string ns)
  1223. {
  1224. int idx = this.FindDefaultAttribute (localName, ns);
  1225. if (idx < 0)
  1226. return null;
  1227. string value = defaultAttributes [idx].ValidatedDefaultValue;
  1228. if (value == null)
  1229. value = defaultAttributes [idx].ValidatedFixedValue;
  1230. return value;
  1231. }
  1232. private int FindDefaultAttribute (string localName, string ns)
  1233. {
  1234. for (int i = 0; i < this.defaultAttributes.Length; i++) {
  1235. XmlSchemaAttribute attr = defaultAttributes [i];
  1236. if (attr.QualifiedName.Name == localName &&
  1237. (ns == null || attr.QualifiedName.Namespace == ns))
  1238. return i;
  1239. }
  1240. return -1;
  1241. }
  1242. bool IXmlLineInfo.HasLineInfo ()
  1243. {
  1244. return readerLineInfo != null && readerLineInfo.HasLineInfo ();
  1245. }
  1246. public override string LookupNamespace (string prefix)
  1247. {
  1248. return reader.LookupNamespace (prefix);
  1249. }
  1250. string IXmlNamespaceResolver.LookupNamespace (string prefix, bool atomizedNames)
  1251. {
  1252. IXmlNamespaceResolver res = reader as IXmlNamespaceResolver;
  1253. if (res != null)
  1254. return res.LookupNamespace (prefix, atomizedNames);
  1255. else
  1256. return reader.LookupNamespace (prefix);
  1257. }
  1258. public override void MoveToAttribute (int i)
  1259. {
  1260. switch (reader.NodeType) {
  1261. case XmlNodeType.XmlDeclaration:
  1262. case XmlNodeType.DocumentType:
  1263. reader.MoveToAttribute (i);
  1264. return;
  1265. }
  1266. currentQName = null;
  1267. if (i < this.nonDefaultAttributeCount) {
  1268. reader.MoveToAttribute (i);
  1269. this.currentDefaultAttribute = -1;
  1270. this.defaultAttributeConsumed = false;
  1271. }
  1272. if (i < AttributeCount) {
  1273. this.currentDefaultAttribute = i - nonDefaultAttributeCount;
  1274. this.defaultAttributeConsumed = false;
  1275. }
  1276. else
  1277. throw new ArgumentOutOfRangeException ("i", i, "Attribute index is out of range.");
  1278. }
  1279. public override bool MoveToAttribute (string name)
  1280. {
  1281. switch (reader.NodeType) {
  1282. case XmlNodeType.XmlDeclaration:
  1283. case XmlNodeType.DocumentType:
  1284. return reader.MoveToAttribute (name);
  1285. }
  1286. currentQName = null;
  1287. bool b = reader.MoveToAttribute (name);
  1288. if (b) {
  1289. this.currentDefaultAttribute = -1;
  1290. this.defaultAttributeConsumed = false;
  1291. return true;
  1292. }
  1293. return MoveToDefaultAttribute (name, null);
  1294. }
  1295. public override bool MoveToAttribute (string localName, string ns)
  1296. {
  1297. switch (reader.NodeType) {
  1298. case XmlNodeType.XmlDeclaration:
  1299. case XmlNodeType.DocumentType:
  1300. return reader.MoveToAttribute (localName, ns);
  1301. }
  1302. currentQName = null;
  1303. bool b = reader.MoveToAttribute (localName, ns);
  1304. if (b) {
  1305. this.currentDefaultAttribute = -1;
  1306. this.defaultAttributeConsumed = false;
  1307. return true;
  1308. }
  1309. return MoveToDefaultAttribute (localName, ns);
  1310. }
  1311. private bool MoveToDefaultAttribute (string localName, string ns)
  1312. {
  1313. int idx = this.FindDefaultAttribute (localName, ns);
  1314. if (idx < 0)
  1315. return false;
  1316. currentDefaultAttribute = idx;
  1317. defaultAttributeConsumed = false;
  1318. return true;
  1319. }
  1320. public override bool MoveToElement ()
  1321. {
  1322. currentDefaultAttribute = -1;
  1323. defaultAttributeConsumed = false;
  1324. currentQName = null;
  1325. return reader.MoveToElement ();
  1326. }
  1327. public override bool MoveToFirstAttribute ()
  1328. {
  1329. switch (reader.NodeType) {
  1330. case XmlNodeType.XmlDeclaration:
  1331. case XmlNodeType.DocumentType:
  1332. return reader.MoveToFirstAttribute ();
  1333. }
  1334. currentQName = null;
  1335. if (this.nonDefaultAttributeCount > 0) {
  1336. bool b = reader.MoveToFirstAttribute ();
  1337. if (b) {
  1338. currentDefaultAttribute = -1;
  1339. defaultAttributeConsumed = false;
  1340. }
  1341. return b;
  1342. }
  1343. if (this.defaultAttributes.Length > 0) {
  1344. currentDefaultAttribute = 0;
  1345. defaultAttributeConsumed = false;
  1346. return true;
  1347. }
  1348. else
  1349. return false;
  1350. }
  1351. public override bool MoveToNextAttribute ()
  1352. {
  1353. switch (reader.NodeType) {
  1354. case XmlNodeType.XmlDeclaration:
  1355. case XmlNodeType.DocumentType:
  1356. return reader.MoveToNextAttribute ();
  1357. }
  1358. currentQName = null;
  1359. if (currentDefaultAttribute >= 0) {
  1360. if (defaultAttributes.Length == currentDefaultAttribute + 1)
  1361. return false;
  1362. currentDefaultAttribute++;
  1363. defaultAttributeConsumed = false;
  1364. return true;
  1365. }
  1366. bool b = reader.MoveToNextAttribute ();
  1367. if (b) {
  1368. currentDefaultAttribute = -1;
  1369. defaultAttributeConsumed = false;
  1370. return true;
  1371. }
  1372. if (defaultAttributes.Length > 0) {
  1373. currentDefaultAttribute = 0;
  1374. defaultAttributeConsumed = false;
  1375. return true;
  1376. }
  1377. else
  1378. return false;
  1379. }
  1380. private void ExamineAdditionalSchema ()
  1381. {
  1382. XmlSchema schema = null;
  1383. string schemaLocation = reader.GetAttribute ("schemaLocation", XmlSchema.InstanceNamespace);
  1384. bool schemaAdded = false;
  1385. if (schemaLocation != null) {
  1386. string [] tmp = null;
  1387. try {
  1388. schemaLocation = XmlSchemaDatatype.FromName ("token", XmlSchema.Namespace).Normalize (schemaLocation);
  1389. tmp = schemaLocation.Split (XmlChar.WhitespaceChars);
  1390. } catch (Exception ex) {
  1391. HandleError ("Invalid schemaLocation attribute format.", ex, true);
  1392. tmp = new string [0];
  1393. }
  1394. if (tmp.Length % 2 != 0)
  1395. HandleError ("Invalid schemaLocation attribute format.");
  1396. for (int i = 0; i < tmp.Length; i += 2) {
  1397. Uri absUri = null;
  1398. XmlTextReader xtr = null;
  1399. try {
  1400. absUri = new Uri ((this.BaseURI != "" ? new Uri (BaseURI) : null), tmp [i + 1]);
  1401. xtr = new XmlTextReader (absUri.ToString ());
  1402. schema = XmlSchema.Read (xtr, null);
  1403. } catch (Exception) { // FIXME: (wishlist) It is bad manner ;-(
  1404. HandleError ("Could not resolve schema location URI: " + absUri, null, true);
  1405. continue;
  1406. } finally {
  1407. if (xtr != null)
  1408. xtr.Close ();
  1409. }
  1410. if (schema.TargetNamespace == null)
  1411. schema.TargetNamespace = tmp [i];
  1412. else if (schema.TargetNamespace != tmp [i])
  1413. HandleError ("Specified schema has different target namespace.");
  1414. }
  1415. }
  1416. if (schema != null) {
  1417. if (!schemas.Contains (schema.TargetNamespace)) {
  1418. schemaAdded = true;
  1419. schemas.Add (schema);
  1420. }
  1421. }
  1422. schema = null;
  1423. string noNsSchemaLocation = reader.GetAttribute ("noNamespaceSchemaLocation", XmlSchema.InstanceNamespace);
  1424. if (noNsSchemaLocation != null) {
  1425. Uri absUri = null;
  1426. XmlTextReader xtr = null;
  1427. try {
  1428. absUri = new Uri ((this.BaseURI != "" ? new Uri (BaseURI) : null), noNsSchemaLocation);
  1429. xtr = new XmlTextReader (absUri.ToString ());
  1430. schema = XmlSchema.Read (xtr, null);
  1431. } catch (Exception) { // FIXME: (wishlist) It is bad manner ;-(
  1432. HandleError ("Could not resolve schema location URI: " + absUri, null, true);
  1433. } finally {
  1434. if (xtr != null)
  1435. xtr.Close ();
  1436. }
  1437. if (schema != null && schema.TargetNamespace != null)
  1438. HandleError ("Specified schema has different target namespace.");
  1439. }
  1440. if (schema != null) {
  1441. if (!schemas.Contains (schema.TargetNamespace)) {
  1442. schemaAdded = true;
  1443. schemas.Add (schema);
  1444. }
  1445. }
  1446. // FIXME: should call Reprocess()?
  1447. if (schemaAdded)
  1448. schemas.Compile ();
  1449. }
  1450. public override bool Read ()
  1451. {
  1452. nonDefaultAttributeCount = 0;
  1453. currentDefaultAttribute = -1;
  1454. defaultAttributeConsumed = false;
  1455. currentQName = null;
  1456. thisElementId = null;
  1457. defaultAttributes = new XmlSchemaAttribute [0];
  1458. if (popContext) {
  1459. elementQNameStack.RemoveAt (elementQNameStack.Count - 1);
  1460. popContext = false;
  1461. }
  1462. bool result = reader.Read ();
  1463. // 3.3.4 ElementLocallyValidElement 7 = Root Valid.
  1464. if (!result && missingIDReferences.Count > 0)
  1465. HandleError ("There are missing ID references: " +
  1466. String.Join (" ",
  1467. this.missingIDReferences.ToArray (typeof (string)) as string []));
  1468. switch (reader.NodeType) {
  1469. case XmlNodeType.XmlDeclaration:
  1470. this.nonDefaultAttributeCount = reader.AttributeCount;
  1471. break;
  1472. case XmlNodeType.Element:
  1473. nonDefaultAttributeCount = reader.AttributeCount;
  1474. // FIXME: schemaLocation could be specified
  1475. // at any Depth.
  1476. if (reader.Depth == 0)
  1477. ExamineAdditionalSchema ();
  1478. this.elementQNameStack.Add (new XmlQualifiedName (reader.LocalName, reader.NamespaceURI));
  1479. // If there is no schema information, then no validation is performed.
  1480. if (schemas.Count == 0)
  1481. break;
  1482. if (skipValidationDepth < 0 || reader.Depth <= skipValidationDepth) {
  1483. if (shouldValidateCharacters) {
  1484. ValidateEndCharacters ();
  1485. shouldValidateCharacters = false;
  1486. }
  1487. AssessStartElementSchemaValidity ();
  1488. storedCharacters.Length = 0;
  1489. } else {
  1490. context.Clear ();
  1491. }
  1492. if (reader.IsEmptyElement)
  1493. goto case XmlNodeType.EndElement;
  1494. else
  1495. shouldValidateCharacters = true;
  1496. break;
  1497. case XmlNodeType.EndElement:
  1498. if (reader.Depth == skipValidationDepth) {
  1499. skipValidationDepth = -1;
  1500. context.Clear ();
  1501. }
  1502. else
  1503. AssessEndElementSchemaValidity ();
  1504. storedCharacters.Length = 0;
  1505. childParticleState = null;
  1506. popContext = true;
  1507. break;
  1508. case XmlNodeType.CDATA:
  1509. case XmlNodeType.SignificantWhitespace:
  1510. case XmlNodeType.Text:
  1511. XmlSchemaComplexType ct = context.ActualType as XmlSchemaComplexType;
  1512. if (ct != null && storedCharacters.Length > 0) {
  1513. switch (ct.ContentType) {
  1514. case XmlSchemaContentType.ElementOnly:
  1515. case XmlSchemaContentType.Empty:
  1516. HandleError ("Not allowed character content was found.");
  1517. break;
  1518. }
  1519. }
  1520. ValidateCharacters ();
  1521. break;
  1522. }
  1523. return result;
  1524. }
  1525. public override bool ReadAttributeValue ()
  1526. {
  1527. if (currentDefaultAttribute < 0)
  1528. return reader.ReadAttributeValue ();
  1529. if (this.defaultAttributeConsumed)
  1530. return false;
  1531. defaultAttributeConsumed = true;
  1532. return true;
  1533. }
  1534. #if NET_1_0
  1535. public override string ReadInnerXml ()
  1536. {
  1537. // MS.NET 1.0 has a serious bug here. It skips validation.
  1538. return reader.ReadInnerXml ();
  1539. }
  1540. public override string ReadOuterXml ()
  1541. {
  1542. // MS.NET 1.0 has a serious bug here. It skips validation.
  1543. return reader.ReadOuterXml ();
  1544. }
  1545. #endif
  1546. // XmlReader.ReadString() should call derived this.Read().
  1547. public override string ReadString ()
  1548. {
  1549. #if NET_1_0
  1550. return reader.ReadString ();
  1551. #else
  1552. return base.ReadString ();
  1553. #endif
  1554. }
  1555. // This class itself does not have this feature.
  1556. public override void ResolveEntity ()
  1557. {
  1558. reader.ResolveEntity ();
  1559. }
  1560. internal class XsdValidationContext
  1561. {
  1562. Hashtable contextStack;
  1563. public XsdValidationContext ()
  1564. {
  1565. contextStack = new Hashtable ();
  1566. }
  1567. // Some of them might be missing (See the spec section 5.3, and also 3.3.4).
  1568. public XmlSchemaElement Element;
  1569. public XsdValidationState ParticleState;
  1570. public XmlSchemaAttribute [] DefaultAttributes;
  1571. // Some of them might be missing (See the spec section 5.3).
  1572. public object SchemaType;
  1573. public object LocalTypeDefinition;
  1574. public object ActualType {
  1575. get {
  1576. if (LocalTypeDefinition != null)
  1577. return LocalTypeDefinition;
  1578. else
  1579. return SchemaType;
  1580. }
  1581. }
  1582. public void Clear ()
  1583. {
  1584. Element = null;
  1585. SchemaType = null;
  1586. ParticleState = null;
  1587. LocalTypeDefinition = null;
  1588. }
  1589. public void PushScope (int depth)
  1590. {
  1591. contextStack [depth] = this.MemberwiseClone ();
  1592. }
  1593. public void PopScope (int depth)
  1594. {
  1595. Load (depth);
  1596. contextStack.Remove (depth + 1);
  1597. }
  1598. public void Load (int depth)
  1599. {
  1600. Clear ();
  1601. XsdValidationContext restored = (XsdValidationContext) contextStack [depth];
  1602. if (restored != null) {
  1603. this.Element = restored.Element;
  1604. this.ParticleState = restored.ParticleState;
  1605. this.SchemaType = restored.SchemaType;
  1606. this.LocalTypeDefinition = restored.LocalTypeDefinition;
  1607. }
  1608. }
  1609. }
  1610. }
  1611. }