XmlSchemaXPath.cs 9.5 KB

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