/Main/Source/ReflectionData/DatabaseIndexedDocument.cs

# · C# · 337 lines · 260 code · 64 blank · 13 comment · 16 complexity · b89a099b857696331c0c06e77beecf98 MD5 · raw file

  1. using System;
  2. using System.IO;
  3. using System.Text;
  4. using System.Xml;
  5. using System.Xml.Xsl;
  6. using System.Xml.XPath;
  7. using System.Collections.Generic;
  8. using Microsoft.Isam.Esent;
  9. using Microsoft.Isam.Esent.Interop;
  10. using Microsoft.Isam.Esent.Collections.Generic;
  11. namespace Sandcastle.ReflectionData
  12. {
  13. internal sealed class DatabaseIndexedDocument : IDisposable
  14. {
  15. #region Private Fields
  16. private bool _isSystem;
  17. private bool _isComments;
  18. private string _dataDir;
  19. // search pattern for index values
  20. private XPathExpression _valueExpression;
  21. // search pattern for the index keys (relative to the index value node)
  22. private XPathExpression _keyExpression;
  23. private XmlReaderSettings _settings;
  24. private PersistentDictionary<string, string> _plusTree;
  25. #endregion
  26. #region Constructors and Destructor
  27. public DatabaseIndexedDocument(bool isSystem, bool isComments,
  28. string workingDir)
  29. {
  30. _isSystem = isSystem;
  31. _isComments = isComments;
  32. _dataDir = workingDir;
  33. string keyXPath = null;
  34. string valueXPath = null;
  35. CustomContext context = new CustomContext();
  36. // The following are the usual key/value in the configuration file...
  37. if (_isComments)
  38. {
  39. // <index name="comments" value="/doc/members/member" key="@name" cache="100">
  40. keyXPath = "@name";
  41. valueXPath = "/doc/members/member";
  42. }
  43. else
  44. {
  45. // <index name="reflection" value="/reflection/apis/api" key="@id" cache="10">
  46. keyXPath = "@id";
  47. valueXPath = "/reflection/apis/api";
  48. }
  49. _keyExpression = XPathExpression.Compile(keyXPath);
  50. _keyExpression.SetContext(context);
  51. _valueExpression = XPathExpression.Compile(valueXPath);
  52. _valueExpression.SetContext(context);
  53. if (PersistentDictionaryFile.Exists(_dataDir))
  54. {
  55. PersistentDictionaryFile.DeleteFiles(_dataDir);
  56. }
  57. _plusTree = new PersistentDictionary<string, string>(_dataDir);
  58. }
  59. ~DatabaseIndexedDocument()
  60. {
  61. this.Dispose(false);
  62. }
  63. #endregion
  64. #region Public Properties
  65. public bool Exists
  66. {
  67. get
  68. {
  69. if (!String.IsNullOrEmpty(_dataDir) && Directory.Exists(_dataDir))
  70. {
  71. return PersistentDictionaryFile.Exists(_dataDir);
  72. }
  73. return false;
  74. }
  75. }
  76. public bool IsSystem
  77. {
  78. get
  79. {
  80. return _isSystem;
  81. }
  82. }
  83. public bool IsComments
  84. {
  85. get
  86. {
  87. return _isComments;
  88. }
  89. }
  90. public XPathExpression ValueExpression
  91. {
  92. get
  93. {
  94. return _valueExpression;
  95. }
  96. }
  97. public XPathExpression KeyExpression
  98. {
  99. get
  100. {
  101. return _keyExpression;
  102. }
  103. }
  104. #endregion
  105. #region Public Methods
  106. public XPathNavigator GetContent(string key)
  107. {
  108. XPathNavigator navigator = null;
  109. if (_plusTree != null && _plusTree.ContainsKey(key))
  110. {
  111. string innerXml = _plusTree[key];
  112. if (String.IsNullOrEmpty(innerXml))
  113. {
  114. return null;
  115. }
  116. if (_settings == null)
  117. {
  118. _settings = new XmlReaderSettings();
  119. _settings.ConformanceLevel = ConformanceLevel.Fragment;
  120. }
  121. StringReader textReader = new StringReader(innerXml);
  122. using (XmlReader reader = XmlReader.Create(textReader, _settings))
  123. {
  124. XPathDocument document = new XPathDocument(reader);
  125. navigator = document.CreateNavigator();
  126. }
  127. }
  128. return navigator;
  129. }
  130. public void AddDocument(string file)
  131. {
  132. BuildExceptions.NotNull(file, "file");
  133. // load the document
  134. XPathDocument document = new XPathDocument(file);
  135. // search for value nodes
  136. XPathNodeIterator valueNodes =
  137. document.CreateNavigator().Select(_valueExpression);
  138. // get the key string for each value node and record it in the index
  139. foreach (XPathNavigator valueNode in valueNodes)
  140. {
  141. XPathNavigator keyNode = valueNode.SelectSingleNode(_keyExpression);
  142. if (keyNode == null)
  143. {
  144. continue;
  145. }
  146. // The outer container interferes with the processing, so
  147. // we use the inner XML of the node...
  148. _plusTree[keyNode.Value] = valueNode.InnerXml;
  149. }
  150. }
  151. #endregion
  152. #region IDisposable Members
  153. public void Dispose()
  154. {
  155. this.Dispose(true);
  156. GC.SuppressFinalize(this);
  157. }
  158. private void Dispose(bool disposing)
  159. {
  160. if (_plusTree != null)
  161. {
  162. try
  163. {
  164. _plusTree.Dispose();
  165. _plusTree = null;
  166. // For the non-system reflection database, delete after use...
  167. if (!_isSystem)
  168. {
  169. if (!String.IsNullOrEmpty(_dataDir) &&
  170. Directory.Exists(_dataDir))
  171. {
  172. PersistentDictionaryFile.DeleteFiles(_dataDir);
  173. }
  174. }
  175. }
  176. catch
  177. {
  178. }
  179. }
  180. }
  181. #endregion
  182. #region CustomContext Class
  183. private sealed class CustomContext : XsltContext
  184. {
  185. // variable control
  186. private Dictionary<string, IXsltContextVariable> variables;
  187. public CustomContext()
  188. : base()
  189. {
  190. variables = new Dictionary<string, IXsltContextVariable>();
  191. }
  192. public string this[string variable]
  193. {
  194. get
  195. {
  196. return (variables[variable].Evaluate(this).ToString());
  197. }
  198. set
  199. {
  200. variables[variable] = new CustomVariable(value);
  201. }
  202. }
  203. public bool ClearVariable(string name)
  204. {
  205. return (variables.Remove(name));
  206. }
  207. public void ClearVariables()
  208. {
  209. variables.Clear();
  210. }
  211. // Implementation of XsltContext methods
  212. public override IXsltContextVariable ResolveVariable(
  213. string prefix, string name)
  214. {
  215. return (variables[name]);
  216. }
  217. public override IXsltContextFunction ResolveFunction(
  218. string prefix, string name, XPathResultType[] argumentTypes)
  219. {
  220. throw new NotImplementedException();
  221. }
  222. public override int CompareDocument(string baseUri, string nextBaseUri)
  223. {
  224. return (0);
  225. }
  226. public override bool Whitespace
  227. {
  228. get
  229. {
  230. return (true);
  231. }
  232. }
  233. public override bool PreserveWhitespace(XPathNavigator node)
  234. {
  235. return (true);
  236. }
  237. }
  238. private sealed class CustomVariable : IXsltContextVariable
  239. {
  240. private string value;
  241. public CustomVariable(string value)
  242. {
  243. this.value = value;
  244. }
  245. public bool IsLocal
  246. {
  247. get
  248. {
  249. return (false);
  250. }
  251. }
  252. public bool IsParam
  253. {
  254. get
  255. {
  256. return (false);
  257. }
  258. }
  259. public XPathResultType VariableType
  260. {
  261. get
  262. {
  263. return (XPathResultType.String);
  264. }
  265. }
  266. public Object Evaluate(XsltContext context)
  267. {
  268. return (value);
  269. }
  270. }
  271. #endregion
  272. }
  273. }