XmlSchemaXPath.cs 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  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. }
  200. if (!step.IsCurrent) // Current step is meaningless, other than its representation.
  201. steps.Add (step);
  202. pos = SkipWhitespace (xpath, pos);
  203. if (xpath.Length == pos) {
  204. currentPath.OrderedSteps = (XsdIdentityStep []) steps.ToArray (typeof (XsdIdentityStep));
  205. paths.Add (currentPath);
  206. return;
  207. }
  208. else if (xpath [pos] == '/') {
  209. pos++;
  210. if (step.IsAttribute) {
  211. error (h, "Unexpected xpath token after Attribute NameTest.");
  212. this.currentPath = null;
  213. return;
  214. }
  215. this.ParseStep (xpath, pos, steps, paths, h, schema);
  216. if (currentPath == null) // For ValidationEventHandler
  217. return;
  218. currentPath.OrderedSteps = (XsdIdentityStep []) steps.ToArray (typeof (XsdIdentityStep));
  219. } else if (xpath [pos] == '|') {
  220. pos++;
  221. currentPath.OrderedSteps = (XsdIdentityStep []) steps.ToArray (typeof (XsdIdentityStep));
  222. paths.Add (this.currentPath);
  223. this.currentPath = new XsdIdentityPath ();
  224. this.ParsePath (xpath, pos, paths, h, schema);
  225. } else {
  226. error (h, "Unexpected xpath token after NameTest.");
  227. this.currentPath = null;
  228. return;
  229. }
  230. }
  231. private int SkipWhitespace (string xpath, int pos)
  232. {
  233. bool loop = true;
  234. while (loop && xpath.Length > pos) {
  235. switch (xpath [pos]) {
  236. case ' ':
  237. case '\t':
  238. case '\r':
  239. case '\n':
  240. pos++;
  241. continue;
  242. default:
  243. loop = false;
  244. break;
  245. }
  246. }
  247. return pos;
  248. }
  249. //<selector
  250. // id = ID
  251. // xpath = a subset of XPath expression, see below
  252. // {any attributes with non-schema namespace . . .}>
  253. // Content: (annotation?)
  254. //</selector>
  255. internal static XmlSchemaXPath Read(XmlSchemaReader reader, ValidationEventHandler h,string name)
  256. {
  257. XmlSchemaXPath path = new XmlSchemaXPath();
  258. reader.MoveToElement();
  259. if(reader.NamespaceURI != XmlSchema.Namespace || reader.LocalName != name)
  260. {
  261. error(h,"Should not happen :1: XmlSchemaComplexContentRestriction.Read, name="+reader.Name,null);
  262. reader.Skip();
  263. return null;
  264. }
  265. path.LineNumber = reader.LineNumber;
  266. path.LinePosition = reader.LinePosition;
  267. path.SourceUri = reader.BaseURI;
  268. XmlNamespaceManager currentMgr = XmlSchemaUtil.GetParserContext (reader.Reader).NamespaceManager;
  269. if (currentMgr != null) {
  270. path.nsmgr = new XmlNamespaceManager (reader.NameTable);
  271. IEnumerator e = currentMgr.GetEnumerator ();
  272. while (e.MoveNext ()) {
  273. string prefix = e.Current as string;
  274. switch (prefix) {
  275. case "xml":
  276. case "xmlns":
  277. continue;
  278. default:
  279. path.nsmgr.AddNamespace (prefix, currentMgr.LookupNamespace (prefix));
  280. break;
  281. }
  282. }
  283. }
  284. while(reader.MoveToNextAttribute())
  285. {
  286. if(reader.Name == "id")
  287. {
  288. path.Id = reader.Value;
  289. }
  290. else if(reader.Name == "xpath")
  291. {
  292. path.xpath = reader.Value;
  293. }
  294. else if((reader.NamespaceURI == "" && reader.Name != "xmlns") || reader.NamespaceURI == XmlSchema.Namespace)
  295. {
  296. error(h,reader.Name + " is not a valid attribute for "+name,null);
  297. }
  298. else
  299. {
  300. XmlSchemaUtil.ReadUnhandledAttribute(reader,path);
  301. }
  302. }
  303. reader.MoveToElement();
  304. if(reader.IsEmptyElement)
  305. return path;
  306. // Content: (annotation?)
  307. int level = 1;
  308. while(reader.ReadNextElement())
  309. {
  310. if(reader.NodeType == XmlNodeType.EndElement)
  311. {
  312. if(reader.LocalName != name)
  313. error(h,"Should not happen :2: XmlSchemaXPath.Read, name="+reader.Name,null);
  314. break;
  315. }
  316. if(level <= 1 && reader.LocalName == "annotation")
  317. {
  318. level = 2; //Only one annotation
  319. XmlSchemaAnnotation annotation = XmlSchemaAnnotation.Read(reader,h);
  320. if(annotation != null)
  321. path.Annotation = annotation;
  322. continue;
  323. }
  324. reader.RaiseInvalidElementError();
  325. }
  326. return path;
  327. }
  328. }
  329. }