Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Xml.Linq;
  6. using System.Xml;
  7. using System.IO;
  8. using System.Text.RegularExpressions;
  9. using System.IO.Packaging;
  10. using System.Security.Principal;
  11. using System.Reflection;
  12. using System.IO.Compression;
  13. namespace Novacode
  14. {
  15. /// <summary>
  16. /// Represents a document.
  17. /// </summary>
  18. public class DocX: Container, IDisposable
  19. {
  20. #region Namespaces
  21. static internal XNamespace w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
  22. static internal XNamespace r = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
  23. static internal XNamespace customPropertiesSchema = "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties";
  24. static internal XNamespace customVTypesSchema = "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes";
  25. #endregion
  26. /// <summary>
  27. /// Returns a collection of Headers in this Document.
  28. /// A document typically contains three Headers.
  29. /// A default one (odd), one for the first page and one for even pages.
  30. /// </summary>
  31. /// <example>
  32. /// <code>
  33. /// // Create a document.
  34. /// using (DocX document = DocX.Create(@"Test.docx"))
  35. /// {
  36. /// // Add header support to this document.
  37. /// document.AddHeaders();
  38. ///
  39. /// // Get a collection of all headers in this document.
  40. /// Headers headers = document.Headers;
  41. ///
  42. /// // The header used for the first page of this document.
  43. /// Header first = headers.first;
  44. ///
  45. /// // The header used for odd pages of this document.
  46. /// Header odd = headers.odd;
  47. ///
  48. /// // The header used for even pages of this document.
  49. /// Header even = headers.even;
  50. /// }
  51. /// </code>
  52. /// </example>
  53. public Headers Headers
  54. {
  55. get
  56. {
  57. return headers;
  58. }
  59. }
  60. private Headers headers;
  61. /// <summary>
  62. /// Returns a collection of Footers in this Document.
  63. /// A document typically contains three Footers.
  64. /// A default one (odd), one for the first page and one for even pages.
  65. /// </summary>
  66. /// <example>
  67. /// <code>
  68. /// // Create a document.
  69. /// using (DocX document = DocX.Create(@"Test.docx"))
  70. /// {
  71. /// // Add footer support to this document.
  72. /// document.AddFooters();
  73. ///
  74. /// // Get a collection of all footers in this document.
  75. /// Footers footers = document.Footers;
  76. ///
  77. /// // The footer used for the first page of this document.
  78. /// Footer first = footers.first;
  79. ///
  80. /// // The footer used for odd pages of this document.
  81. /// Footer odd = footers.odd;
  82. ///
  83. /// // The footer used for even pages of this document.
  84. /// Footer even = footers.even;
  85. /// }
  86. /// </code>
  87. /// </example>
  88. public Footers Footers
  89. {
  90. get
  91. {
  92. return footers;
  93. }
  94. }
  95. private Footers footers;
  96. /// <summary>
  97. /// Should the Document use different Headers and Footers for odd and even pages?
  98. /// </summary>
  99. /// // Create a document.
  100. /// using (DocX document = DocX.Create(@"Test.docx"))
  101. /// {
  102. /// // Add header support to this document.
  103. /// document.AddHeaders();
  104. ///
  105. /// // Get a collection of all headers in this document.
  106. /// Headers headers = document.Headers;
  107. ///
  108. /// // The header used for odd pages of this document.
  109. /// Header odd = headers.odd;
  110. ///
  111. /// // The header used for even pages of this document.
  112. /// Header even = headers.even;
  113. ///
  114. /// // Force the document to use a different header for odd and even pages.
  115. /// document.DifferentOddAndEvenPages = true;
  116. ///
  117. /// // Content can be added to the Headers in the same manor that it would be added to the main document.
  118. /// Paragraph p1 = odd.InsertParagraph();
  119. /// p1.Append("This is the odd pages header.");
  120. ///
  121. /// Paragraph p2 = even.InsertParagraph();
  122. /// p2.Append("This is the even pages header.");
  123. ///
  124. /// // Save all changes to this document.
  125. /// document.Save();
  126. /// }// Release this document from memory.
  127. /// </example>
  128. public bool DifferentOddAndEvenPages
  129. {
  130. get
  131. {
  132. XDocument settings;
  133. using (TextReader tr = new StreamReader(settingsPart.GetStream()))
  134. settings = XDocument.Load(tr);
  135. XElement evenAndOddHeaders = settings.Root.Element(w + "evenAndOddHeaders");
  136. return evenAndOddHeaders != null;
  137. }
  138. set
  139. {
  140. XDocument settings;
  141. using (TextReader tr = new StreamReader(settingsPart.GetStream()))
  142. settings = XDocument.Load(tr);
  143. XElement evenAndOddHeaders = settings.Root.Element(w + "evenAndOddHeaders");
  144. if (evenAndOddHeaders == null)
  145. {
  146. if (value)
  147. settings.Root.AddFirst(new XElement(w + "evenAndOddHeaders"));
  148. }
  149. else
  150. {
  151. if (!value)
  152. evenAndOddHeaders.Remove();
  153. }
  154. using (TextWriter tw = new StreamWriter(settingsPart.GetStream()))
  155. settings.Save(tw);
  156. }
  157. }
  158. /// <summary>
  159. /// Should the Document use an independent Header and Footer for the first page?
  160. /// </summary>
  161. /// <example>
  162. /// // Create a document.
  163. /// using (DocX document = DocX.Create(@"Test.docx"))
  164. /// {
  165. /// // Add header support to this document.
  166. /// document.AddHeaders();
  167. ///
  168. /// // The header used for the first page of this document.
  169. /// Header first = document.Headers.first;
  170. ///
  171. /// // Force the document to use a different header for first page.
  172. /// document.DifferentFirstPage = true;
  173. ///
  174. /// // Content can be added to the Headers in the same manor that it would be added to the main document.
  175. /// Paragraph p = first.InsertParagraph();
  176. /// p.Append("This is the first pages header.");
  177. ///
  178. /// // Save all changes to this document.
  179. /// document.Save();
  180. /// }// Release this document from memory.
  181. /// </example>
  182. public bool DifferentFirstPage
  183. {
  184. get
  185. {
  186. XElement body = mainDoc.Root.Element(w + "body");
  187. XElement sectPr = body.Element(w + "sectPr");
  188. if (sectPr != null)
  189. {
  190. XElement titlePg = sectPr.Element(w + "titlePg");
  191. if (titlePg != null)
  192. return true;
  193. }
  194. return false;
  195. }
  196. set
  197. {
  198. XElement body = mainDoc.Root.Element(w + "body");
  199. XElement sectPr = null;
  200. XElement titlePg = null;
  201. if (sectPr == null)
  202. body.Add(new XElement(w + "sectPr", string.Empty));
  203. sectPr = body.Element(w + "sectPr");
  204. titlePg = sectPr.Element(w + "titlePg");
  205. if (titlePg == null)
  206. {
  207. if (value)
  208. sectPr.Add(new XElement(w + "titlePg", string.Empty));
  209. }
  210. else
  211. {
  212. if (!value)
  213. titlePg.Remove();
  214. }
  215. }
  216. }
  217. private Header GetHeaderByType(string type)
  218. {
  219. return (Header)GetHeaderOrFooterByType(type, true);
  220. }
  221. private Footer GetFooterByType(string type)
  222. {
  223. return (Footer)GetHeaderOrFooterByType(type, false);
  224. }
  225. private object GetHeaderOrFooterByType(string type, bool b)
  226. {
  227. string reference = "footerReference";
  228. if (b)
  229. reference = "headerReference";
  230. string Id =
  231. (
  232. from e in mainDoc.Descendants(XName.Get("body", DocX.w.NamespaceName)).Descendants()
  233. where (e.Name.LocalName == reference) && (e.Attribute(w + "type").Value == type)
  234. select e.Attribute(r + "id").Value
  235. ).FirstOrDefault();
  236. if (Id != null)
  237. {
  238. Uri partUri = mainPart.GetRelationship(Id).TargetUri;
  239. if (!partUri.OriginalString.StartsWith("/word/"))
  240. partUri = new Uri("/word/" + partUri.OriginalString, UriKind.Relative);
  241. PackagePart part = package.GetPart(partUri);
  242. XDocument doc;
  243. using (TextReader tr = new StreamReader(part.GetStream()))
  244. {
  245. doc = XDocument.Load(tr);
  246. if(b)
  247. return new Header(this, doc.Element(w + "hdr"), part);
  248. else
  249. return new Footer(this, doc.Element(w + "ftr"), part);
  250. }
  251. }
  252. return null;
  253. }
  254. // Get the word\document.xml part
  255. internal PackagePart mainPart;
  256. // Get the word\settings.xml part
  257. internal PackagePart settingsPart;
  258. #region Private instance variables defined foreach DocX object
  259. // The collection of Paragraphs in this document.
  260. internal List<Paragraph> paragraphs = new List<Paragraph>();
  261. #endregion
  262. #region Internal variables defined foreach DocX object
  263. // Object representation of the .docx
  264. internal Package package;
  265. // The mainDocument is loaded into a XDocument object for easy querying and editing
  266. internal XDocument mainDoc;
  267. internal XDocument header1;
  268. internal XDocument header2;
  269. internal XDocument header3;
  270. // A lookup for the Paragraphs in this document.
  271. internal Dictionary<int, Paragraph> paragraphLookup = new Dictionary<int, Paragraph>();
  272. // Every document is stored in a MemoryStream, all edits made to a document are done in memory.
  273. internal MemoryStream memoryStream;
  274. // The filename that this document was loaded from
  275. internal string filename;
  276. // The stream that this document was loaded from
  277. internal Stream stream;
  278. #endregion
  279. internal DocX(DocX document, XElement xml): base(document, xml)
  280. {
  281. }
  282. /// <summary>
  283. /// Returns a list of Images in this document.
  284. /// </summary>
  285. /// <example>
  286. /// Get the unique Id of every Image in this document.
  287. /// <code>
  288. /// // Load a document.
  289. /// DocX document = DocX.Load(@"C:\Example\Test.docx");
  290. ///
  291. /// // Loop through each Image in this document.
  292. /// foreach (Novacode.Image i in document.Images)
  293. /// {
  294. /// // Get the unique Id which identifies this Image.
  295. /// string uniqueId = i.Id;
  296. /// }
  297. ///
  298. /// </code>
  299. /// </example>
  300. /// <seealso cref="AddImage(string)"/>
  301. /// <seealso cref="AddImage(Stream)"/>
  302. /// <seealso cref="Paragraph.Pictures"/>
  303. /// <seealso cref="Paragraph.InsertPicture"/>
  304. public List<Image> Images
  305. {
  306. get
  307. {
  308. PackageRelationshipCollection imageRelationships = mainPart.GetRelationshipsByType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/image");
  309. if (imageRelationships.Count() > 0)
  310. {
  311. return
  312. (
  313. from i in imageRelationships
  314. select new Image(this, i)
  315. ).ToList();
  316. }
  317. return new List<Image>();
  318. }
  319. }
  320. /// <summary>
  321. /// Returns a list of custom properties in this document.
  322. /// </summary>
  323. /// <example>
  324. /// Method 1: Get the name, type and value of each CustomProperty in this document.
  325. /// <code>
  326. /// // Load Example.docx
  327. /// DocX document = DocX.Load(@"C:\Example\Test.docx");
  328. ///
  329. /// /*
  330. /// * No two custom properties can have the same name,
  331. /// * so a Dictionary is the perfect data structure to store them in.
  332. /// * Each custom property can be accessed using its name.
  333. /// */
  334. /// foreach (string name in document.CustomProperties.Keys)
  335. /// {
  336. /// // Grab a custom property using its name.
  337. /// CustomProperty cp = document.CustomProperties[name];
  338. ///
  339. /// // Write this custom properties details to Console.
  340. /// Console.WriteLine(string.Format("Name: '{0}', Value: {1}", cp.Name, cp.Value));
  341. /// }
  342. ///
  343. /// Console.WriteLine("Press any key...");
  344. ///
  345. /// // Wait for the user to press a key before closing the Console.
  346. /// Console.ReadKey();
  347. /// </code>
  348. /// </example>
  349. /// <example>
  350. /// Method 2: Get the name, type and value of each CustomProperty in this document.
  351. /// <code>
  352. /// // Load Example.docx
  353. /// DocX document = DocX.Load(@"C:\Example\Test.docx");
  354. ///
  355. /// /*
  356. /// * No two custom properties can have the same name,
  357. /// * so a Dictionary is the perfect data structure to store them in.
  358. /// * The values of this Dictionary are CustomProperties.
  359. /// */
  360. /// foreach (CustomProperty cp in document.CustomProperties.Values)
  361. /// {
  362. /// // Write this custom properties details to Console.
  363. /// Console.WriteLine(string.Format("Name: '{0}', Value: {1}", cp.Name, cp.Value));
  364. /// }
  365. ///
  366. /// Console.WriteLine("Press any key...");
  367. ///
  368. /// // Wait for the user to press a key before closing the Console.
  369. /// Console.ReadKey();
  370. /// </code>
  371. /// </example>
  372. /// <seealso cref="AddCustomProperty"/>
  373. public Dictionary<string, CustomProperty> CustomProperties
  374. {
  375. get
  376. {
  377. if (package.PartExists(new Uri("/docProps/custom.xml", UriKind.Relative)))
  378. {
  379. PackagePart docProps_custom = package.GetPart(new Uri("/docProps/custom.xml", UriKind.Relative));
  380. XDocument customPropDoc;
  381. using (TextReader tr = new StreamReader(docProps_custom.GetStream(FileMode.Open, FileAccess.Read)))
  382. customPropDoc = XDocument.Load(tr, LoadOptions.PreserveWhitespace);
  383. // Get all of the custom properties in this document
  384. return
  385. (
  386. from p in customPropDoc.Descendants(XName.Get("property", customPropertiesSchema.NamespaceName))
  387. let Name = p.Attribute(XName.Get("name")).Value
  388. let Type = p.Descendants().Single().Name.LocalName
  389. let Value = p.Descendants().Single().Value
  390. select new CustomProperty(Name, Type, Value)
  391. ).ToDictionary(p => p.Name, StringComparer.CurrentCultureIgnoreCase);
  392. }
  393. return new Dictionary<string, CustomProperty>();
  394. }
  395. }
  396. /// <summary>
  397. /// Get the Text of this document.
  398. /// </summary>
  399. /// <example>
  400. /// Write to Console the Text from this document.
  401. /// <code>
  402. /// // Load a document
  403. /// DocX document = DocX.Load(@"C:\Example\Test.docx");
  404. ///
  405. /// // Get the text of this document.
  406. /// string text = document.Text;
  407. ///
  408. /// // Write the text of this document to Console.
  409. /// Console.Write(text);
  410. ///
  411. /// // Wait for the user to press a key before closing the console window.
  412. /// Console.ReadKey();
  413. /// </code>
  414. /// </example>
  415. public string Text
  416. {
  417. get
  418. {
  419. string text = string.Empty;
  420. foreach (Paragraph p in paragraphs)
  421. {
  422. text += p.Text + "\n";
  423. }
  424. return text;
  425. }
  426. }
  427. internal string GetCollectiveText(List<PackagePart> list)
  428. {
  429. string text = string.Empty;
  430. foreach (var hp in list)
  431. {
  432. using (TextReader tr = new StreamReader(hp.GetStream()))
  433. {
  434. XDocument d = XDocument.Load(tr);
  435. StringBuilder sb = new StringBuilder();
  436. // Loop through each text item in this run
  437. foreach (XElement descendant in d.Descendants())
  438. {
  439. switch (descendant.Name.LocalName)
  440. {
  441. case "tab":
  442. sb.Append("\t");
  443. break;
  444. case "br":
  445. sb.Append("\n");
  446. break;
  447. case "t":
  448. goto case "delText";
  449. case "delText":
  450. sb.Append(descendant.Value);
  451. break;
  452. default: break;
  453. }
  454. }
  455. text += "\n" + sb.ToString();
  456. }
  457. }
  458. return text;
  459. }
  460. /// <summary>
  461. /// Insert the contents of another document at the end of this document.
  462. /// </summary>
  463. /// <param name="document">The document to insert at the end of this document.</param>
  464. /// <example>
  465. /// Create a new document and insert an old document into it.
  466. /// <code>
  467. /// // Create a new document.
  468. /// using (DocX newDocument = DocX.Create(@"NewDocument.docx"))
  469. /// {
  470. /// // Load an old document.
  471. /// using (DocX oldDocument = DocX.Load(@"OldDocument.docx"))
  472. /// {
  473. /// // Insert the old document into the new document.
  474. /// newDocument.InsertDocument(oldDocument);
  475. ///
  476. /// // Save the new document.
  477. /// newDocument.Save();
  478. /// }// Release the old document from memory.
  479. /// }// Release the new document from memory.
  480. /// </code>
  481. /// <remarks>
  482. /// If the document being inserted contains Images, CustomProperties and or custom styles, these will be correctly inserted into the new document. In the case of Images, new ID's are generated for the Images being inserted to avoid ID conflicts. CustomProperties with the same name will be ignored not replaced.
  483. /// </remarks>
  484. /// </example>
  485. public void InsertDocument(DocX document)
  486. {
  487. #region /word/document.xml
  488. // Get the external elements that are going to be inserted.
  489. IEnumerable<XElement> external_elements = document.mainDoc.Root.Element(XName.Get("body", DocX.w.NamespaceName)).Elements();
  490. // Get the body element of the internal document.
  491. XElement internal_body = mainDoc.Root.Element(XName.Get("body", DocX.w.NamespaceName));
  492. // Insert the elements
  493. internal_body.Add(external_elements);
  494. // A moment of genius
  495. int count = external_elements.Count();
  496. external_elements = internal_body.Elements().Reverse().TakeWhile((i, j) => j < count);
  497. #endregion
  498. #region /word/styles.xml
  499. Uri word_styles_Uri = new Uri("/word/styles.xml", UriKind.Relative);
  500. // If the external document has a styles.xml, we need to insert its elements into the internal documents styles.xml.
  501. if (document.package.PartExists(word_styles_Uri))
  502. {
  503. // Load the external documents styles.xml into memory.
  504. XDocument external_word_styles;
  505. using (TextReader tr = new StreamReader(document.package.GetPart(word_styles_Uri).GetStream()))
  506. external_word_styles = XDocument.Load(tr);
  507. // If the internal document contains no /word/styles.xml create one.
  508. if (!package.PartExists(word_styles_Uri))
  509. HelperFunctions.AddDefaultStylesXml(package);
  510. // Load the internal documents styles.xml into memory.
  511. XDocument internal_word_styles;
  512. using (TextReader tr = new StreamReader(package.GetPart(word_styles_Uri).GetStream()))
  513. internal_word_styles = XDocument.Load(tr);
  514. // Create a list of internal and external style elements for easy iteration.
  515. var internal_style_list = internal_word_styles.Root.Elements(XName.Get("style", DocX.w.NamespaceName));
  516. var external_style_list = external_word_styles.Root.Elements(XName.Get("style", DocX.w.NamespaceName));
  517. // Loop through the external style elements
  518. foreach (XElement style in external_style_list)
  519. {
  520. // If the internal styles document does not contain this element, add it.
  521. if (!internal_style_list.Contains(style))
  522. internal_word_styles.Root.Add(style);
  523. }
  524. // Save the internal styles document.
  525. using (TextWriter tw = new StreamWriter(package.GetPart(word_styles_Uri).GetStream()))
  526. internal_word_styles.Save(tw);
  527. }
  528. #endregion
  529. #region Images
  530. PackagePart internal_word_document = mainPart;
  531. PackagePart external_word_document = document.mainPart;
  532. // Get all Image relationships in the external document.
  533. var external_image_rels = external_word_document.GetRelationshipsByType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/image");
  534. // Get all Image relationships in the internal document.
  535. var internal_image_rels = internal_word_document.GetRelationshipsByType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/image");
  536. var internal_image_parts = internal_image_rels.Select(ir => package.GetParts().Where(p => p.Uri.ToString().EndsWith(ir.TargetUri.ToString())).First());
  537. int max = 0;
  538. var values =
  539. (
  540. from ip in internal_image_parts
  541. let Name = Path.GetFileNameWithoutExtension(ip.Uri.ToString())
  542. let Number = Regex.Match(Name, @"\d+$").Value
  543. select Number != string.Empty ? int.Parse(Number) : 0
  544. );
  545. if (values.Count() > 0)
  546. max = Math.Max(max, values.Max());
  547. // Foreach external image relationship
  548. foreach (var rel in external_image_rels)
  549. {
  550. string uri_string = rel.TargetUri.ToString();
  551. if (!uri_string.StartsWith("/"))
  552. uri_string = "/" + uri_string;
  553. PackagePart external_image_part = rel.Package.GetPart(new Uri("/word" + uri_string, UriKind.RelativeOrAbsolute));
  554. PackagePart internal_image_part = package.CreatePart(new Uri(string.Format("/word/media/image{0}.jpeg", max + 1), UriKind.RelativeOrAbsolute), System.Net.Mime.MediaTypeNames.Image.Jpeg);
  555. PackageRelationship pr = internal_word_document.CreateRelationship(internal_image_part.Uri, TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image");
  556. var query = from e in external_elements.DescendantsAndSelf()
  557. let embed = e.Attribute(XName.Get("embed", "http://schemas.openxmlformats.org/officeDocument/2006/relationships"))
  558. where embed != null && embed.Value == rel.Id
  559. select embed;
  560. foreach (XAttribute a in query)
  561. a.Value = pr.Id;
  562. using (Stream stream = internal_image_part.GetStream(FileMode.Create, FileAccess.Write))
  563. {
  564. using (Stream s = external_image_part.GetStream())
  565. {
  566. byte[] bytes = new byte[s.Length];
  567. s.Read(bytes, 0, (int)s.Length);
  568. stream.Write(bytes, 0, (int)s.Length);
  569. }
  570. }
  571. max++;
  572. }
  573. #endregion
  574. #region CustomProperties
  575. // Check if the external document contains custom properties.
  576. if (document.package.PartExists(new Uri("/docProps/custom.xml", UriKind.Relative)))
  577. {
  578. PackagePart external_docProps_custom = document.package.GetPart(new Uri("/docProps/custom.xml", UriKind.Relative));
  579. XDocument external_customPropDoc;
  580. using (TextReader tr = new StreamReader(external_docProps_custom.GetStream(FileMode.Open, FileAccess.Read)))
  581. external_customPropDoc = XDocument.Load(tr, LoadOptions.PreserveWhitespace);
  582. // Get all of the custom properties in this document.
  583. IEnumerable<XElement> external_customProperties =
  584. (
  585. from cp in external_customPropDoc.Descendants(XName.Get("property", customPropertiesSchema.NamespaceName))
  586. select cp
  587. );
  588. // If the internal document does not contain a customFilePropertyPart, create one.
  589. if (!package.PartExists(new Uri("/docProps/custom.xml", UriKind.Relative)))
  590. HelperFunctions.CreateCustomPropertiesPart(this);
  591. PackagePart internal_docProps_custom = package.GetPart(new Uri("/docProps/custom.xml", UriKind.Relative));
  592. XDocument internal_customPropDoc;
  593. using (TextReader tr = new StreamReader(internal_docProps_custom.GetStream(FileMode.Open, FileAccess.Read)))
  594. internal_customPropDoc = XDocument.Load(tr, LoadOptions.PreserveWhitespace);
  595. foreach (XElement cp in external_customProperties)
  596. {
  597. // Does the internal document already have a custom property with this name?
  598. XElement conflict =
  599. (
  600. from d in internal_customPropDoc.Descendants(XName.Get("property", customPropertiesSchema.NamespaceName))
  601. let ExternalName = d.Attribute(XName.Get("name", customPropertiesSchema.NamespaceName))
  602. let InternalName = cp.Attribute(XName.Get("name", customPropertiesSchema.NamespaceName))
  603. where ExternalName != null && InternalName != null && ExternalName == InternalName
  604. select d
  605. ).FirstOrDefault();
  606. // Same name
  607. if (conflict != null)
  608. {
  609. }
  610. // There is no conflict, just add the Custom Property.
  611. else
  612. internal_customPropDoc.Root.Add(cp);
  613. }
  614. using (TextWriter tw = new StreamWriter(internal_docProps_custom.GetStream(FileMode.Open, FileAccess.Write)))
  615. internal_customPropDoc.Save(tw);
  616. }
  617. #endregion
  618. // A document can only have one header and one footer.
  619. #region Remove external (header & footer) references
  620. var externalHeaderAndFooterReferences =
  621. (
  622. from d in external_elements.Descendants()
  623. where d.Name.LocalName == "headerReference" || d.Name.LocalName == "footerReference"
  624. select d
  625. );
  626. foreach (var r in externalHeaderAndFooterReferences.ToList())
  627. r.Remove();
  628. #endregion
  629. HelperFunctions.RebuildParagraphs(this);
  630. }
  631. /// <summary>
  632. /// Insert a new Table at the end of this document.
  633. /// </summary>
  634. /// <param name="coloumnCount">The number of coloumns to create.</param>
  635. /// <param name="rowCount">The number of rows to create.</param>
  636. /// <returns>A new Table.</returns>
  637. /// <example>
  638. /// Insert a new Table with 2 coloumns and 3 rows, at the end of a document.
  639. /// <code>
  640. /// // Create a document.
  641. /// using (DocX document = DocX.Create(@"C:\Example\Test.docx"))
  642. /// {
  643. /// // Create a new Table with 2 coloumns and 3 rows.
  644. /// Table newTable = document.InsertTable(2, 3);
  645. ///
  646. /// // Set the design of this Table.
  647. /// newTable.Design = TableDesign.LightShadingAccent2;
  648. ///
  649. /// // Set the coloumn names.
  650. /// newTable.Rows[0].Cells[0].Paragraph.InsertText("Ice Cream", false);
  651. /// newTable.Rows[0].Cells[1].Paragraph.InsertText("Price", false);
  652. ///
  653. /// // Fill row 1
  654. /// newTable.Rows[1].Cells[0].Paragraph.InsertText("Chocolate", false);
  655. /// newTable.Rows[1].Cells[1].Paragraph.InsertText("€3:50", false);
  656. ///
  657. /// // Fill row 2
  658. /// newTable.Rows[2].Cells[0].Paragraph.InsertText("Vanilla", false);
  659. /// newTable.Rows[2].Cells[1].Paragraph.InsertText("€3:00", false);
  660. ///
  661. /// // Save all changes made to document b.
  662. /// document.Save();
  663. /// }// Release this document from memory.
  664. /// </code>
  665. /// </example>
  666. public Table InsertTable(int coloumnCount, int rowCount)
  667. {
  668. XElement newTable = HelperFunctions.CreateTable(rowCount, coloumnCount);
  669. mainDoc.Descendants(XName.Get("body", DocX.w.NamespaceName)).First().Add(newTable);
  670. HelperFunctions.RebuildParagraphs(this);
  671. return new Table(this, newTable);
  672. }
  673. public Table AddTable(int rowCount, int coloumnCount)
  674. {
  675. return (new Table(this, HelperFunctions.CreateTable(rowCount, coloumnCount)));
  676. }
  677. /// <summary>
  678. /// Insert a Table into this document. The Table's source can be a completely different document.
  679. /// </summary>
  680. /// <param name="t">The Table to insert.</param>
  681. /// <param name="index">The index to insert this Table at.</param>
  682. /// <returns>The Table now associated with this document.</returns>
  683. /// <example>
  684. /// Extract a Table from document a and insert it into document b, at index 10.
  685. /// <code>
  686. /// // Place holder for a Table.
  687. /// Table t;
  688. ///
  689. /// // Load document a.
  690. /// using (DocX documentA = DocX.Load(@"C:\Example\a.docx"))
  691. /// {
  692. /// // Get the first Table from this document.
  693. /// t = documentA.Tables[0];
  694. /// }
  695. ///
  696. /// // Load document b.
  697. /// using (DocX documentB = DocX.Load(@"C:\Example\b.docx"))
  698. /// {
  699. /// /*
  700. /// * Insert the Table that was extracted from document a, into document b.
  701. /// * This creates a new Table that is now associated with document b.
  702. /// */
  703. /// Table newTable = documentB.InsertTable(10, t);
  704. ///
  705. /// // Save all changes made to document b.
  706. /// documentB.Save();
  707. /// }// Release this document from memory.
  708. /// </code>
  709. /// </example>
  710. public Table InsertTable(int index, Table t)
  711. {
  712. Paragraph p = HelperFunctions.GetFirstParagraphEffectedByInsert(this, index);
  713. XElement[] split = HelperFunctions.SplitParagraph(p, index - p.startIndex);
  714. XElement newXElement = new XElement(t.Xml);
  715. p.Xml.ReplaceWith
  716. (
  717. split[0],
  718. newXElement,
  719. split[1]
  720. );
  721. Table newTable = new Table(this, newXElement);
  722. newTable.Design = t.Design;
  723. HelperFunctions.RebuildParagraphs(this);
  724. return newTable;
  725. }
  726. /// <summary>
  727. /// Insert a Table into this document. The Table's source can be a completely different document.
  728. /// </summary>
  729. /// <param name="t">The Table to insert.</param>
  730. /// <returns>The Table now associated with this document.</returns>
  731. /// <example>
  732. /// Extract a Table from document a and insert it at the end of document b.
  733. /// <code>
  734. /// // Place holder for a Table.
  735. /// Table t;
  736. ///
  737. /// // Load document a.
  738. /// using (DocX documentA = DocX.Load(@"C:\Example\a.docx"))
  739. /// {
  740. /// // Get the first Table from this document.
  741. /// t = documentA.Tables[0];
  742. /// }
  743. ///
  744. /// // Load document b.
  745. /// using (DocX documentB = DocX.Load(@"C:\Example\b.docx"))
  746. /// {
  747. /// /*
  748. /// * Insert the Table that was extracted from document a, into document b.
  749. /// * This creates a new Table that is now associated with document b.
  750. /// */
  751. /// Table newTable = documentB.InsertTable(t);
  752. ///
  753. /// // Save all changes made to document b.
  754. /// documentB.Save();
  755. /// }// Release this document from memory.
  756. /// </code>
  757. /// </example>
  758. public Table InsertTable(Table t)
  759. {
  760. XElement newXElement = new XElement(t.Xml);
  761. mainDoc.Descendants(XName.Get("body", DocX.w.NamespaceName)).First().Add(newXElement);
  762. Table newTable = new Table(this, newXElement);
  763. newTable.Design = t.Design;
  764. return newTable;
  765. }
  766. /// <summary>
  767. /// Insert a new Table at the end of this document.
  768. /// </summary>
  769. /// <param name="coloumnCount">The number of coloumns to create.</param>
  770. /// <param name="rowCount">The number of rows to create.</param>
  771. /// <param name="index">The index to insert this Table at.</param>
  772. /// <returns>A new Table.</returns>
  773. /// <example>
  774. /// Insert a new Table with 2 coloumns and 3 rows, at index 37 in this document.
  775. /// <code>
  776. /// // Create a document.
  777. /// using (DocX document = DocX.Load(@"C:\Example\Test.docx"))
  778. /// {
  779. /// // Create a new Table with 2 coloumns and 3 rows. Insert this Table at index 37.
  780. /// Table newTable = document.InsertTable(37, 2, 3);
  781. ///
  782. /// // Set the design of this Table.
  783. /// newTable.Design = TableDesign.LightShadingAccent3;
  784. ///
  785. /// // Set the coloumn names.
  786. /// newTable.Rows[0].Cells[0].Paragraph.InsertText("Ice Cream", false);
  787. /// newTable.Rows[0].Cells[1].Paragraph.InsertText("Price", false);
  788. ///
  789. /// // Fill row 1
  790. /// newTable.Rows[1].Cells[0].Paragraph.InsertText("Chocolate", false);
  791. /// newTable.Rows[1].Cells[1].Paragraph.InsertText("€3:50", false);
  792. ///
  793. /// // Fill row 2
  794. /// newTable.Rows[2].Cells[0].Paragraph.InsertText("Vanilla", false);
  795. /// newTable.Rows[2].Cells[1].Paragraph.InsertText("€3:00", false);
  796. ///
  797. /// // Save all changes made to document b.
  798. /// document.Save();
  799. /// }// Release this document from memory.
  800. /// </code>
  801. /// </example>
  802. public Table InsertTable(int index, int coloumnCount, int rowCount)
  803. {
  804. XElement newTable = HelperFunctions.CreateTable(rowCount, coloumnCount);
  805. Paragraph p = HelperFunctions.GetFirstParagraphEffectedByInsert(this, index);
  806. if (p == null)
  807. mainDoc.Descendants(XName.Get("body", DocX.w.NamespaceName)).First().AddFirst(newTable);
  808. else
  809. {
  810. XElement[] split = HelperFunctions.SplitParagraph(p, index - p.startIndex);
  811. p.Xml.ReplaceWith
  812. (
  813. split[0],
  814. newTable,
  815. split[1]
  816. );
  817. }
  818. HelperFunctions.RebuildParagraphs(this);
  819. return new Table(this, newTable);
  820. }
  821. /// <summary>
  822. /// Creates a document using a Stream.
  823. /// </summary>
  824. /// <param name="stream">The Stream to create the document from.</param>
  825. /// <returns>Returns a DocX object which represents the document.</returns>
  826. /// <example>
  827. /// Creating a document from a FileStream.
  828. /// <code>
  829. /// // Use a FileStream fs to create a new document.
  830. /// using(FileStream fs = new FileStream(@"C:\Example\Test.docx", FileMode.Create))
  831. /// {
  832. /// // Load the document using fs
  833. /// using (DocX document = DocX.Create(fs))
  834. /// {
  835. /// // Do something with the document here.
  836. ///
  837. /// // Save all changes made to this document.
  838. /// document.Save();
  839. /// }// Release this document from memory.
  840. /// }
  841. /// </code>
  842. /// </example>
  843. /// <example>
  844. /// Creating a document in a SharePoint site.
  845. /// <code>
  846. /// using(SPSite mySite = new SPSite("http://server/sites/site"))
  847. /// {
  848. /// // Open a connection to the SharePoint site
  849. /// using(SPWeb myWeb = mySite.OpenWeb())
  850. /// {
  851. /// // Create a MemoryStream ms.
  852. /// using (MemoryStream ms = new MemoryStream())
  853. /// {
  854. /// // Create a document using ms.
  855. /// using (DocX document = DocX.Create(ms))
  856. /// {
  857. /// // Do something with the document here.
  858. ///
  859. /// // Save all changes made to this document.
  860. /// document.Save();
  861. /// }// Release this document from memory
  862. ///
  863. /// // Add the document to the SharePoint site
  864. /// web.Files.Add("filename", ms.ToArray(), true);
  865. /// }
  866. /// }
  867. /// }
  868. /// </code>
  869. /// </example>
  870. /// <seealso cref="DocX.Create(string)"/>
  871. /// <seealso cref="DocX.Load(System.IO.Stream)"/>
  872. /// <seealso cref="DocX.Load(string)"/>
  873. /// <seealso cref="DocX.Save()"/>
  874. public static DocX Create(Stream stream)
  875. {
  876. // Store this document in memory
  877. MemoryStream ms = new MemoryStream();
  878. // Create the docx package
  879. Package package = Package.Open(ms, FileMode.Create, FileAccess.ReadWrite);
  880. PostCreation(ref package);
  881. DocX document = DocX.Load(ms);
  882. document.stream = stream;
  883. return document;
  884. }
  885. /// <summary>
  886. /// Creates a document using a fully qualified or relative filename.
  887. /// </summary>
  888. /// <param name="filename">The fully qualified or relative filename.</param>
  889. /// <returns>Returns a DocX object which represents the document.</returns>
  890. /// <example>
  891. /// <code>
  892. /// // Create a document using a relative filename.
  893. /// using (DocX document = DocX.Create(@"..\Test.docx"))
  894. /// {
  895. /// // Do something with the document here.
  896. ///
  897. /// // Save all changes made to this document.
  898. /// document.Save();
  899. /// }// Release this document from memory
  900. /// </code>
  901. /// <code>
  902. /// // Create a document using a relative filename.
  903. /// using (DocX document = DocX.Create(@"..\Test.docx"))
  904. /// {
  905. /// // Do something with the document here.
  906. ///
  907. /// // Save all changes made to this document.
  908. /// document.Save();
  909. /// }// Release this document from memory
  910. /// </code>
  911. /// <seealso cref="DocX.Create(System.IO.Stream)"/>
  912. /// <seealso cref="DocX.Load(System.IO.Stream)"/>
  913. /// <seealso cref="DocX.Load(string)"/>
  914. /// <seealso cref="DocX.Save()"/>
  915. /// </example>
  916. public static DocX Create(string filename)
  917. {
  918. // Store this document in memory
  919. MemoryStream ms = new MemoryStream();
  920. // Create the docx package
  921. //WordprocessingDocument wdDoc = WordprocessingDocument.Create(ms, DocumentFormat.OpenXml.WordprocessingDocumentType.Document);
  922. Package package = Package.Open(ms, FileMode.Create, FileAccess.ReadWrite);
  923. PostCreation(ref package);
  924. DocX document = DocX.Load(ms);
  925. document.filename = filename;
  926. return document;
  927. }
  928. internal static void PostCreation(ref Package package)
  929. {
  930. XDocument mainDoc, stylesDoc;
  931. #region MainDocumentPart
  932. // Create the main document part for this package
  933. PackagePart mainDocumentPart = package.CreatePart(new Uri("/word/document.xml", UriKind.Relative), "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml");
  934. package.CreateRelationship(mainDocumentPart.Uri, TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument");
  935. // Load the document part into a XDocument object
  936. using (TextReader tr = new StreamReader(mainDocumentPart.GetStream(FileMode.Create, FileAccess.ReadWrite)))
  937. {
  938. mainDoc = XDocument.Parse
  939. (@"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>
  940. <w:document xmlns:ve=""http://schemas.openxmlformats.org/markup-compatibility/2006"" xmlns:o=""urn:schemas-microsoft-com:office:office"" xmlns:r=""http://schemas.openxmlformats.org/officeDocument/2006/relationships"" xmlns:m=""http://schemas.openxmlformats.org/officeDocument/2006/math"" xmlns:v=""urn:schemas-microsoft-com:vml"" xmlns:wp=""http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"" xmlns:w10=""urn:schemas-microsoft-com:office:word"" xmlns:w=""http://schemas.openxmlformats.org/wordprocessingml/2006/main"" xmlns:wne=""http://schemas.microsoft.com/office/word/2006/wordml"">
  941. <w:body>
  942. <w:sectPr w:rsidR=""003E25F4"" w:rsidSect=""00FC3028"">
  943. <w:pgSz w:w=""11906"" w:h=""16838""/>
  944. <w:pgMar w:top=""1440"" w:right=""1440"" w:bottom=""1440"" w:left=""1440"" w:header=""708"" w:footer=""708"" w:gutter=""0""/>
  945. <w:cols w:space=""708""/>
  946. <w:docGrid w:linePitch=""360""/>
  947. </w:sectPr>
  948. </w:body>
  949. </w:document>"
  950. );
  951. }
  952. // Save the main document
  953. using (TextWriter tw = new StreamWriter(mainDocumentPart.GetStream(FileMode.Create, FileAccess.Write)))
  954. mainDoc.Save(tw, SaveOptions.DisableFormatting);
  955. #endregion
  956. #region StylePart
  957. stylesDoc = HelperFunctions.AddDefaultStylesXml(package);
  958. #endregion
  959. package.Close();
  960. }
  961. internal static DocX PostLoad(ref Package package)
  962. {
  963. DocX document = new DocX(null, null);
  964. document.package = package;
  965. document.Document = document;
  966. #region MainDocumentPart
  967. document.mainPart = package.GetParts().Where
  968. (
  969. p => p.ContentType.Equals
  970. (
  971. "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml",
  972. StringComparison.CurrentCultureIgnoreCase
  973. )
  974. ).Single();
  975. using (TextReader tr = new StreamReader(document.mainPart.GetStream(FileMode.Open, FileAccess.Read)))
  976. document.mainDoc = XDocument.Load(tr, LoadOptions.PreserveWhitespace);
  977. HelperFunctions.RebuildParagraphs(document);
  978. #endregion
  979. Headers headers = new Headers();
  980. headers.odd = document.GetHeaderByType("default");
  981. headers.even = document.GetHeaderByType("even");
  982. headers.first = document.GetHeaderByType("first");
  983. Footers footers = new Footers();
  984. footers.odd = document.GetFooterByType("default");
  985. footers.even = document.GetFooterByType("even");
  986. footers.first = document.GetFooterByType("first");
  987. document.Xml = document.mainDoc.Root.Element(w + "body");
  988. document.headers = headers;
  989. document.footers = footers;
  990. document.settingsPart = HelperFunctions.CreateOrGetSettingsPart(package);
  991. return document;
  992. }
  993. /// <summary>
  994. /// Loads a document into a DocX object using a Stream.
  995. /// </summary>
  996. /// <param name="stream">The Stream to load the document from.</param>
  997. /// <returns>
  998. /// Returns a DocX object which represents the document.
  999. /// </returns>
  1000. /// <example>
  1001. /// Loading a document from a FileStream.
  1002. /// <code>
  1003. /// // Open a FileStream fs to a document.
  1004. /// using (FileStream fs = new FileStream(@"C:\Example\Test.docx", FileMode.Open))
  1005. /// {
  1006. /// // Load the document using fs.
  1007. /// using (DocX document = DocX.Load(fs))
  1008. /// {
  1009. /// // Do something with the document here.
  1010. ///
  1011. /// // Save all changes made to the document.
  1012. /// document.Save();
  1013. /// }// Release this document from memory.
  1014. /// }
  1015. /// </code>
  1016. /// </example>
  1017. /// <example>
  1018. /// Loading a document from a SharePoint site.
  1019. /// <code>
  1020. /// // Get the SharePoint site that you want to access.
  1021. /// using (SPSite mySite = new SPSite("http://server/sites/site"))
  1022. /// {
  1023. /// // Open a connection to the SharePoint site
  1024. /// using (SPWeb myWeb = mySite.OpenWeb())
  1025. /// {
  1026. /// // Grab a document stored on this site.
  1027. /// SPFile file = web.GetFile("Source_Folder_Name/Source_File");
  1028. ///
  1029. /// // DocX.Load requires a Stream, so open a Stream to this document.
  1030. /// Stream str = new MemoryStream(file.OpenBinary());
  1031. ///
  1032. /// // Load the file using the Stream str.
  1033. /// using (DocX document = DocX.Load(str))
  1034. /// {
  1035. /// // Do something with the document here.
  1036. ///
  1037. /// // Save all changes made to the document.
  1038. /// document.Save();
  1039. /// }// Release this document from memory.
  1040. /// }
  1041. /// }
  1042. /// </code>
  1043. /// </example>
  1044. /// <seealso cref="DocX.Load(string)"/>
  1045. /// <seealso cref="DocX.Create(System.IO.Stream)"/>
  1046. /// <seealso cref="DocX.Create(string)"/>
  1047. /// <seealso cref="DocX.Save()"/>
  1048. public static DocX Load(Stream stream)
  1049. {
  1050. MemoryStream ms = new MemoryStream();
  1051. stream.Position = 0;
  1052. byte[] data = new byte[stream.Length];
  1053. stream.Read(data, 0, (int)stream.Length);
  1054. ms.Write(data, 0, (int)stream.Length);
  1055. // Open the docx package
  1056. Package package = Package.Open(ms, FileMode.Open, FileAccess.ReadWrite);
  1057. DocX document = PostLoad(ref package);
  1058. document.package = package;
  1059. document.memoryStream = ms;
  1060. document.stream = stream;
  1061. return document;
  1062. }
  1063. /// <summary>
  1064. /// Loads a document into a DocX object using a fully qualified or relative filename.
  1065. /// </summary>
  1066. /// <param name="filename">The fully qualified or relative filename.</param>
  1067. /// <returns>
  1068. /// Returns a DocX object which represents the document.
  1069. /// </returns>
  1070. /// <example>
  1071. /// <code>
  1072. /// // Load a document using its fully qualified filename
  1073. /// using (DocX document = DocX.Load(@"C:\Example\Test.docx"))
  1074. /// {
  1075. /// // Do something with the document here
  1076. ///
  1077. /// // Save all changes made to document.
  1078. /// document.Save();
  1079. /// }// Release this document from memory.
  1080. /// </code>
  1081. /// <code>
  1082. /// // Load a document using its relative filename.
  1083. /// using(DocX document = DocX.Load(@"..\..\Test.docx"))
  1084. /// {
  1085. /// // Do something with the document here.
  1086. ///
  1087. /// // Save all changes made to document.
  1088. /// document.Save();
  1089. /// }// Release this document from memory.
  1090. /// </code>
  1091. /// <seealso cref="DocX.Load(System.IO.Stream)"/>
  1092. /// <seealso cref="DocX.Create(System.IO.Stream)"/>
  1093. /// <seealso cref="DocX.Create(string)"/>
  1094. /// <seealso cref="DocX.Save()"/>
  1095. /// </example>
  1096. public static DocX Load(string filename)
  1097. {
  1098. if (!File.Exists(filename))
  1099. throw new FileNotFoundException(string.Format("File could not be found {0}", filename));
  1100. MemoryStream ms = new MemoryStream();
  1101. using (FileStream fs = new FileStream(filename, FileMode.Open))
  1102. {
  1103. byte[] data = new byte[fs.Length];
  1104. fs.Read(data, 0, (int)fs.Length);
  1105. ms.Write(data, 0, (int)fs.Length);
  1106. }
  1107. // Open the docx package
  1108. Package package = Package.Open(ms, FileMode.Open, FileAccess.ReadWrite);
  1109. DocX document = PostLoad(ref package);
  1110. document.package = package;
  1111. document.filename = filename;
  1112. document.memoryStream = ms;
  1113. return document;
  1114. }
  1115. /// <summary>
  1116. /// Add an Image into this document from a fully qualified or relative filename.
  1117. /// </summary>
  1118. /// <param name="filename">The fully qualified or relative filename.</param>
  1119. /// <returns>An Image file.</returns>
  1120. /// <example>
  1121. /// Add an Image into this document from a fully qualified filename.
  1122. /// <code>
  1123. /// // Load a document.
  1124. /// using (DocX document = DocX.Load(@"C:\Example\Test.docx"))
  1125. /// {
  1126. /// // Add an Image from a file.
  1127. /// document.AddImage(@"C:\Example\Image.png");
  1128. ///
  1129. /// // Save all changes made to this document.
  1130. /// document.Save();
  1131. /// }// Release this document from memory.
  1132. /// </code>
  1133. /// </example>
  1134. /// <seealso cref="AddImage(System.IO.Stream)"/>
  1135. /// <seealso cref="Paragraph.InsertPicture"/>
  1136. public Image AddImage(string filename)
  1137. {
  1138. return AddImage(filename as object);
  1139. }
  1140. /// <summary>
  1141. /// Add an Image into this document from a Stream.
  1142. /// </summary>
  1143. /// <param name="stream">A Stream stream.</param>
  1144. /// <returns>An Image file.</returns>
  1145. /// <example>
  1146. /// Add an Image into a document using a Stream.
  1147. /// <code>
  1148. /// // Open a FileStream fs to an Image.
  1149. /// using (FileStream fs = new FileStream(@"C:\Example\Image.jpg", FileMode.Open))
  1150. /// {
  1151. /// // Load a document.
  1152. /// using (DocX document = DocX.Load(@"C:\Example\Test.docx"))
  1153. /// {
  1154. /// // Add an Image from a filestream fs.
  1155. /// document.AddImage(fs);
  1156. ///
  1157. /// // Save all changes made to this document.
  1158. /// document.Save();
  1159. /// }// Release this document from memory.
  1160. /// }
  1161. /// </code>
  1162. /// </example>
  1163. /// <seealso cref="AddImage(string)"/>
  1164. /// <seealso cref="Paragraph.InsertPicture"/>
  1165. public Image AddImage(Stream stream)
  1166. {
  1167. return AddImage(stream as object);
  1168. }
  1169. /// <summary>
  1170. /// Adds a hyperlink to a document and creates a Paragraph which uses it.
  1171. /// </summary>
  1172. /// <param name="text">The text as displayed by the hyperlink.</param>
  1173. /// <param name="uri">The hyperlink itself.</param>
  1174. /// <returns>Returns a hyperlink that can be inserted into a Paragraph.</returns>
  1175. /// <example>
  1176. /// Adds a hyperlink to a document and creates a Paragraph which uses it.
  1177. /// <code>
  1178. /// // Create a document.
  1179. /// using (DocX document = DocX.Create(@"Test.docx"))
  1180. /// {
  1181. /// // Add a hyperlink to this document.
  1182. /// Hyperlink h = document.AddHyperlink("Google", new Uri("http://www.google.com"));
  1183. ///
  1184. /// // Add a new Paragraph to this document.
  1185. /// Paragraph p = document.InsertParagraph();
  1186. /// p.Append("My favourite search engine is ");
  1187. /// p.AppendHyperlink(h);
  1188. /// p.Append(", I think it's great.");
  1189. ///
  1190. /// // Save all changes made to this document.
  1191. /// document.Save();
  1192. /// }
  1193. /// </code>
  1194. /// </example>
  1195. public Hyperlink AddHyperlink(string text, Uri uri)
  1196. {
  1197. XElement i = new XElement
  1198. (
  1199. XName.Get("hyperlink", DocX.w.NamespaceName),
  1200. new XAttribute(r + "id", string.Empty),
  1201. new XAttribute(w + "history", "1"),
  1202. new XElement(XName.Get("r", DocX.w.NamespaceName),
  1203. new XElement(XName.Get("rPr", DocX.w.NamespaceName),
  1204. new XElement(XName.Get("rStyle", DocX.w.NamespaceName),
  1205. new XAttribute(w + "val", "Hyperlink"))),
  1206. new XElement(XName.Get("t", DocX.w.NamespaceName), text))
  1207. );
  1208. Hyperlink h = new Hyperlink(this, i);
  1209. h.Text = text;
  1210. h.Uri = uri;
  1211. AddHyperlinkStyleIfNotPresent();
  1212. return h;
  1213. }
  1214. internal void AddHyperlinkStyleIfNotPresent()
  1215. {
  1216. Uri word_styles_Uri = new Uri("/word/styles.xml", UriKind.Relative);
  1217. // If the internal document contains no /word/styles.xml create one.
  1218. if (!package.PartExists(word_styles_Uri))
  1219. HelperFunctions.AddDefaultStylesXml(package);
  1220. // Load the styles.xml into memory.
  1221. XDocument word_styles;
  1222. using (TextReader tr = new StreamReader(package.GetPart(word_styles_Uri).GetStream()))
  1223. word_styles = XDocument.Load(tr);
  1224. bool hyperlinkStyleExists =
  1225. (
  1226. from s in word_styles.Element(w + "styles").Elements()
  1227. let styleId = s.Attribute(XName.Get("styleId", w.NamespaceName))
  1228. where (styleId != null && styleId.Value == "Hyperlink")
  1229. select s
  1230. ).Count() > 0;
  1231. if (!hyperlinkStyleExists)
  1232. {
  1233. XElement style = new XElement
  1234. (
  1235. w + "style",
  1236. new XAttribute(w + "type", "character"),
  1237. new XAttribute(w + "styleId", "Hyperlink"),
  1238. new XElement(w + "name", new XAttribute(w + "val", "Hyperlink")),
  1239. new XElement(w + "basedOn", new XAttribute(w + "val", "DefaultParagraphFont")),
  1240. new XElement(w + "uiPriority", new XAttribute(w + "val", "99")),
  1241. new XElement(w + "unhideWhenUsed"),
  1242. new XElement(w + "rsid", new XAttribute(w + "val", "0005416C")),
  1243. new XElement
  1244. (
  1245. w + "rPr",
  1246. new XElement(w + "color", new XAttribute(w + "val", "0000FF"), new XAttribute(w + "themeColor", "hyperlink")),
  1247. new XElement
  1248. (
  1249. w + "u",
  1250. new XAttribute(w + "val", "single")
  1251. )
  1252. )
  1253. );
  1254. word_styles.Element(w + "styles").Add(style);
  1255. // Save the styles document.
  1256. using (TextWriter tw = new StreamWriter(package.GetPart(word_styles_Uri).GetStream()))
  1257. word_styles.Save(tw);
  1258. }
  1259. }
  1260. private string GetNextFreeRelationshipID()
  1261. {
  1262. string id =
  1263. (
  1264. from r in mainPart.GetRelationships()
  1265. select r.Id
  1266. ).Max();
  1267. // The convension for ids is rid01, rid02, etc
  1268. string newId = id.Replace("rId", "");
  1269. int result;
  1270. if (int.TryParse(newId, out result))
  1271. return ("rId" + (result + 1));
  1272. else
  1273. return Guid.NewGuid().ToString();
  1274. }
  1275. /// <summary>
  1276. /// Adds three new Headers to this document. One for the first page, one for odd pages and one for even pages.
  1277. /// </summary>
  1278. /// <example>
  1279. /// // Create a document.
  1280. /// using (DocX document = DocX.Create(@"Test.docx"))
  1281. /// {
  1282. /// // Add header support to this document.
  1283. /// document.AddHeaders();
  1284. ///
  1285. /// // Get a collection of all headers in this document.
  1286. /// Headers headers = document.Headers;
  1287. ///
  1288. /// // The header used for the first page of this document.
  1289. /// Header first = headers.first;
  1290. ///
  1291. /// // The header used for odd pages of this document.
  1292. /// Header odd = headers.odd;
  1293. ///
  1294. /// // The header used for even pages of this document.
  1295. /// Header even = headers.even;
  1296. ///
  1297. /// // Force the document to use a different header for first, odd and even pages.
  1298. /// document.DifferentFirstPage = true;
  1299. /// document.DifferentOddAndEvenPages = true;
  1300. ///
  1301. /// // Content can be added to the Headers in the same manor that it would be added to the main document.
  1302. /// Paragraph p = first.InsertParagraph();
  1303. /// p.Append("This is the first pages header.");
  1304. ///
  1305. /// // Save all changes to this document.
  1306. /// document.Save();
  1307. /// }// Release this document from memory.
  1308. /// </example>
  1309. public void AddHeaders()
  1310. {
  1311. AddHeadersOrFooters(true);
  1312. headers.odd = Document.GetHeaderByType("default");
  1313. headers.even = Document.GetHeaderByType("even");
  1314. headers.first = Document.GetHeaderByType("first");
  1315. }
  1316. /// <summary>
  1317. /// Adds three new Footers to this document. One for the first page, one for odd pages and one for even pages.
  1318. /// </summary>
  1319. /// <example>
  1320. /// // Create a document.
  1321. /// using (DocX document = DocX.Create(@"Test.docx"))
  1322. /// {
  1323. /// // Add footer support to this document.
  1324. /// document.AddFooters();
  1325. ///
  1326. /// // Get a collection of all footers in this document.
  1327. /// Footers footers = document.Footers;
  1328. ///
  1329. /// // The footer used for the first page of this document.
  1330. /// Footer first = footers.first;
  1331. ///
  1332. /// // The footer used for odd pages of this document.
  1333. /// Footer odd = footers.odd;
  1334. ///
  1335. /// // The footer used for even pages of this document.
  1336. /// Footer even = footers.even;
  1337. ///
  1338. /// // Force the document to use a different footer for first, odd and even pages.
  1339. /// document.DifferentFirstPage = true;
  1340. /// document.DifferentOddAndEvenPages = true;
  1341. ///
  1342. /// // Content can be added to the Footers in the same manor that it would be added to the main document.
  1343. /// Paragraph p = first.InsertParagraph();
  1344. /// p.Append("This is the first pages footer.");
  1345. ///
  1346. /// // Save all changes to this document.
  1347. /// document.Save();
  1348. /// }// Release this document from memory.
  1349. /// </example>
  1350. public void AddFooters()
  1351. {
  1352. AddHeadersOrFooters(false);
  1353. footers.odd = Document.GetFooterByType("default");
  1354. footers.even = Document.GetFooterByType("even");
  1355. footers.first = Document.GetFooterByType("first");
  1356. }
  1357. /// <summary>
  1358. /// Adds a Header to a document.
  1359. /// If the document already contains a Header it will be replaced.
  1360. /// </summary>
  1361. /// <returns>The Header that was added to the document.</returns>
  1362. internal void AddHeadersOrFooters(bool b)
  1363. {
  1364. string element = "ftr";
  1365. string reference = "footer";
  1366. if (b)
  1367. {
  1368. element = "hdr";
  1369. reference = "header";
  1370. }
  1371. DeleteHeadersOrFooters(b);
  1372. XElement sectPr = mainDoc.Root.Element(w + "body").Element(w + "sectPr");
  1373. for (int i = 1; i < 4; i++)
  1374. {
  1375. string header_uri = string.Format("/word/{0}{1}.xml", reference, i);
  1376. PackagePart headerPart = package.CreatePart(new Uri(header_uri, UriKind.Relative), string.Format("application/vnd.openxmlformats-officedocument.wordprocessingml.{0}+xml", reference));
  1377. PackageRelationship headerRelationship = mainPart.CreateRelationship(headerPart.Uri, TargetMode.Internal, string.Format("http://schemas.openxmlformats.org/officeDocument/2006/relationships/{0}", reference));
  1378. XDocument header;
  1379. // Load the document part into a XDocument object
  1380. using (TextReader tr = new StreamReader(headerPart.GetStream(FileMode.Create, FileAccess.ReadWrite)))
  1381. {
  1382. header = XDocument.Parse
  1383. (string.Format(@"<?xml version=""1.0"" encoding=""utf-16"" standalone=""yes""?>
  1384. <w:{0} xmlns:ve=""http://schemas.openxmlformats.org/markup-compatibility/2006"" xmlns:o=""urn:schemas-microsoft-com:office:office"" xmlns:r=""http://schemas.openxmlformats.org/officeDocument/2006/relationships"" xmlns:m=""http://schemas.openxmlformats.org/officeDocument/2006/math"" xmlns:v=""urn:schemas-microsoft-com:vml"" xmlns:wp=""http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"" xmlns:w10=""urn:schemas-microsoft-com:office:word"" xmlns:w=""http://schemas.openxmlformats.org/wordprocessingml/2006/main"" xmlns:wne=""http://schemas.microsoft.com/office/word/2006/wordml"">
  1385. <w:p w:rsidR=""009D472B"" w:rsidRDefault=""009D472B"">
  1386. <w:pPr>
  1387. <w:pStyle w:val=""{1}"" />
  1388. </w:pPr>
  1389. </w:p>
  1390. </w:{0}>", element, reference)
  1391. );
  1392. }
  1393. // Save the main document
  1394. using (TextWriter tw = new StreamWriter(headerPart.GetStream(FileMode.Create, FileAccess.Write)))
  1395. header.Save(tw, SaveOptions.DisableFormatting);
  1396. string type;
  1397. switch (i)
  1398. {
  1399. case 1: type = "default"; break;
  1400. case 2: type = "even"; break;
  1401. case 3: type = "first"; break;
  1402. default: throw new ArgumentOutOfRangeException();
  1403. }
  1404. sectPr.Add
  1405. (
  1406. new XElement
  1407. (
  1408. w + string.Format("{0}Reference", reference),
  1409. new XAttribute(w + "type", type),
  1410. new XAttribute(r + "id", headerRelationship.Id)
  1411. )
  1412. );
  1413. }
  1414. }
  1415. internal void DeleteHeadersOrFooters(bool b)
  1416. {
  1417. string reference = "footer";
  1418. if (b)
  1419. reference = "header";
  1420. // Get all header Relationships in this document.
  1421. var header_relationships = mainPart.GetRelationshipsByType(string.Format("http://schemas.openxmlformats.org/officeDocument/2006/relationships/{0}", reference));
  1422. foreach (PackageRelationship header_relationship in header_relationships)
  1423. {
  1424. // Get the TargetUri for this Part.
  1425. Uri header_uri = header_relationship.TargetUri;
  1426. // Check to see if the document actually contains the Part.
  1427. if (!header_uri.OriginalString.StartsWith("/word/"))
  1428. header_uri = new Uri("/word/" + header_uri.OriginalString, UriKind.Relative);
  1429. if (package.PartExists(header_uri))
  1430. {
  1431. // Delete the Part
  1432. package.DeletePart(header_uri);
  1433. // Get all references to this Relationship in the document.
  1434. var query =
  1435. (
  1436. from e in mainDoc.Descendants(XName.Get("body", DocX.w.NamespaceName)).Descendants()
  1437. where (e.Name.LocalName == string.Format("{0}Reference", reference)) && (e.Attribute(r + "id").Value == header_relationship.Id)
  1438. select e
  1439. );
  1440. // Remove all references to this Relationship in the document.
  1441. for (int i = 0; i < query.Count(); i++)
  1442. query.ElementAt(i).Remove();
  1443. // Delete the Relationship.
  1444. package.DeleteRelationship(header_relationship.Id);
  1445. }
  1446. }
  1447. }
  1448. internal Image AddImage(object o)
  1449. {
  1450. // Open a Stream to the new image being added.
  1451. Stream newImageStream;
  1452. if (o is string)
  1453. newImageStream = new FileStream(o as string, FileMode.Open, FileAccess.Read);
  1454. else
  1455. newImageStream = o as Stream;
  1456. // Get all image parts in word\document.xml
  1457. var imageParts = mainPart.GetRelationshipsByType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/image").Select(ir => package.GetParts().Where(p => p.Uri.ToString().EndsWith(ir.TargetUri.ToString())).First());
  1458. // Loop through each image part in this document.
  1459. foreach (PackagePart pp in imageParts)
  1460. {
  1461. // Open a tempory Stream to this image part.
  1462. using (Stream tempStream = pp.GetStream(FileMode.Open, FileAccess.Read))
  1463. {
  1464. // Compare this image to the new image being added.
  1465. if (HelperFunctions.IsSameFile(tempStream, newImageStream))
  1466. {
  1467. // Get the image object for this image part
  1468. string id = mainPart.GetRelationshipsByType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/image")
  1469. .Where(r => r.TargetUri == pp.Uri)
  1470. .Select(r => r.Id).First();
  1471. // Return the Image object
  1472. return Images.Where(i => i.Id == id).First();
  1473. }
  1474. }
  1475. }
  1476. /*
  1477. * This Image being added is infact a new Image,
  1478. * we need to generate a unique name for this image of the format imageN.ext,
  1479. * where n is an integer that has not been used before.
  1480. * This could probabily be replace by a Guid.
  1481. */
  1482. int max = 0;
  1483. var values =
  1484. (
  1485. from ip in imageParts
  1486. let Name = Path.GetFileNameWithoutExtension(ip.Uri.ToString())
  1487. let Number = Regex.Match(Name, @"\d+$").Value
  1488. select Number != string.Empty ? int.Parse(Number) : 0
  1489. );
  1490. if (values.Count() > 0)
  1491. max = Math.Max(max, values.Max());
  1492. // Create a new image part.
  1493. PackagePart img = package.CreatePart(new Uri(string.Format("/word/media/image{0}.jpeg", max + 1), UriKind.Relative), System.Net.Mime.MediaTypeNames.Image.Jpeg);
  1494. // Create a new image relationship
  1495. PackageRelationship rel = mainPart.CreateRelationship(img.Uri, TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image");
  1496. // Open a Stream to the newly created Image part.
  1497. using (Stream stream = img.GetStream(FileMode.Create, FileAccess.Write))
  1498. {
  1499. // Using the Stream to the real image, copy this streams data into the newly create Image part.
  1500. using (newImageStream)
  1501. {
  1502. byte[] bytes = new byte[newImageStream.Length];
  1503. newImageStream.Read(bytes, 0, (int)newImageStream.Length);
  1504. stream.Write(bytes, 0, (int)newImageStream.Length);
  1505. }// Close the Stream to the new image.
  1506. }// Close the Stream to the new image part.
  1507. return new Image(this, rel);
  1508. }
  1509. /// <summary>
  1510. /// Save this document back to the location it was loaded from.
  1511. /// </summary>
  1512. /// <example>
  1513. /// <code>
  1514. /// // Load a document.
  1515. /// using (DocX document = DocX.Load(@"C:\Example\Test.docx"))
  1516. /// {
  1517. /// // Add an Image from a file.
  1518. /// document.AddImage(@"C:\Example\Image.jpg");
  1519. ///
  1520. /// // Save all changes made to this document.
  1521. /// document.Save();
  1522. /// }// Release this document from memory.
  1523. /// </code>
  1524. /// </example>
  1525. /// <seealso cref="DocX.SaveAs(string)"/>
  1526. /// <seealso cref="DocX.Create(System.IO.Stream)"/>
  1527. /// <seealso cref="DocX.Create(string)"/>
  1528. /// <seealso cref="DocX.Load(System.IO.Stream)"/>
  1529. /// <seealso cref="DocX.Load(string)"/>
  1530. /// <!--
  1531. /// Bug found and fixed by krugs525 on August 12 2009.
  1532. /// Use TFS compare to see exact code change.
  1533. /// -->
  1534. public void Save()
  1535. {
  1536. Headers headers = Headers;
  1537. // Save the main document
  1538. using (TextWriter tw = new StreamWriter(mainPart.GetStream(FileMode.Create, FileAccess.Write)))
  1539. mainDoc.Save(tw, SaveOptions.DisableFormatting);
  1540. XElement body = mainDoc.Root.Element(w + "body");
  1541. XElement sectPr = body.Element(w + "sectPr");
  1542. var evenHeaderRef =
  1543. (
  1544. from e in sectPr.Elements(w + "headerReference")
  1545. let type = e.Attribute(w + "type")
  1546. where type != null && type.Value.Equals("even", StringComparison.CurrentCultureIgnoreCase)
  1547. select e.Attribute(r + "id").Value
  1548. ).SingleOrDefault();
  1549. if(evenHeaderRef != null)
  1550. {
  1551. XElement even = headers.even.Xml;
  1552. Uri target = mainPart.GetRelationship(evenHeaderRef).TargetUri;
  1553. using (TextWriter tw = new StreamWriter(package.GetPart(target).GetStream(FileMode.Create, FileAccess.Write)))
  1554. {
  1555. new XDocument
  1556. (
  1557. new XDeclaration("1.0", "UTF-8", "yes"),
  1558. even
  1559. ).Save(tw, SaveOptions.DisableFormatting);
  1560. }
  1561. }
  1562. var oddHeaderRef =
  1563. (
  1564. from e in sectPr.Elements(w + "headerReference")
  1565. let type = e.Attribute(w + "type")
  1566. where type != null && type.Value.Equals("default", StringComparison.CurrentCultureIgnoreCase)
  1567. select e.Attribute(r + "id").Value
  1568. ).SingleOrDefault();
  1569. if(oddHeaderRef != null)
  1570. {
  1571. XElement odd = headers.odd.Xml;
  1572. Uri target = mainPart.GetRelationship(oddHeaderRef).TargetUri;
  1573. // Save header1
  1574. using (TextWriter tw = new StreamWriter(package.GetPart(target).GetStream(FileMode.Create, FileAccess.Write)))
  1575. {
  1576. new XDocument
  1577. (
  1578. new XDeclaration("1.0", "UTF-8", "yes"),
  1579. odd
  1580. ).Save(tw, SaveOptions.DisableFormatting);
  1581. }
  1582. }
  1583. var firstHeaderRef =
  1584. (
  1585. from e in sectPr.Elements(w + "headerReference")
  1586. let type = e.Attribute(w + "type")
  1587. where type != null && type.Value.Equals("first", StringComparison.CurrentCultureIgnoreCase)
  1588. select e.Attribute(r + "id").Value
  1589. ).SingleOrDefault();
  1590. if(firstHeaderRef != null)
  1591. {
  1592. XElement first = headers.first.Xml;
  1593. Uri target = mainPart.GetRelationship(firstHeaderRef).TargetUri;
  1594. // Save header3
  1595. using (TextWriter tw = new StreamWriter(package.GetPart(target).GetStream(FileMode.Create, FileAccess.Write)))
  1596. {
  1597. new XDocument
  1598. (
  1599. new XDeclaration("1.0", "UTF-8", "yes"),
  1600. first
  1601. ).Save(tw, SaveOptions.DisableFormatting);
  1602. }
  1603. }
  1604. var oddFooterRef =
  1605. (
  1606. from e in sectPr.Elements(w + "footerReference")
  1607. let type = e.Attribute(w + "type")
  1608. where type != null && type.Value.Equals("default", StringComparison.CurrentCultureIgnoreCase)
  1609. select e.Attribute(r + "id").Value
  1610. ).SingleOrDefault();
  1611. if(oddFooterRef != null)
  1612. {
  1613. XElement odd = footers.odd.Xml;
  1614. Uri target = mainPart.GetRelationship(oddFooterRef).TargetUri;
  1615. // Save header1
  1616. using (TextWriter tw = new StreamWriter(package.GetPart(target).GetStream(FileMode.Create, FileAccess.Write)))
  1617. {
  1618. new XDocument
  1619. (
  1620. new XDeclaration("1.0", "UTF-8", "yes"),
  1621. odd
  1622. ).Save(tw, SaveOptions.DisableFormatting);
  1623. }
  1624. }
  1625. var evenFooterRef =
  1626. (
  1627. from e in sectPr.Elements(w + "footerReference")
  1628. let type = e.Attribute(w + "type")
  1629. where type != null && type.Value.Equals("even", StringComparison.CurrentCultureIgnoreCase)
  1630. select e.Attribute(r + "id").Value
  1631. ).SingleOrDefault();
  1632. if (evenFooterRef != null)
  1633. {
  1634. XElement even = footers.even.Xml;
  1635. Uri target = mainPart.GetRelationship(evenFooterRef).TargetUri;
  1636. // Save header2
  1637. using (TextWriter tw = new StreamWriter(package.GetPart(target).GetStream(FileMode.Create, FileAccess.Write)))
  1638. {
  1639. new XDocument
  1640. (
  1641. new XDeclaration("1.0", "UTF-8", "yes"),
  1642. even
  1643. ).Save(tw, SaveOptions.DisableFormatting);
  1644. }
  1645. }
  1646. var firstFooterRef =
  1647. (
  1648. from e in sectPr.Elements(w + "footerReference")
  1649. let type = e.Attribute(w + "type")
  1650. where type != null && type.Value.Equals("first", StringComparison.CurrentCultureIgnoreCase)
  1651. select e.Attribute(r + "id").Value
  1652. ).SingleOrDefault();
  1653. if (firstFooterRef != null)
  1654. {
  1655. XElement first = footers.first.Xml;
  1656. Uri target = mainPart.GetRelationship(firstFooterRef).TargetUri;
  1657. // Save header3
  1658. using (TextWriter tw = new StreamWriter(package.GetPart(target).GetStream(FileMode.Create, FileAccess.Write)))
  1659. {
  1660. new XDocument
  1661. (
  1662. new XDeclaration("1.0", "UTF-8", "yes"),
  1663. first
  1664. ).Save(tw, SaveOptions.DisableFormatting);
  1665. }
  1666. }
  1667. // Close the document so that it can be saved.
  1668. Dispose();
  1669. #region Save this document back to a file or stream, that was specified by the user at save time.
  1670. if (filename != null)
  1671. {
  1672. using (FileStream fs = new FileStream(filename, FileMode.Create))
  1673. fs.Write(memoryStream.ToArray(), 0, (int)memoryStream.Length);
  1674. }
  1675. else
  1676. {
  1677. // Set the length of this stream to 0
  1678. stream.SetLength(0);
  1679. // Write to the beginning of the stream
  1680. stream.Position = 0;
  1681. memoryStream.WriteTo(stream);
  1682. }
  1683. #endregion
  1684. // Re-open the document
  1685. package = Package.Open(memoryStream, FileMode.Open, FileAccess.ReadWrite);
  1686. }
  1687. /// <summary>
  1688. /// Save this document to a file.
  1689. /// </summary>
  1690. /// <param name="filename">The filename to save this document as.</param>
  1691. /// <example>
  1692. /// Load a document from one file and save it to another.
  1693. /// <code>
  1694. /// // Load a document using its fully qualified filename.
  1695. /// DocX document = DocX.Load(@"C:\Example\Test1.docx");
  1696. ///
  1697. /// // Insert a new Paragraph
  1698. /// document.InsertParagraph("Hello world!", false);
  1699. ///
  1700. /// // Save the document to a new location.
  1701. /// document.SaveAs(@"C:\Example\Test2.docx");
  1702. /// </code>
  1703. /// </example>
  1704. /// <example>
  1705. /// Load a document from a Stream and save it to a file.
  1706. /// <code>
  1707. /// DocX document;
  1708. /// using (FileStream fs1 = new FileStream(@"C:\Example\Test1.docx", FileMode.Open))
  1709. /// {
  1710. /// // Load a document using a stream.
  1711. /// document = DocX.Load(fs1);
  1712. ///
  1713. /// // Insert a new Paragraph
  1714. /// document.InsertParagraph("Hello world again!", false);
  1715. /// }
  1716. ///
  1717. /// // Save the document to a new location.
  1718. /// document.SaveAs(@"C:\Example\Test2.docx");
  1719. /// </code>
  1720. /// </example>
  1721. /// <seealso cref="DocX.Save()"/>
  1722. /// <seealso cref="DocX.Create(System.IO.Stream)"/>
  1723. /// <seealso cref="DocX.Create(string)"/>
  1724. /// <seealso cref="DocX.Load(System.IO.Stream)"/>
  1725. /// <seealso cref="DocX.Load(string)"/>
  1726. public void SaveAs(string filename)
  1727. {
  1728. this.filename = filename;
  1729. this.stream = null;
  1730. Save();
  1731. }
  1732. /// <summary>
  1733. /// Save this document to a Stream.
  1734. /// </summary>
  1735. /// <param name="stream">The Stream to save this document to.</param>
  1736. /// <example>
  1737. /// Load a document from a file and save it to a Stream.
  1738. /// <code>
  1739. /// // Place holder for a document.
  1740. /// DocX document;
  1741. ///
  1742. /// using (FileStream fs1 = new FileStream(@"C:\Example\Test1.docx", FileMode.Open))
  1743. /// {
  1744. /// // Load a document using a stream.
  1745. /// document = DocX.Load(fs1);
  1746. ///
  1747. /// // Insert a new Paragraph
  1748. /// document.InsertParagraph("Hello world again!", false);
  1749. /// }
  1750. ///
  1751. /// using (FileStream fs2 = new FileStream(@"C:\Example\Test2.docx", FileMode.Create))
  1752. /// {
  1753. /// // Save the document to a different stream.
  1754. /// document.SaveAs(fs2);
  1755. /// }
  1756. ///
  1757. /// // Release this document from memory.
  1758. /// document.Dispose();
  1759. /// </code>
  1760. /// </example>
  1761. /// <example>
  1762. /// Load a document from one Stream and save it to another.
  1763. /// <code>
  1764. /// DocX document;
  1765. /// using (FileStream fs1 = new FileStream(@"C:\Example\Test1.docx", FileMode.Open))
  1766. /// {
  1767. /// // Load a document using a stream.
  1768. /// document = DocX.Load(fs1);
  1769. ///
  1770. /// // Insert a new Paragraph
  1771. /// document.InsertParagraph("Hello world again!", false);
  1772. /// }
  1773. ///
  1774. /// using (FileStream fs2 = new FileStream(@"C:\Example\Test2.docx", FileMode.Create))
  1775. /// {
  1776. /// // Save the document to a different stream.
  1777. /// document.SaveAs(fs2);
  1778. /// }
  1779. /// </code>
  1780. /// </example>
  1781. /// <seealso cref="DocX.Save()"/>
  1782. /// <seealso cref="DocX.Create(System.IO.Stream)"/>
  1783. /// <seealso cref="DocX.Create(string)"/>
  1784. /// <seealso cref="DocX.Load(System.IO.Stream)"/>
  1785. /// <seealso cref="DocX.Load(string)"/>
  1786. public void SaveAs(Stream stream)
  1787. {
  1788. this.filename = null;
  1789. this.stream = stream;
  1790. Save();
  1791. }
  1792. /// <summary>
  1793. /// Add a custom property to this document. If a custom property already exists with the same name it will be replace. CustomProperty names are case insensitive.
  1794. /// </summary>
  1795. /// <param name="cp">The CustomProperty to add to this document.</param>
  1796. /// <example>
  1797. /// Add a custom properties of each type to a document.
  1798. /// <code>
  1799. /// // Load Example.docx
  1800. /// using (DocX document = DocX.Load(@"C:\Example\Test.docx"))
  1801. /// {
  1802. /// // A CustomProperty called forename which stores a string.
  1803. /// CustomProperty forename;
  1804. ///
  1805. /// // If this document does not contain a custom property called 'forename', create one.
  1806. /// if (!document.CustomProperties.ContainsKey("forename"))
  1807. /// {
  1808. /// // Create a new custom property called 'forename' and set its value.
  1809. /// document.AddCustomProperty(new CustomProperty("forename", "Cathal"));
  1810. /// }
  1811. ///
  1812. /// // Get this documents custom property called 'forename'.
  1813. /// forename = document.CustomProperties["forename"];
  1814. ///
  1815. /// // Print all of the information about this CustomProperty to Console.
  1816. /// Console.WriteLine(string.Format("Name: '{0}', Value: '{1}'\nPress any key...", forename.Name, forename.Value));
  1817. ///
  1818. /// // Save all changes made to this document.
  1819. /// document.Save();
  1820. /// } // Release this document from memory.
  1821. ///
  1822. /// // Wait for the user to press a key before exiting.
  1823. /// Console.ReadKey();
  1824. /// </code>
  1825. /// </example>
  1826. /// <seealso cref="CustomProperty"/>
  1827. /// <seealso cref="CustomProperties"/>
  1828. public void AddCustomProperty(CustomProperty cp)
  1829. {
  1830. // If this document does not contain a customFilePropertyPart create one.
  1831. if(!package.PartExists(new Uri("/docProps/custom.xml", UriKind.Relative)))
  1832. HelperFunctions.CreateCustomPropertiesPart(this);
  1833. XDocument customPropDoc;
  1834. PackagePart customPropPart = package.GetPart(new Uri("/docProps/custom.xml", UriKind.Relative));
  1835. using (TextReader tr = new StreamReader(customPropPart.GetStream(FileMode.Open, FileAccess.Read)))
  1836. customPropDoc = XDocument.Load(tr, LoadOptions.PreserveWhitespace);
  1837. // Each custom property has a PID, get the highest PID in this document.
  1838. IEnumerable<int> pids =
  1839. (
  1840. from d in customPropDoc.Descendants()
  1841. where d.Name.LocalName == "property"
  1842. select int.Parse(d.Attribute(XName.Get("pid")).Value)
  1843. );
  1844. int pid = 1;
  1845. if (pids.Count() > 0)
  1846. pid = pids.Max();
  1847. // Check if a custom property already exists with this name
  1848. var customProperty =
  1849. (
  1850. from d in customPropDoc.Descendants()
  1851. where (d.Name.LocalName == "property") && (d.Attribute(XName.Get("name")).Value == cp.Name)
  1852. select d
  1853. ).SingleOrDefault();
  1854. // If a custom property with this name already exists remove it.
  1855. if (customProperty != null)
  1856. customProperty.Remove();
  1857. XElement propertiesElement = customPropDoc.Element(XName.Get("Properties", customPropertiesSchema.NamespaceName));
  1858. propertiesElement.Add
  1859. (
  1860. new XElement
  1861. (
  1862. XName.Get("property", customPropertiesSchema.NamespaceName),
  1863. new XAttribute("fmtid", "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"),
  1864. new XAttribute("pid", pid + 1),
  1865. new XAttribute("name", cp.Name),
  1866. new XElement(customVTypesSchema + cp.Type, cp.Value)
  1867. )
  1868. );
  1869. // Save the custom properties
  1870. using (TextWriter tw = new StreamWriter(customPropPart.GetStream(FileMode.Create, FileAccess.Write)))
  1871. customPropDoc.Save(tw, SaveOptions.DisableFormatting);
  1872. // Refresh all fields in this document which display this custom property.
  1873. UpdateCustomPropertyValue(this, cp.Name, cp.Value.ToString());
  1874. }
  1875. internal static void UpdateCustomPropertyValue(DocX document, string customPropertyName, string customPropertyValue)
  1876. {
  1877. foreach (XElement e in document.mainDoc.Descendants(XName.Get("fldSimple", w.NamespaceName)))
  1878. {
  1879. string attr_value = e.Attribute(XName.Get("instr", w.NamespaceName)).Value.Replace(" ", string.Empty).Trim();
  1880. string match_value = string.Format(@"DOCPROPERTY {0} \* MERGEFORMAT", customPropertyName).Replace(" ", string.Empty);
  1881. if (attr_value.Equals(match_value, StringComparison.CurrentCultureIgnoreCase))
  1882. {
  1883. XElement firstRun = e.Element(w + "r");
  1884. XElement firstText = firstRun.Element(w + "t");
  1885. XElement rPr = firstText.Element(w + "rPr");
  1886. // Delete everything and insert updated text value
  1887. e.RemoveNodes();
  1888. XElement t = new XElement(w + "t", rPr, customPropertyValue);
  1889. Novacode.Text.PreserveSpace(t);
  1890. e.Add(new XElement(firstRun.Name, firstRun.Attributes(), firstRun.Element(XName.Get("rPr", w.NamespaceName)), t));
  1891. }
  1892. }
  1893. //#region Headers
  1894. //foreach(PackagePart pp in document.headers)
  1895. //{
  1896. // XDocument header = XDocument.Load(new StreamReader(pp.GetStream()));
  1897. // foreach (XElement e in header.Descendants(XName.Get("fldSimple", w.NamespaceName)))
  1898. // {
  1899. // if (e.Attribute(XName.Get("instr", w.NamespaceName)).Value.Trim().Equals(string.Format(@"DOCPROPERTY {0} \* MERGEFORMAT", customPropertyName), StringComparison.CurrentCultureIgnoreCase))
  1900. // {
  1901. // XElement firstRun = e.Element(w + "r");
  1902. // // Delete everything and insert updated text value
  1903. // e.RemoveNodes();
  1904. // XElement t = new XElement(w + "t", customPropertyValue);
  1905. // Novacode.Text.PreserveSpace(t);
  1906. // e.Add(new XElement(firstRun.Name, firstRun.Attributes(), firstRun.Element(XName.Get("rPr", w.NamespaceName)), t));
  1907. // }
  1908. // }
  1909. // using (TextWriter tw = new StreamWriter(pp.GetStream()))
  1910. // header.Save(tw);
  1911. //}
  1912. //#endregion
  1913. //#region Footers
  1914. //foreach (PackagePart pp in document.footers)
  1915. //{
  1916. // XDocument footer = XDocument.Load(new StreamReader(pp.GetStream()));
  1917. // foreach (XElement e in footer.Descendants(XName.Get("fldSimple", w.NamespaceName)))
  1918. // {
  1919. // if (e.Attribute(XName.Get("instr", w.NamespaceName)).Value.Trim().Equals(string.Format(@"DOCPROPERTY {0} \* MERGEFORMAT", customPropertyName), StringComparison.CurrentCultureIgnoreCase))
  1920. // {
  1921. // XElement firstRun = e.Element(w + "r");
  1922. // // Delete everything and insert updated text value
  1923. // e.RemoveNodes();
  1924. // XElement t = new XElement(w + "t", customPropertyValue);
  1925. // Novacode.Text.PreserveSpace(t);
  1926. // e.Add(new XElement(firstRun.Name, firstRun.Attributes(), firstRun.Element(XName.Get("rPr", w.NamespaceName)), t));
  1927. // }
  1928. // }
  1929. // using (TextWriter tw = new StreamWriter(pp.GetStream()))
  1930. // footer.Save(tw);
  1931. //}
  1932. //#endregion
  1933. }
  1934. public override Paragraph InsertParagraph()
  1935. {
  1936. Paragraph p = base.InsertParagraph();
  1937. p.PackagePart = mainPart;
  1938. return p;
  1939. }
  1940. public override Paragraph InsertParagraph(int index, string text, bool trackChanges)
  1941. {
  1942. Paragraph p = base.InsertParagraph(index, text, trackChanges);
  1943. p.PackagePart = mainPart;
  1944. return p;
  1945. }
  1946. public override Paragraph InsertParagraph(Paragraph p)
  1947. {
  1948. p.PackagePart = mainPart;
  1949. return base.InsertParagraph(p);
  1950. }
  1951. public override Paragraph InsertParagraph(int index, Paragraph p)
  1952. {
  1953. p.PackagePart = mainPart;
  1954. return base.InsertParagraph(index, p);
  1955. }
  1956. public override Paragraph InsertParagraph(int index, string text, bool trackChanges, Formatting formatting)
  1957. {
  1958. Paragraph p = base.InsertParagraph(index, text, trackChanges, formatting);
  1959. p.PackagePart = mainPart;
  1960. return p;
  1961. }
  1962. public override Paragraph InsertParagraph(string text)
  1963. {
  1964. Paragraph p = base.InsertParagraph(text);
  1965. p.PackagePart = mainPart;
  1966. return p;
  1967. }
  1968. public override Paragraph InsertParagraph(string text, bool trackChanges)
  1969. {
  1970. Paragraph p = base.InsertParagraph(text, trackChanges);
  1971. p.PackagePart = mainPart;
  1972. return p;
  1973. }
  1974. public override Paragraph InsertParagraph(string text, bool trackChanges, Formatting formatting)
  1975. {
  1976. Paragraph p = base.InsertParagraph(text, trackChanges, formatting);
  1977. p.PackagePart = mainPart;
  1978. return p;
  1979. }
  1980. #region IDisposable Members
  1981. /// <summary>
  1982. /// Releases all resources used by this document.
  1983. /// </summary>
  1984. /// <example>
  1985. /// If you take advantage of the using keyword, Dispose() is automatically called for you.
  1986. /// <code>
  1987. /// // Load document.
  1988. /// using (DocX document = DocX.Load(@"C:\Example\Test.docx"))
  1989. /// {
  1990. /// // The document is only in memory while in this scope.
  1991. ///
  1992. /// }// Dispose() is automatically called at this point.
  1993. /// </code>
  1994. /// </example>
  1995. /// <example>
  1996. /// This example is equilivant to the one above example.
  1997. /// <code>
  1998. /// // Load document.
  1999. /// DocX document = DocX.Load(@"C:\Example\Test.docx");
  2000. ///
  2001. /// // Do something with the document here.
  2002. ///
  2003. /// // Dispose of the document.
  2004. /// document.Dispose();
  2005. /// </code>
  2006. /// </example>
  2007. public void Dispose()
  2008. {
  2009. package.Close();
  2010. }
  2011. #endregion
  2012. }
  2013. }