XmlSchemaXPath.cs 9.5 KB

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