DTDObjectModel.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605
  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. DTDElementDeclarationCollection elementDecls;
  20. DTDAttListDeclarationCollection attListDecls;
  21. DTDEntityDeclarationCollection entityDecls;
  22. DTDNotationDeclarationCollection notationDecls;
  23. public DTDObjectModel ()
  24. {
  25. elementDecls = new DTDElementDeclarationCollection (this);
  26. attListDecls = new DTDAttListDeclarationCollection (this);
  27. entityDecls = new DTDEntityDeclarationCollection (this);
  28. notationDecls = new DTDNotationDeclarationCollection (this);
  29. factory = new DTDAutomataFactory (this);
  30. }
  31. public string Name;
  32. public string PublicId;
  33. public string SystemId;
  34. public string InternalSubset;
  35. public string ResolveEntity (string name)
  36. {
  37. DTDEntityDeclaration decl = EntityDecls [name]
  38. as DTDEntityDeclaration;
  39. return decl.EntityValue;
  40. }
  41. private DTDAutomataFactory factory;
  42. public DTDAutomataFactory Factory {
  43. get { return factory; }
  44. }
  45. public DTDElementDeclaration RootElement {
  46. get { return ElementDecls [Name]; }
  47. }
  48. public DTDElementDeclarationCollection ElementDecls {
  49. get { return elementDecls; }
  50. }
  51. public DTDAttListDeclarationCollection AttListDecls {
  52. get { return attListDecls; }
  53. }
  54. public DTDEntityDeclarationCollection EntityDecls {
  55. get { return entityDecls; }
  56. }
  57. public DTDNotationDeclarationCollection NotationDecls {
  58. get { return notationDecls; }
  59. }
  60. DTDElementAutomata rootAutomata;
  61. public DTDAutomata RootAutomata {
  62. get {
  63. if (rootAutomata == null)
  64. rootAutomata = new DTDElementAutomata (this, this.Name);
  65. return rootAutomata;
  66. }
  67. }
  68. DTDEmptyAutomata emptyAutomata;
  69. public DTDEmptyAutomata Empty {
  70. get {
  71. if (emptyAutomata == null)
  72. emptyAutomata = new DTDEmptyAutomata (this);
  73. return emptyAutomata;
  74. }
  75. }
  76. DTDAnyAutomata anyAutomata;
  77. public DTDAnyAutomata Any {
  78. get {
  79. if (anyAutomata == null)
  80. anyAutomata = new DTDAnyAutomata (this);
  81. return anyAutomata;
  82. }
  83. }
  84. DTDInvalidAutomata invalidAutomata;
  85. public DTDInvalidAutomata Invalid {
  86. get {
  87. if (invalidAutomata == null)
  88. invalidAutomata = new DTDInvalidAutomata (this);
  89. return invalidAutomata;
  90. }
  91. }
  92. }
  93. public class DTDElementDeclarationCollection
  94. {
  95. Hashtable elementDecls = new Hashtable ();
  96. DTDObjectModel root;
  97. public DTDElementDeclarationCollection (DTDObjectModel root)
  98. {
  99. this.root = root;
  100. }
  101. public DTDElementDeclaration this [string name] {
  102. get { return elementDecls [name] as DTDElementDeclaration; }
  103. }
  104. public void Add (string name, DTDElementDeclaration decl)
  105. {
  106. if (elementDecls [name] != null)
  107. throw new InvalidOperationException (String.Format (
  108. "Element declaration for {0} was already added.",
  109. name));
  110. decl.SetRoot (root);
  111. elementDecls.Add (name, decl);
  112. }
  113. public ICollection Keys {
  114. get { return elementDecls.Keys; }
  115. }
  116. public ICollection Values {
  117. get { return elementDecls.Values; }
  118. }
  119. }
  120. public class DTDAttListDeclarationCollection
  121. {
  122. Hashtable attListDecls = new Hashtable ();
  123. DTDObjectModel root;
  124. public DTDAttListDeclarationCollection (DTDObjectModel root)
  125. {
  126. this.root = root;
  127. }
  128. public DTDAttListDeclaration this [string name] {
  129. get { return attListDecls [name] as DTDAttListDeclaration; }
  130. }
  131. public void Add (string name, DTDAttListDeclaration decl)
  132. {
  133. DTDAttListDeclaration existing = this [name];
  134. if (existing != null) {
  135. // It should be valid and
  136. // has effect of additive declaration.
  137. foreach (DTDAttributeDefinition def in decl.Definitions)
  138. if (decl.Get (def.Name) == null)
  139. existing.Add (def);
  140. } else {
  141. decl.SetRoot (root);
  142. attListDecls.Add (name, decl);
  143. }
  144. }
  145. public ICollection Keys {
  146. get { return attListDecls.Keys; }
  147. }
  148. public ICollection Values {
  149. get { return attListDecls.Values; }
  150. }
  151. }
  152. public class DTDEntityDeclarationCollection
  153. {
  154. Hashtable entityDecls = new Hashtable ();
  155. DTDObjectModel root;
  156. public DTDEntityDeclarationCollection (DTDObjectModel root)
  157. {
  158. this.root = root;
  159. }
  160. public DTDEntityDeclaration this [string name] {
  161. get { return entityDecls [name] as DTDEntityDeclaration; }
  162. }
  163. public void Add (string name, DTDEntityDeclaration decl)
  164. {
  165. if (entityDecls [name] != null)
  166. throw new InvalidOperationException (String.Format (
  167. "Entity declaration for {0} was already added.",
  168. name));
  169. decl.SetRoot (root);
  170. entityDecls.Add (name, decl);
  171. }
  172. public ICollection Keys {
  173. get { return entityDecls.Keys; }
  174. }
  175. public ICollection Values {
  176. get { return entityDecls.Values; }
  177. }
  178. }
  179. public class DTDNotationDeclarationCollection
  180. {
  181. Hashtable notationDecls = new Hashtable ();
  182. DTDObjectModel root;
  183. public DTDNotationDeclarationCollection (DTDObjectModel root)
  184. {
  185. this.root = root;
  186. }
  187. public DTDNotationDeclaration this [string name] {
  188. get { return notationDecls [name] as DTDNotationDeclaration; }
  189. }
  190. public void Add (string name, DTDNotationDeclaration decl)
  191. {
  192. if (notationDecls [name] != null)
  193. throw new InvalidOperationException (String.Format (
  194. "Notation declaration for {0} was already added.",
  195. name));
  196. decl.SetRoot (root);
  197. notationDecls.Add (name, decl);
  198. }
  199. public ICollection Keys {
  200. get { return notationDecls.Keys; }
  201. }
  202. public ICollection Values {
  203. get { return notationDecls.Values; }
  204. }
  205. }
  206. public class DTDContentModel
  207. {
  208. private DTDObjectModel root;
  209. DTDAutomata compiledAutomata;
  210. private string ownerElementName;
  211. public string ElementName;
  212. public DTDContentOrderType OrderType = DTDContentOrderType.None;
  213. public DTDContentModelCollection ChildModels
  214. = new DTDContentModelCollection ();
  215. public DTDOccurence Occurence = DTDOccurence.One;
  216. internal DTDContentModel (DTDObjectModel root, string ownerElementName)
  217. {
  218. this.root = root;
  219. this.ownerElementName = ownerElementName;
  220. }
  221. public DTDElementDeclaration ElementDecl {
  222. get {
  223. return root.ElementDecls [ownerElementName];
  224. }
  225. }
  226. public DTDAutomata GetAutomata ()
  227. {
  228. if (compiledAutomata == null)
  229. Compile ();
  230. return compiledAutomata;
  231. }
  232. public DTDAutomata Compile ()
  233. {
  234. compiledAutomata = CompileInternal ();
  235. return compiledAutomata;
  236. }
  237. private DTDAutomata CompileInternal ()
  238. {
  239. if (ElementDecl.IsAny)
  240. return root.Any;
  241. if (ElementDecl.IsEmpty)
  242. return root.Empty;
  243. DTDAutomata basis = GetBasicContentAutomata ();
  244. switch (Occurence) {
  245. case DTDOccurence.One:
  246. return basis;
  247. case DTDOccurence.Optional:
  248. return Choice (root.Empty, basis);
  249. case DTDOccurence.OneOrMore:
  250. return new DTDOneOrMoreAutomata (root, basis);
  251. case DTDOccurence.ZeroOrMore:
  252. return Choice (root.Empty, new DTDOneOrMoreAutomata (root, basis));
  253. }
  254. throw new InvalidOperationException ();
  255. }
  256. private DTDAutomata GetBasicContentAutomata ()
  257. {
  258. if (ElementName != null)
  259. return new DTDElementAutomata (root, ElementName);
  260. switch (ChildModels.Count) {
  261. case 0:
  262. return root.Empty;
  263. case 1:
  264. return ChildModels [0].GetAutomata ();
  265. }
  266. DTDAutomata current = null;
  267. int childCount = ChildModels.Count;
  268. switch (OrderType) {
  269. case DTDContentOrderType.Seq:
  270. current = Sequence (
  271. ChildModels [childCount - 2].GetAutomata (),
  272. ChildModels [childCount - 1].GetAutomata ());
  273. for (int i = childCount - 2; i > 0; i--)
  274. current = Sequence (
  275. ChildModels [i - 1].GetAutomata (), current);
  276. return current;
  277. case DTDContentOrderType.Or:
  278. current = Choice (
  279. ChildModels [childCount - 2].GetAutomata (),
  280. ChildModels [childCount - 1].GetAutomata ());
  281. for (int i = childCount - 2; i > 0; i--)
  282. current = Choice (
  283. ChildModels [i - 1].GetAutomata (), current);
  284. return current;
  285. default:
  286. throw new InvalidOperationException ("Invalid pattern specification");
  287. }
  288. }
  289. private DTDAutomata Sequence (DTDAutomata l, DTDAutomata r)
  290. {
  291. return root.Factory.Sequence (l, r);
  292. }
  293. private DTDAutomata Choice (DTDAutomata l, DTDAutomata r)
  294. {
  295. return l.MakeChoice (r);
  296. }
  297. }
  298. public class DTDContentModelCollection
  299. {
  300. ArrayList contentModel = new ArrayList ();
  301. public DTDContentModelCollection ()
  302. {
  303. }
  304. public DTDContentModel this [int i] {
  305. get { return contentModel [i] as DTDContentModel; }
  306. }
  307. public int Count {
  308. get { return contentModel.Count; }
  309. }
  310. public void Add (DTDContentModel model)
  311. {
  312. contentModel.Add (model);
  313. }
  314. }
  315. public abstract class DTDNode
  316. {
  317. private DTDObjectModel root;
  318. internal void SetRoot (DTDObjectModel root)
  319. {
  320. this.root = root;
  321. }
  322. protected DTDObjectModel Root {
  323. get { return root; }
  324. }
  325. }
  326. public class DTDElementDeclaration : DTDNode // : ICloneable
  327. {
  328. public string Name;
  329. public bool IsEmpty;
  330. public bool IsAny;
  331. public bool IsMixedContent;
  332. public DTDContentModel contentModel;
  333. DTDObjectModel root;
  334. internal DTDElementDeclaration (DTDObjectModel root)
  335. {
  336. this.root = root;
  337. }
  338. public DTDContentModel ContentModel {
  339. get {
  340. if (contentModel == null)
  341. contentModel = new DTDContentModel (root, Name);
  342. return contentModel;
  343. }
  344. }
  345. public DTDAttListDeclaration Attributes {
  346. get {
  347. return Root.AttListDecls [Name];
  348. }
  349. }
  350. // public object Clone ()
  351. // {
  352. // return this.MemberwiseClone ();
  353. // }
  354. }
  355. public class DTDAttributeDefinition : DTDNode// : ICloneable
  356. {
  357. public string Name;
  358. public XmlSchemaDatatype Datatype;
  359. // entity reference inside enumerated values are not allowed,
  360. // but on the other hand, they are allowed inside default value.
  361. // Then I decided to use string ArrayList for enumerated values,
  362. // and unresolved string value for DefaultValue.
  363. public ArrayList EnumeratedAttributeDeclaration = new ArrayList ();
  364. public string UnresolvedDefaultValue = null;
  365. public ArrayList EnumeratedNotations = new ArrayList();
  366. public DTDAttributeOccurenceType OccurenceType = DTDAttributeOccurenceType.None;
  367. private string resolvedDefaultValue;
  368. private string resolvedNormalizedDefaultValue;
  369. internal DTDAttributeDefinition () {}
  370. public string DefaultValue {
  371. get {
  372. if (resolvedDefaultValue == null)
  373. resolvedDefaultValue = ComputeDefaultValue ();
  374. return resolvedDefaultValue;
  375. }
  376. }
  377. public string NormalizedDefaultValue {
  378. get {
  379. if (resolvedNormalizedDefaultValue == null) {
  380. object o = (string) Datatype.ParseValue (ComputeDefaultValue (), null, null);
  381. resolvedNormalizedDefaultValue =
  382. (o is string []) ?
  383. String.Join (" ", (string []) o) :
  384. o.ToString ();
  385. }
  386. return resolvedNormalizedDefaultValue;
  387. }
  388. }
  389. private string ComputeDefaultValue ()
  390. {
  391. if (UnresolvedDefaultValue == null)
  392. return null;
  393. StringBuilder sb = new StringBuilder ();
  394. int pos = 0;
  395. int next = 0;
  396. while ((next = this.UnresolvedDefaultValue.IndexOf ('&', pos)) >= 0) {
  397. sb.Append (this.UnresolvedDefaultValue.Substring (pos, next - 1));
  398. int semicolon = this.UnresolvedDefaultValue.IndexOf (';', next);
  399. string name = this.UnresolvedDefaultValue.Substring (pos + 1, semicolon - 1);
  400. sb.Append (Root.ResolveEntity (name));
  401. }
  402. sb.Append (this.UnresolvedDefaultValue.Substring (pos));
  403. // strip quote chars
  404. string ret = sb.ToString (1, sb.Length - 2);
  405. sb.Length = 0;
  406. return ret;
  407. }
  408. public char QuoteChar {
  409. get {
  410. return UnresolvedDefaultValue.Length > 0 ?
  411. this.UnresolvedDefaultValue [0] :
  412. '"';
  413. }
  414. }
  415. // public object Clone ()
  416. // {
  417. // return this.MemberwiseClone ();
  418. // }
  419. }
  420. public class DTDAttListDeclaration : DTDNode // : ICloneable
  421. {
  422. public string Name;
  423. internal DTDAttListDeclaration () {}
  424. private Hashtable attributeOrders = new Hashtable ();
  425. private ArrayList attributes = new ArrayList ();
  426. public DTDAttributeDefinition this [int i] {
  427. get { return Get (i); }
  428. }
  429. public DTDAttributeDefinition this [string name] {
  430. get { return Get (name); }
  431. }
  432. public DTDAttributeDefinition Get (int i)
  433. {
  434. return attributes [i] as DTDAttributeDefinition;
  435. }
  436. public DTDAttributeDefinition Get (string name)
  437. {
  438. object o = attributeOrders [name];
  439. if (o != null)
  440. return attributes [(int) o] as DTDAttributeDefinition;
  441. else
  442. return null;
  443. }
  444. public ICollection Definitions {
  445. get { return attributes; }
  446. }
  447. public void Add (DTDAttributeDefinition def)
  448. {
  449. if (attributeOrders [def.Name] != null)
  450. throw new InvalidOperationException (String.Format (
  451. "Attribute definition for {0} was already added at element {1}.",
  452. def.Name, this.Name));
  453. def.SetRoot (Root);
  454. attributeOrders.Add (def.Name, attributes.Count);
  455. attributes.Add (def);
  456. }
  457. public int Count {
  458. get { return attributeOrders.Count; }
  459. }
  460. // public object Clone ()
  461. // {
  462. // return this.MemberwiseClone ();
  463. // }
  464. }
  465. public class DTDEntityDeclaration : DTDNode
  466. {
  467. public string Name;
  468. public string PublicId;
  469. public string SystemId;
  470. public string NotationName;
  471. // FIXME: should have more complex value than simple string
  472. public string EntityValue;
  473. internal DTDEntityDeclaration () {}
  474. }
  475. public class DTDNotationDeclaration : DTDNode
  476. {
  477. public string Name;
  478. public string LocalName;
  479. public string Prefix;
  480. public string PublicId;
  481. public string SystemId;
  482. internal DTDNotationDeclaration () {}
  483. }
  484. public class DTDParameterEntityDeclaration : DTDNode
  485. {
  486. public string Name;
  487. public string PublicId;
  488. public string SystemId;
  489. public string BaseURI;
  490. public string Value;
  491. }
  492. public enum DTDContentOrderType
  493. {
  494. None,
  495. Seq,
  496. Or
  497. }
  498. public enum DTDAttributeOccurenceType
  499. {
  500. None,
  501. Required,
  502. Optional,
  503. Fixed
  504. }
  505. public enum DTDOccurence
  506. {
  507. One,
  508. Optional,
  509. ZeroOrMore,
  510. OneOrMore
  511. }
  512. }