DTDObjectModel.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494
  1. //
  2. // Mono.Xml.DTDObjectModel
  3. //
  4. // Author:
  5. // Atsushi Enomoto ([email protected])
  6. //
  7. // (C)2003 Atsushi Enomoto
  8. //
  9. using System;
  10. using System.Collections;
  11. using System.Text;
  12. using System.Xml;
  13. using System.Xml.Schema;
  14. using Mono.Xml.Schema;
  15. namespace Mono.Xml
  16. {
  17. public class DTDObjectModel
  18. {
  19. internal DTDElementDeclarationCollection elementDecls;
  20. internal DTDAttListDeclarationCollection attListDecls;
  21. internal Hashtable EntityDecls = new Hashtable ();
  22. internal Hashtable NotationDecls = new Hashtable ();
  23. public DTDObjectModel ()
  24. {
  25. elementDecls = new DTDElementDeclarationCollection (this);
  26. attListDecls = new DTDAttListDeclarationCollection (this);
  27. factory = new DTDAutomataFactory (this);
  28. }
  29. public string Name;
  30. public string PublicId;
  31. public string SystemId;
  32. public string InternalSubset;
  33. public string ResolveEntity (string name)
  34. {
  35. DTDEntityDeclaration decl = EntityDecls [name]
  36. as DTDEntityDeclaration;
  37. return decl.EntityValue;
  38. }
  39. private DTDAutomataFactory factory;
  40. public DTDAutomataFactory Factory {
  41. get { return factory; }
  42. }
  43. public DTDElementDeclaration RootElement {
  44. get { return ElementDecls [Name]; }
  45. }
  46. public DTDElementDeclarationCollection ElementDecls {
  47. get { return elementDecls; }
  48. }
  49. public DTDAttListDeclarationCollection AttListDecls {
  50. get { return attListDecls; }
  51. }
  52. DTDElementAutomata rootAutomata;
  53. public DTDAutomata RootAutomata {
  54. get {
  55. if (rootAutomata == null)
  56. rootAutomata = new DTDElementAutomata (this, this.Name);
  57. return rootAutomata;
  58. }
  59. }
  60. DTDEmptyAutomata emptyAutomata;
  61. public DTDEmptyAutomata Empty {
  62. get {
  63. if (emptyAutomata == null)
  64. emptyAutomata = new DTDEmptyAutomata (this);
  65. return emptyAutomata;
  66. }
  67. }
  68. DTDAnyAutomata anyAutomata;
  69. public DTDAnyAutomata Any {
  70. get {
  71. if (anyAutomata == null)
  72. anyAutomata = new DTDAnyAutomata (this);
  73. return anyAutomata;
  74. }
  75. }
  76. DTDInvalidAutomata invalidAutomata;
  77. public DTDInvalidAutomata Invalid {
  78. get {
  79. if (invalidAutomata == null)
  80. invalidAutomata = new DTDInvalidAutomata (this);
  81. return invalidAutomata;
  82. }
  83. }
  84. }
  85. public class DTDElementDeclarationCollection
  86. {
  87. Hashtable elementDecls = new Hashtable ();
  88. DTDObjectModel root;
  89. public DTDElementDeclarationCollection (DTDObjectModel root)
  90. {
  91. this.root = root;
  92. }
  93. public DTDElementDeclaration this [string name] {
  94. get { return elementDecls [name] as DTDElementDeclaration; }
  95. }
  96. public void Add (string name, DTDElementDeclaration decl)
  97. {
  98. if (elementDecls [name] != null)
  99. throw new InvalidOperationException (String.Format (
  100. "Element declaration for {0} was already added.",
  101. name));
  102. decl.SetRoot (root);
  103. elementDecls.Add (name, decl);
  104. }
  105. public ICollection Keys {
  106. get { return elementDecls.Keys; }
  107. }
  108. public ICollection Values {
  109. get { return elementDecls.Values; }
  110. }
  111. }
  112. public class DTDAttListDeclarationCollection
  113. {
  114. Hashtable attListDecls = new Hashtable ();
  115. DTDObjectModel root;
  116. public DTDAttListDeclarationCollection (DTDObjectModel root)
  117. {
  118. this.root = root;
  119. }
  120. public DTDAttListDeclaration this [string name] {
  121. get { return attListDecls [name] as DTDAttListDeclaration; }
  122. }
  123. public void Add (string name, DTDAttListDeclaration decl)
  124. {
  125. if (attListDecls [name] != null)
  126. throw new InvalidOperationException (String.Format (
  127. "AttList declaration for {0} was already added.",
  128. name));
  129. decl.SetRoot (root);
  130. attListDecls.Add (name, decl);
  131. }
  132. public ICollection Keys {
  133. get { return attListDecls.Keys; }
  134. }
  135. public ICollection Values {
  136. get { return attListDecls.Values; }
  137. }
  138. }
  139. public class DTDContentModel
  140. {
  141. private DTDObjectModel root;
  142. DTDAutomata compiledAutomata;
  143. private string ownerElementName;
  144. public string ElementName;
  145. public DTDContentOrderType OrderType = DTDContentOrderType.None;
  146. public DTDContentModelCollection ChildModels
  147. = new DTDContentModelCollection ();
  148. public DTDOccurence Occurence = DTDOccurence.One;
  149. internal DTDContentModel (DTDObjectModel root, string ownerElementName)
  150. {
  151. this.root = root;
  152. this.ownerElementName = ownerElementName;
  153. }
  154. public DTDElementDeclaration ElementDecl {
  155. get {
  156. return root.ElementDecls [ownerElementName];
  157. }
  158. }
  159. public DTDAutomata GetAutomata ()
  160. {
  161. if (compiledAutomata == null)
  162. Compile ();
  163. return compiledAutomata;
  164. }
  165. public DTDAutomata Compile ()
  166. {
  167. compiledAutomata = CompileInternal ();
  168. return compiledAutomata;
  169. }
  170. private DTDAutomata CompileInternal ()
  171. {
  172. if (ElementDecl.IsAny)
  173. return root.Any;
  174. if (ElementDecl.IsEmpty)
  175. return root.Empty;
  176. DTDAutomata basis = GetBasicContentAutomata ();
  177. switch (Occurence) {
  178. case DTDOccurence.One:
  179. return basis;
  180. case DTDOccurence.Optional:
  181. return Choice (root.Empty, basis);
  182. case DTDOccurence.OneOrMore:
  183. return new DTDOneOrMoreAutomata (root, basis);
  184. case DTDOccurence.ZeroOrMore:
  185. return Choice (root.Empty, new DTDOneOrMoreAutomata (root, basis));
  186. }
  187. throw new InvalidOperationException ();
  188. }
  189. private DTDAutomata GetBasicContentAutomata ()
  190. {
  191. if (ElementName != null)
  192. return new DTDElementAutomata (root, ElementName);
  193. switch (ChildModels.Count) {
  194. case 0:
  195. return root.Empty;
  196. case 1:
  197. return ChildModels [0].GetAutomata ();
  198. }
  199. DTDAutomata current = null;
  200. int childCount = ChildModels.Count;
  201. switch (OrderType) {
  202. case DTDContentOrderType.Seq:
  203. current = Sequence (
  204. ChildModels [childCount - 2].GetAutomata (),
  205. ChildModels [childCount - 1].GetAutomata ());
  206. for (int i = childCount - 2; i > 0; i--)
  207. current = Sequence (
  208. ChildModels [i - 1].GetAutomata (), current);
  209. return current;
  210. case DTDContentOrderType.Or:
  211. current = Choice (
  212. ChildModels [childCount - 2].GetAutomata (),
  213. ChildModels [childCount - 1].GetAutomata ());
  214. for (int i = childCount - 2; i > 0; i--)
  215. current = Choice (
  216. ChildModels [i - 1].GetAutomata (), current);
  217. return current;
  218. default:
  219. throw new InvalidOperationException ("Invalid pattern specification");
  220. }
  221. }
  222. private DTDAutomata Sequence (DTDAutomata l, DTDAutomata r)
  223. {
  224. return root.Factory.Sequence (l, r);
  225. }
  226. private DTDAutomata Choice (DTDAutomata l, DTDAutomata r)
  227. {
  228. return l.MakeChoice (r);
  229. }
  230. }
  231. public class DTDContentModelCollection
  232. {
  233. ArrayList contentModel = new ArrayList ();
  234. public DTDContentModelCollection ()
  235. {
  236. }
  237. public DTDContentModel this [int i] {
  238. get { return contentModel [i] as DTDContentModel; }
  239. }
  240. public int Count {
  241. get { return contentModel.Count; }
  242. }
  243. public void Add (DTDContentModel model)
  244. {
  245. contentModel.Add (model);
  246. }
  247. }
  248. public abstract class DTDNode
  249. {
  250. private DTDObjectModel root;
  251. internal void SetRoot (DTDObjectModel root)
  252. {
  253. this.root = root;
  254. }
  255. protected DTDObjectModel Root {
  256. get { return root; }
  257. }
  258. }
  259. public class DTDElementDeclaration : DTDNode // : ICloneable
  260. {
  261. public string Name;
  262. public bool IsEmpty;
  263. public bool IsAny;
  264. public bool IsMixedContent;
  265. public DTDContentModel contentModel;
  266. DTDObjectModel root;
  267. internal DTDElementDeclaration (DTDObjectModel root)
  268. {
  269. this.root = root;
  270. }
  271. public DTDContentModel ContentModel {
  272. get {
  273. if (contentModel == null)
  274. contentModel = new DTDContentModel (root, Name);
  275. return contentModel;
  276. }
  277. }
  278. public DTDAttListDeclaration Attributes {
  279. get {
  280. return Root.AttListDecls [Name];
  281. }
  282. }
  283. // public object Clone ()
  284. // {
  285. // return this.MemberwiseClone ();
  286. // }
  287. }
  288. public class DTDAttributeDefinition : DTDNode// : ICloneable
  289. {
  290. public string Name;
  291. public XmlSchemaDatatype Datatype;
  292. // entity reference inside enumerated values are not allowed,
  293. // but on the other hand, they are allowed inside default value.
  294. // Then I decided to use string ArrayList for enumerated values,
  295. // and unresolved string value for DefaultValue.
  296. public ArrayList EnumeratedAttributeDeclaration = new ArrayList ();
  297. public string UnresolvedDefaultValue = null;
  298. public ArrayList EnumeratedNotations = new ArrayList();
  299. public DTDAttributeOccurenceType OccurenceType = DTDAttributeOccurenceType.None;
  300. private string resolvedDefaultValue;
  301. internal DTDAttributeDefinition () {}
  302. public string DefaultValue {
  303. get {
  304. if (resolvedDefaultValue == null)
  305. resolvedDefaultValue = ComputeDefaultValue ();
  306. return resolvedDefaultValue;
  307. }
  308. }
  309. private string ComputeDefaultValue ()
  310. {
  311. StringBuilder sb = new StringBuilder ();
  312. int pos = 0;
  313. int next = 0;
  314. while ((next = this.UnresolvedDefaultValue.IndexOf ('&', pos)) >= 0) {
  315. sb.Append (this.UnresolvedDefaultValue.Substring (pos, next - 1));
  316. int semicolon = this.UnresolvedDefaultValue.IndexOf (';', next);
  317. string name = this.UnresolvedDefaultValue.Substring (pos + 1, semicolon - 1);
  318. sb.Append (Root.ResolveEntity (name));
  319. }
  320. sb.Append (this.UnresolvedDefaultValue.Substring (pos));
  321. string ret = sb.ToString ();
  322. sb.Length = 0;
  323. return ret;
  324. }
  325. // public object Clone ()
  326. // {
  327. // return this.MemberwiseClone ();
  328. // }
  329. }
  330. public class DTDAttListDeclaration : DTDNode// : ICloneable
  331. {
  332. public string Name;
  333. internal DTDAttListDeclaration () {}
  334. private Hashtable attributeOrders = new Hashtable ();
  335. private Hashtable attributes = new Hashtable ();
  336. public DTDAttributeDefinition this [int i] {
  337. get { return Get (i); }
  338. }
  339. public DTDAttributeDefinition this [string name] {
  340. get { return Get (name); }
  341. }
  342. public DTDAttributeDefinition Get (int i)
  343. {
  344. return attributes [i] as DTDAttributeDefinition;
  345. }
  346. public DTDAttributeDefinition Get (string name)
  347. {
  348. return attributes [name] as DTDAttributeDefinition;
  349. }
  350. public ICollection Definitions {
  351. get { return attributes.Values; }
  352. }
  353. public void Add (DTDAttributeDefinition def)
  354. {
  355. if (attributes [def.Name] != null)
  356. throw new InvalidOperationException (String.Format (
  357. "Attribute definition for {0} was already added at element {1}.",
  358. def.Name, this.Name));
  359. def.SetRoot (Root);
  360. attributes.Add (def.Name, def);
  361. attributeOrders.Add (def.Name, attributeOrders.Count);
  362. }
  363. public int Count {
  364. get { return attributeOrders.Count; }
  365. }
  366. // public object Clone ()
  367. // {
  368. // return this.MemberwiseClone ();
  369. // }
  370. }
  371. public class DTDEntityDeclaration : DTDNode
  372. {
  373. public string Name;
  374. public string PublicId;
  375. public string SystemId;
  376. public string NotationName;
  377. // FIXME: should have more complex value than simple string
  378. public string EntityValue;
  379. internal DTDEntityDeclaration () {}
  380. }
  381. public class DTDNotationDeclaration : DTDNode
  382. {
  383. public string Name;
  384. public string LocalName;
  385. public string Prefix;
  386. public string PublicId;
  387. public string SystemId;
  388. internal DTDNotationDeclaration () {}
  389. }
  390. public class DTDParameterEntityDeclaration : DTDNode
  391. {
  392. public string Name;
  393. public string PublicId;
  394. public string SystemId;
  395. public string BaseURI;
  396. public string Value;
  397. }
  398. public enum DTDContentOrderType
  399. {
  400. None,
  401. Seq,
  402. Or
  403. }
  404. public enum DTDAttributeOccurenceType
  405. {
  406. None,
  407. Required,
  408. Optional,
  409. Fixed
  410. }
  411. public enum DTDOccurence
  412. {
  413. One,
  414. Optional,
  415. ZeroOrMore,
  416. OneOrMore
  417. }
  418. }