XmlSchemaXPath.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  1. // Author: Dwivedi, Ajay kumar
  2. // [email protected]
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining
  5. // a copy of this software and associated documentation files (the
  6. // "Software"), to deal in the Software without restriction, including
  7. // without limitation the rights to use, copy, modify, merge, publish,
  8. // distribute, sublicense, and/or sell copies of the Software, and to
  9. // permit persons to whom the Software is furnished to do so, subject to
  10. // the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be
  13. // included in all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  16. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  17. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  18. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  19. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  20. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  21. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  22. //
  23. using System;
  24. using System.Collections;
  25. using System.Xml.Serialization;
  26. using System.ComponentModel;
  27. using System.Xml;
  28. using Mono.Xml;
  29. using Mono.Xml.Schema;
  30. namespace System.Xml.Schema
  31. {
  32. /// <summary>
  33. /// Summary description for XmlSchemaXPath.
  34. /// </summary>
  35. public class XmlSchemaXPath : XmlSchemaAnnotated
  36. {
  37. private string xpath;
  38. XmlNamespaceManager nsmgr;
  39. internal bool isSelector;
  40. XsdIdentityPath [] compiledExpression;
  41. XsdIdentityPath currentPath;
  42. public XmlSchemaXPath()
  43. {
  44. }
  45. [DefaultValue("")]
  46. [System.Xml.Serialization.XmlAttribute("xpath")]
  47. public string XPath
  48. {
  49. get{ return xpath; }
  50. set{ xpath = value; }
  51. }
  52. internal override int Compile(ValidationEventHandler h, XmlSchema schema)
  53. {
  54. // If this is already compiled this time, simply skip.
  55. if (this.IsComplied (schema.CompilationId))
  56. return 0;
  57. if (nsmgr == null) {
  58. nsmgr = new XmlNamespaceManager (new NameTable ());
  59. if (Namespaces != null)
  60. foreach (XmlQualifiedName qname in Namespaces.ToArray ())
  61. nsmgr.AddNamespace (qname.Name, qname.Namespace);
  62. }
  63. currentPath = new XsdIdentityPath ();
  64. ParseExpression (xpath, h, schema);
  65. XmlSchemaUtil.CompileID(Id, this, schema.IDCollection, h);
  66. this.CompilationId = schema.CompilationId;
  67. return errorCount;
  68. }
  69. internal XsdIdentityPath [] CompiledExpression {
  70. get { return compiledExpression; }
  71. }
  72. private void ParseExpression (string xpath, ValidationEventHandler h, XmlSchema schema)
  73. {
  74. ArrayList paths = new ArrayList ();
  75. ParsePath (xpath, 0, paths, h, schema);
  76. this.compiledExpression = (XsdIdentityPath []) paths.ToArray (typeof (XsdIdentityPath));
  77. }
  78. private void ParsePath (string xpath, int pos, ArrayList paths,
  79. ValidationEventHandler h, XmlSchema schema)
  80. {
  81. pos = SkipWhitespace (xpath, pos);
  82. if (xpath.Length >= pos + 3 && xpath [pos] == '.') {
  83. int tmp = pos;
  84. pos++;
  85. pos = SkipWhitespace (xpath, pos);
  86. if (xpath.Length > pos + 2 && xpath.IndexOf ("//", pos, 2) == pos) {
  87. currentPath.Descendants = true;
  88. pos += 2;
  89. }
  90. else
  91. pos = tmp; // revert
  92. }
  93. ArrayList al = new ArrayList ();
  94. ParseStep (xpath, pos, al, paths, h, schema);
  95. }
  96. private void ParseStep (string xpath, int pos, ArrayList steps,
  97. ArrayList paths, ValidationEventHandler h, XmlSchema schema)
  98. {
  99. pos = SkipWhitespace (xpath, pos);
  100. if (xpath.Length == pos) {
  101. error (h, "Empty xpath expression is specified");
  102. return;
  103. }
  104. XsdIdentityStep step = new XsdIdentityStep ();
  105. switch (xpath [pos]) {
  106. case '@':
  107. if (isSelector) {
  108. error (h, "Selector cannot include attribute axes.");
  109. currentPath = null;
  110. return;
  111. }
  112. pos++;
  113. step.IsAttribute = true;
  114. pos = SkipWhitespace (xpath, pos);
  115. if (xpath.Length > pos && xpath [pos] == '*') {
  116. pos++;
  117. step.IsAnyName = true;
  118. break;
  119. }
  120. goto default;
  121. case '.':
  122. pos++; // do nothing ;-)
  123. step.IsCurrent = true;
  124. break;
  125. case '*':
  126. pos++;
  127. step.IsAnyName = true;
  128. break;
  129. case 'c':
  130. if (xpath.Length > pos + 5 && xpath.IndexOf ("child", pos, 5) == pos) {
  131. int tmp = pos;
  132. pos += 5;
  133. pos = SkipWhitespace (xpath, pos);
  134. if (xpath.Length > pos && xpath [pos] == ':' && xpath [pos+1] == ':') {
  135. pos += 2;
  136. if (xpath.Length > pos && xpath [pos] == '*') {
  137. pos++;
  138. step.IsAnyName = true;
  139. break;
  140. }
  141. pos = SkipWhitespace (xpath, pos);
  142. }
  143. else
  144. pos = tmp;
  145. }
  146. goto default;
  147. case 'a':
  148. if (xpath.Length > pos + 9 && xpath.IndexOf ("attribute", pos, 9) == pos) {
  149. int tmp = pos;
  150. pos += 9;
  151. pos = SkipWhitespace (xpath, pos);
  152. if (xpath.Length > pos && xpath [pos] == ':' && xpath [pos+1] == ':') {
  153. if (isSelector) {
  154. error (h, "Selector cannot include attribute axes.");
  155. currentPath = null;
  156. return;
  157. }
  158. pos += 2;
  159. step.IsAttribute = true;
  160. if (xpath.Length > pos && xpath [pos] == '*') {
  161. pos++;
  162. step.IsAnyName = true;
  163. break;
  164. }
  165. pos = SkipWhitespace (xpath, pos);
  166. }
  167. else
  168. pos = tmp;
  169. }
  170. goto default;
  171. default:
  172. int nameStart = pos;
  173. while (xpath.Length > pos) {
  174. if (!XmlChar.IsNCNameChar (xpath [pos]))
  175. break;
  176. else
  177. pos++;
  178. }
  179. if (pos == nameStart) {
  180. error (h, "Invalid path format for a field.");
  181. this.currentPath = null;
  182. return;
  183. }
  184. if (xpath.Length == pos || xpath [pos] != ':')
  185. step.Name = xpath.Substring (nameStart, pos - nameStart);
  186. else {
  187. string prefix = xpath.Substring (nameStart, pos - nameStart);
  188. pos++;
  189. if (xpath.Length > pos && xpath [pos] == '*') {
  190. string ns = nsmgr.LookupNamespace (prefix, false);
  191. if (ns == null) {
  192. error (h, "Specified prefix '" + prefix + "' is not declared.");
  193. this.currentPath = null;
  194. return;
  195. }
  196. step.NsName = ns;
  197. pos++;
  198. } else {
  199. int localNameStart = pos;
  200. while (xpath.Length > pos) {
  201. if (!XmlChar.IsNCNameChar (xpath [pos]))
  202. break;
  203. else
  204. pos++;
  205. }
  206. step.Name = xpath.Substring (localNameStart, pos - localNameStart);
  207. string ns = nsmgr.LookupNamespace (prefix, false);
  208. if (ns == null) {
  209. error (h, "Specified prefix '" + prefix + "' is not declared.");
  210. this.currentPath = null;
  211. return;
  212. }
  213. step.Namespace = ns;
  214. }
  215. }
  216. break;
  217. }
  218. if (!step.IsCurrent) // Current step is meaningless, other than its representation.
  219. steps.Add (step);
  220. pos = SkipWhitespace (xpath, pos);
  221. if (xpath.Length == pos) {
  222. currentPath.OrderedSteps = (XsdIdentityStep []) steps.ToArray (typeof (XsdIdentityStep));
  223. paths.Add (currentPath);
  224. return;
  225. }
  226. else if (xpath [pos] == '/') {
  227. pos++;
  228. if (step.IsAttribute) {
  229. error (h, "Unexpected xpath token after Attribute NameTest.");
  230. this.currentPath = null;
  231. return;
  232. }
  233. this.ParseStep (xpath, pos, steps, paths, h, schema);
  234. if (currentPath == null) // For ValidationEventHandler
  235. return;
  236. currentPath.OrderedSteps = (XsdIdentityStep []) steps.ToArray (typeof (XsdIdentityStep));
  237. } else if (xpath [pos] == '|') {
  238. pos++;
  239. currentPath.OrderedSteps = (XsdIdentityStep []) steps.ToArray (typeof (XsdIdentityStep));
  240. paths.Add (this.currentPath);
  241. this.currentPath = new XsdIdentityPath ();
  242. this.ParsePath (xpath, pos, paths, h, schema);
  243. } else {
  244. error (h, "Unexpected xpath token after NameTest.");
  245. this.currentPath = null;
  246. return;
  247. }
  248. }
  249. private int SkipWhitespace (string xpath, int pos)
  250. {
  251. bool loop = true;
  252. while (loop && xpath.Length > pos) {
  253. switch (xpath [pos]) {
  254. case ' ':
  255. case '\t':
  256. case '\r':
  257. case '\n':
  258. pos++;
  259. continue;
  260. default:
  261. loop = false;
  262. break;
  263. }
  264. }
  265. return pos;
  266. }
  267. //<selector
  268. // id = ID
  269. // xpath = a subset of XPath expression, see below
  270. // {any attributes with non-schema namespace . . .}>
  271. // Content: (annotation?)
  272. //</selector>
  273. internal static XmlSchemaXPath Read(XmlSchemaReader reader, ValidationEventHandler h,string name)
  274. {
  275. XmlSchemaXPath path = new XmlSchemaXPath();
  276. reader.MoveToElement();
  277. if(reader.NamespaceURI != XmlSchema.Namespace || reader.LocalName != name)
  278. {
  279. error(h,"Should not happen :1: XmlSchemaComplexContentRestriction.Read, name="+reader.Name,null);
  280. reader.Skip();
  281. return null;
  282. }
  283. path.LineNumber = reader.LineNumber;
  284. path.LinePosition = reader.LinePosition;
  285. path.SourceUri = reader.BaseURI;
  286. XmlNamespaceManager currentMgr = XmlSchemaUtil.GetParserContext (reader.Reader).NamespaceManager;
  287. if (currentMgr != null) {
  288. path.nsmgr = new XmlNamespaceManager (reader.NameTable);
  289. IEnumerator e = currentMgr.GetEnumerator ();
  290. while (e.MoveNext ()) {
  291. string prefix = e.Current as string;
  292. switch (prefix) {
  293. case "xml":
  294. case "xmlns":
  295. continue;
  296. default:
  297. path.nsmgr.AddNamespace (prefix, currentMgr.LookupNamespace (prefix, false));
  298. break;
  299. }
  300. }
  301. }
  302. while(reader.MoveToNextAttribute())
  303. {
  304. if(reader.Name == "id")
  305. {
  306. path.Id = reader.Value;
  307. }
  308. else if(reader.Name == "xpath")
  309. {
  310. path.xpath = reader.Value;
  311. }
  312. else if((reader.NamespaceURI == "" && reader.Name != "xmlns") || reader.NamespaceURI == XmlSchema.Namespace)
  313. {
  314. error(h,reader.Name + " is not a valid attribute for "+name,null);
  315. }
  316. else
  317. {
  318. XmlSchemaUtil.ReadUnhandledAttribute(reader,path);
  319. }
  320. }
  321. reader.MoveToElement();
  322. if(reader.IsEmptyElement)
  323. return path;
  324. // Content: (annotation?)
  325. int level = 1;
  326. while(reader.ReadNextElement())
  327. {
  328. if(reader.NodeType == XmlNodeType.EndElement)
  329. {
  330. if(reader.LocalName != name)
  331. error(h,"Should not happen :2: XmlSchemaXPath.Read, name="+reader.Name,null);
  332. break;
  333. }
  334. if(level <= 1 && reader.LocalName == "annotation")
  335. {
  336. level = 2; //Only one annotation
  337. XmlSchemaAnnotation annotation = XmlSchemaAnnotation.Read(reader,h);
  338. if(annotation != null)
  339. path.Annotation = annotation;
  340. continue;
  341. }
  342. reader.RaiseInvalidElementError();
  343. }
  344. return path;
  345. }
  346. }
  347. }