DOCX.cs 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.IO.Compression;
  5. using System.Xml;
  6. namespace DOCX
  7. {
  8. public class Docx : IDisposable
  9. {
  10. private readonly ZipArchive _zip;
  11. private readonly XmlNamespaceManager _ns = new XmlNamespaceManager(new NameTable());
  12. private readonly Dictionary<string, string> _namespaces = new Dictionary<string, string>
  13. {
  14. {"w", "http://schemas.openxmlformats.org/wordprocessingml/2006/main"}
  15. };
  16. private void LoadNamespaces()
  17. {
  18. foreach (var item in _namespaces)
  19. {
  20. _ns.AddNamespace(item.Key, item.Value);
  21. }
  22. }
  23. public Docx(string path)
  24. {
  25. _zip = ZipFile.Open(path, ZipArchiveMode.Update);
  26. LoadNamespaces();
  27. }
  28. public Docx(ZipArchive zipArchive)
  29. {
  30. _zip = zipArchive;
  31. LoadNamespaces();
  32. }
  33. private (XmlDocument doc, string message) GetXML(ZipArchiveEntry entry)
  34. {
  35. XmlDocument doc = new XmlDocument()
  36. {
  37. PreserveWhitespace = true // Disables auto-indent
  38. };
  39. try
  40. {
  41. using (StreamReader sr = new StreamReader(entry.Open()))
  42. {
  43. doc.Load(sr);
  44. }
  45. }
  46. catch (Exception e)
  47. {
  48. return (null, $"Error reading {entry.Name}!\n{e}");
  49. }
  50. return (doc, "OK");
  51. }
  52. private (bool status, string message) SaveXML(XmlDocument doc, ZipArchiveEntry entry)
  53. {
  54. try
  55. {
  56. using (StreamWriter sw = new StreamWriter(entry.Open()))
  57. {
  58. doc.Save(sw);
  59. }
  60. }
  61. catch (Exception e)
  62. {
  63. return (false, $"Error saving {entry.Name}!\n{e}");
  64. }
  65. return (true, "OK");
  66. }
  67. private (bool status, string message) AddTrackRevisions(ZipArchiveEntry settings)
  68. {
  69. var loadResult = GetXML(settings);
  70. if (loadResult.doc == null)
  71. return (false, loadResult.message);
  72. XmlDocument doc = loadResult.doc;
  73. if (doc.SelectSingleNode("//w:trackRevisions", _ns) != null) return (true, "No change needed.");
  74. XmlElement trackRevisions = doc.CreateElement("w", "trackRevisions", _namespaces["w"]);
  75. if (doc.DocumentElement == null)
  76. return (false, "No root element in settings.xml!");
  77. doc.DocumentElement.AppendChild(trackRevisions);
  78. return SaveXML(doc, settings);
  79. }
  80. public (bool status, string message) EnableTrackedChanges()
  81. {
  82. ZipArchiveEntry settings = _zip.GetEntry(@"word/settings.xml");
  83. if (settings == null)
  84. return (false,
  85. "Can't access settings.xml!");
  86. var result = AddTrackRevisions(settings);
  87. return !result.status ? (false, result.message) : (true, "OK");
  88. }
  89. public void Dispose()
  90. {
  91. Dispose(true);
  92. GC.SuppressFinalize(this);
  93. }
  94. ~Docx()
  95. {
  96. Dispose(false);
  97. }
  98. protected virtual void Dispose(bool disposing)
  99. {
  100. if (disposing)
  101. {
  102. _zip.Dispose();
  103. }
  104. }
  105. }
  106. }