DTDObjectModel.cs 14 KB

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