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

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045
  1. using System;
  2. using System.IO;
  3. using System.Linq;
  4. using System.Xml.Linq;
  5. using System.IO.Packaging;
  6. using System.Collections.Generic;
  7. using System.Text.RegularExpressions;
  8. using System.Collections.ObjectModel;
  9. namespace Novacode
  10. {
  11. public abstract class Container : DocXElement
  12. {
  13. public virtual ReadOnlyCollection<Content> Contents
  14. {
  15. get
  16. {
  17. List<Content> contents = GetContents();
  18. return contents.AsReadOnly();
  19. }
  20. }
  21. /// <summary>
  22. /// Returns a list of all Paragraphs inside this container.
  23. /// </summary>
  24. /// <example>
  25. /// <code>
  26. /// Load a document.
  27. /// using (DocX document = DocX.Load(@"Test.docx"))
  28. /// {
  29. /// // All Paragraphs in this document.
  30. /// <![CDATA[ List<Paragraph> ]]> documentParagraphs = document.Paragraphs;
  31. ///
  32. /// // Make sure this document contains at least one Table.
  33. /// if (document.Tables.Count() > 0)
  34. /// {
  35. /// // Get the first Table in this document.
  36. /// Table t = document.Tables[0];
  37. ///
  38. /// // All Paragraphs in this Table.
  39. /// <![CDATA[ List<Paragraph> ]]> tableParagraphs = t.Paragraphs;
  40. ///
  41. /// // Make sure this Table contains at least one Row.
  42. /// if (t.Rows.Count() > 0)
  43. /// {
  44. /// // Get the first Row in this document.
  45. /// Row r = t.Rows[0];
  46. ///
  47. /// // All Paragraphs in this Row.
  48. /// <![CDATA[ List<Paragraph> ]]> rowParagraphs = r.Paragraphs;
  49. ///
  50. /// // Make sure this Row contains at least one Cell.
  51. /// if (r.Cells.Count() > 0)
  52. /// {
  53. /// // Get the first Cell in this document.
  54. /// Cell c = r.Cells[0];
  55. ///
  56. /// // All Paragraphs in this Cell.
  57. /// <![CDATA[ List<Paragraph> ]]> cellParagraphs = c.Paragraphs;
  58. /// }
  59. /// }
  60. /// }
  61. ///
  62. /// // Save all changes to this document.
  63. /// document.Save();
  64. /// }// Release this document from memory.
  65. /// </code>
  66. /// </example>
  67. public virtual ReadOnlyCollection<Paragraph> Paragraphs
  68. {
  69. get
  70. {
  71. List<Paragraph> paragraphs = GetParagraphs();
  72. foreach (var p in paragraphs)
  73. {
  74. if ((p.Xml.ElementsAfterSelf().FirstOrDefault() != null) && (p.Xml.ElementsAfterSelf().First().Name.Equals(DocX.w + "tbl")))
  75. p.FollowingTable = new Table(this.Document, p.Xml.ElementsAfterSelf().First());
  76. p.ParentContainer = GetParentFromXmlName(p.Xml.Ancestors().First().Name.LocalName);
  77. if (p.IsListItem)
  78. {
  79. GetListItemType(p);
  80. }
  81. }
  82. return paragraphs.AsReadOnly();
  83. }
  84. }
  85. public virtual ReadOnlyCollection<Paragraph> ParagraphsDeepSearch
  86. {
  87. get
  88. {
  89. List<Paragraph> paragraphs = GetParagraphs(true);
  90. foreach (var p in paragraphs)
  91. {
  92. if ((p.Xml.ElementsAfterSelf().FirstOrDefault() != null) && (p.Xml.ElementsAfterSelf().First().Name.Equals(DocX.w + "tbl")))
  93. p.FollowingTable = new Table(this.Document, p.Xml.ElementsAfterSelf().First());
  94. p.ParentContainer = GetParentFromXmlName(p.Xml.Ancestors().First().Name.LocalName);
  95. if (p.IsListItem)
  96. {
  97. GetListItemType(p);
  98. }
  99. }
  100. return paragraphs.AsReadOnly();
  101. }
  102. }
  103. /// <summary>
  104. /// Removes paragraph at specified position
  105. /// </summary>
  106. /// <param name="index">Index of paragraph to remove</param>
  107. /// <returns>True if removed</returns>
  108. public bool RemoveParagraphAt(int index)
  109. {
  110. int i = 0;
  111. foreach (var paragraph in Xml.Descendants(DocX.w + "p"))
  112. {
  113. if (i == index)
  114. {
  115. paragraph.Remove();
  116. return true;
  117. }
  118. ++i;
  119. }
  120. return false;
  121. }
  122. /// <summary>
  123. /// Removes paragraph
  124. /// </summary>
  125. /// <param name="p">Paragraph to remove</param>
  126. /// <returns>True if removed</returns>
  127. public bool RemoveParagraph(Paragraph p)
  128. {
  129. foreach (var paragraph in Xml.Descendants(DocX.w + "p"))
  130. {
  131. if (paragraph.Equals(p.Xml))
  132. {
  133. paragraph.Remove();
  134. return true;
  135. }
  136. }
  137. return false;
  138. }
  139. public virtual List<Section> Sections
  140. {
  141. get
  142. {
  143. var allParas = Paragraphs;
  144. var parasInASection = new List<Paragraph>();
  145. var sections = new List<Section>();
  146. foreach (var para in allParas)
  147. {
  148. var sectionInPara = para.Xml.Descendants().FirstOrDefault(s => s.Name.LocalName == "sectPr");
  149. if (sectionInPara == null)
  150. {
  151. parasInASection.Add(para);
  152. }
  153. else
  154. {
  155. parasInASection.Add(para);
  156. var section = new Section(Document, sectionInPara) { SectionParagraphs = parasInASection };
  157. sections.Add(section);
  158. parasInASection = new List<Paragraph>();
  159. }
  160. }
  161. XElement body = Xml.Element(XName.Get("body", DocX.w.NamespaceName));
  162. XElement baseSectionXml = body.Element(XName.Get("sectPr", DocX.w.NamespaceName));
  163. var baseSection = new Section(Document, baseSectionXml) { SectionParagraphs = parasInASection };
  164. sections.Add(baseSection);
  165. return sections;
  166. }
  167. }
  168. private void GetListItemType(Paragraph p)
  169. {
  170. var ilvlNode = p.ParagraphNumberProperties.Descendants().FirstOrDefault(el => el.Name.LocalName == "ilvl");
  171. var ilvlValue = ilvlNode.Attribute(DocX.w + "val").Value;
  172. var numIdNode = p.ParagraphNumberProperties.Descendants().FirstOrDefault(el => el.Name.LocalName == "numId");
  173. var numIdValue = numIdNode.Attribute(DocX.w + "val").Value;
  174. //find num node in numbering
  175. var numNodes = Document.numbering.Descendants().Where(n => n.Name.LocalName == "num");
  176. XElement numNode = numNodes.FirstOrDefault(node => node.Attribute(DocX.w + "numId").Value.Equals(numIdValue));
  177. if (numNode != null)
  178. {
  179. //Get abstractNumId node and its value from numNode
  180. var abstractNumIdNode = numNode.Descendants().First(n => n.Name.LocalName == "abstractNumId");
  181. var abstractNumNodeValue = abstractNumIdNode.Attribute(DocX.w + "val").Value;
  182. var abstractNumNodes = Document.numbering.Descendants().Where(n => n.Name.LocalName == "abstractNum");
  183. XElement abstractNumNode =
  184. abstractNumNodes.FirstOrDefault(node => node.Attribute(DocX.w + "abstractNumId").Value.Equals(abstractNumNodeValue));
  185. //Find lvl node
  186. var lvlNodes = abstractNumNode.Descendants().Where(n => n.Name.LocalName == "lvl");
  187. XElement lvlNode = null;
  188. foreach (XElement node in lvlNodes)
  189. {
  190. if (node.Attribute(DocX.w + "ilvl").Value.Equals(ilvlValue))
  191. {
  192. lvlNode = node;
  193. break;
  194. }
  195. }
  196. var numFmtNode = lvlNode.Descendants().First(n => n.Name.LocalName == "numFmt");
  197. p.ListItemType = GetListItemType(numFmtNode.Attribute(DocX.w + "val").Value);
  198. }
  199. }
  200. public ContainerType ParentContainer;
  201. internal List<Content> GetContents(bool deepSearch = false)
  202. {
  203. // Need some memory that can be updated by the recursive search.
  204. //int index = 0;
  205. List<Content> contents = new List<Content>();
  206. foreach (XElement e in Xml.Descendants(XName.Get("sdt", DocX.w.NamespaceName)))
  207. {
  208. Content content = new Content(Document, e, 0);
  209. XElement el = e.Elements(XName.Get("sdtPr", DocX.w.NamespaceName)).First();
  210. content.Name = GetAttribute(el, "alias", "val");
  211. content.Tag = GetAttribute(el, "tag", "val");
  212. contents.Add(content);
  213. }
  214. return contents;
  215. }
  216. private string GetAttribute(XElement e, string localName, string attributeName)
  217. {
  218. string val = string.Empty;
  219. try
  220. {
  221. val = e.Elements(XName.Get(localName, DocX.w.NamespaceName)).Attributes(XName.Get(attributeName, DocX.w.NamespaceName)).FirstOrDefault().Value;
  222. }
  223. catch (Exception)
  224. {
  225. val = "Missing";
  226. }
  227. return val;
  228. }
  229. internal List<Paragraph> GetParagraphs(bool deepSearch = false)
  230. {
  231. // Need some memory that can be updated by the recursive search.
  232. int index = 0;
  233. List<Paragraph> paragraphs = new List<Paragraph>();
  234. foreach (XElement e in Xml.Descendants(XName.Get("p", DocX.w.NamespaceName)))
  235. {
  236. index += HelperFunctions.GetText(e).Length;
  237. Paragraph paragraph = new Paragraph(Document, e, index);
  238. paragraphs.Add(paragraph);
  239. }
  240. // GetParagraphsRecursive(Xml, ref index, ref paragraphs, deepSearch);
  241. return paragraphs;
  242. }
  243. internal void GetParagraphsRecursive(XElement Xml, ref int index, ref List<Paragraph> paragraphs, bool deepSearch = false)
  244. {
  245. // sdtContent are for PageNumbers inside Headers or Footers, don't go any deeper.
  246. //if (Xml.Name.LocalName == "sdtContent")
  247. // return;
  248. var keepSearching = true;
  249. if (Xml.Name.LocalName == "p")
  250. {
  251. paragraphs.Add(new Paragraph(Document, Xml, index));
  252. index += HelperFunctions.GetText(Xml).Length;
  253. if (!deepSearch)
  254. keepSearching = false;
  255. }
  256. if (keepSearching && Xml.HasElements)
  257. {
  258. foreach (XElement e in Xml.Elements())
  259. {
  260. GetParagraphsRecursive(e, ref index, ref paragraphs, deepSearch);
  261. }
  262. }
  263. }
  264. public virtual List<Table> Tables
  265. {
  266. get
  267. {
  268. List<Table> tables =
  269. (
  270. from t in Xml.Descendants(DocX.w + "tbl")
  271. select new Table(Document, t)
  272. ).ToList();
  273. return tables;
  274. }
  275. }
  276. public virtual List<List> Lists
  277. {
  278. get
  279. {
  280. var lists = new List<List>();
  281. var list = new List(Document, Xml);
  282. foreach (var paragraph in Paragraphs)
  283. {
  284. if (paragraph.IsListItem)
  285. {
  286. if (list.CanAddListItem(paragraph))
  287. {
  288. list.AddItem(paragraph);
  289. }
  290. else
  291. {
  292. lists.Add(list);
  293. list = new List(Document, Xml);
  294. list.AddItem(paragraph);
  295. }
  296. }
  297. }
  298. lists.Add(list);
  299. return lists;
  300. }
  301. }
  302. public virtual List<Hyperlink> Hyperlinks
  303. {
  304. get
  305. {
  306. List<Hyperlink> hyperlinks = new List<Hyperlink>();
  307. foreach (Paragraph p in Paragraphs)
  308. hyperlinks.AddRange(p.Hyperlinks);
  309. return hyperlinks;
  310. }
  311. }
  312. public virtual List<Picture> Pictures
  313. {
  314. get
  315. {
  316. List<Picture> pictures = new List<Picture>();
  317. foreach (Paragraph p in Paragraphs)
  318. pictures.AddRange(p.Pictures);
  319. return pictures;
  320. }
  321. }
  322. /// <summary>
  323. /// Sets the Direction of content.
  324. /// </summary>
  325. /// <param name="direction">Direction either LeftToRight or RightToLeft</param>
  326. /// <example>
  327. /// Set the Direction of content in a Paragraph to RightToLeft.
  328. /// <code>
  329. /// // Load a document.
  330. /// using (DocX document = DocX.Load(@"Test.docx"))
  331. /// {
  332. /// // Get the first Paragraph from this document.
  333. /// Paragraph p = document.InsertParagraph();
  334. ///
  335. /// // Set the Direction of this Paragraph.
  336. /// p.Direction = Direction.RightToLeft;
  337. ///
  338. /// // Make sure the document contains at lest one Table.
  339. /// if (document.Tables.Count() > 0)
  340. /// {
  341. /// // Get the first Table from this document.
  342. /// Table t = document.Tables[0];
  343. ///
  344. /// /*
  345. /// * Set the direction of the entire Table.
  346. /// * Note: The same function is available at the Row and Cell level.
  347. /// */
  348. /// t.SetDirection(Direction.RightToLeft);
  349. /// }
  350. ///
  351. /// // Save all changes to this document.
  352. /// document.Save();
  353. /// }// Release this document from memory.
  354. /// </code>
  355. /// </example>
  356. public virtual void SetDirection(Direction direction)
  357. {
  358. foreach (Paragraph p in Paragraphs)
  359. p.Direction = direction;
  360. }
  361. public virtual List<int> FindAll(string str)
  362. {
  363. return FindAll(str, RegexOptions.None);
  364. }
  365. public virtual List<int> FindAll(string str, RegexOptions options)
  366. {
  367. List<int> list = new List<int>();
  368. foreach (Paragraph p in Paragraphs)
  369. {
  370. List<int> indexes = p.FindAll(str, options);
  371. for (int i = 0; i < indexes.Count(); i++)
  372. indexes[0] += p.startIndex;
  373. list.AddRange(indexes);
  374. }
  375. return list;
  376. }
  377. /// <summary>
  378. /// Find all unique instances of the given Regex Pattern,
  379. /// returning the list of the unique strings found
  380. /// </summary>
  381. /// <param name="pattern"></param>
  382. /// <param name="options"></param>
  383. /// <returns></returns>
  384. public virtual List<string> FindUniqueByPattern(string pattern, RegexOptions options)
  385. {
  386. List<string> rawResults = new List<string>();
  387. foreach (Paragraph p in Paragraphs)
  388. { // accumulate the search results from all paragraphs
  389. List<string> partials = p.FindAllByPattern(pattern, options);
  390. rawResults.AddRange(partials);
  391. }
  392. // this dictionary is used to collect results and test for uniqueness
  393. Dictionary<string, int> uniqueResults = new Dictionary<string, int>();
  394. foreach (string currValue in rawResults)
  395. {
  396. if (!uniqueResults.ContainsKey(currValue))
  397. { // if the dictionary doesn't have it, add it
  398. uniqueResults.Add(currValue, 0);
  399. }
  400. }
  401. return uniqueResults.Keys.ToList(); // return the unique list of results
  402. }
  403. public virtual void ReplaceText(string searchValue, string newValue, bool trackChanges = false, RegexOptions options = RegexOptions.None, Formatting newFormatting = null, Formatting matchFormatting = null, MatchFormattingOptions formattingOptions = MatchFormattingOptions.SubsetMatch, bool escapeRegEx = true, bool useRegExSubstitutions = false)
  404. {
  405. if (string.IsNullOrEmpty(searchValue))
  406. throw new ArgumentException("oldValue cannot be null or empty", "searchValue");
  407. if (newValue == null)
  408. throw new ArgumentException("newValue cannot be null or empty", "newValue");
  409. // ReplaceText in Headers of the document.
  410. var headerList = new List<Header> { Document.Headers.first, Document.Headers.even, Document.Headers.odd };
  411. foreach (var header in headerList)
  412. if (header != null)
  413. foreach (var paragraph in header.Paragraphs)
  414. paragraph.ReplaceText(searchValue, newValue, trackChanges, options, newFormatting, matchFormatting, formattingOptions, escapeRegEx, useRegExSubstitutions);
  415. // ReplaceText int main body of document.
  416. foreach (var paragraph in Paragraphs)
  417. paragraph.ReplaceText(searchValue, newValue, trackChanges, options, newFormatting, matchFormatting, formattingOptions, escapeRegEx, useRegExSubstitutions);
  418. // ReplaceText in Footers of the document.
  419. var footerList = new List<Footer> { Document.Footers.first, Document.Footers.even, Document.Footers.odd };
  420. foreach (var footer in footerList)
  421. if (footer != null)
  422. foreach (var paragraph in footer.Paragraphs)
  423. paragraph.ReplaceText(searchValue, newValue, trackChanges, options, newFormatting, matchFormatting, formattingOptions, escapeRegEx, useRegExSubstitutions);
  424. }
  425. /// <summary>
  426. ///
  427. /// </summary>
  428. /// <param name="searchValue">Value to find</param>
  429. /// <param name="regexMatchHandler">A Func that accepts the matching regex search group value and passes it to this to return the replacement string</param>
  430. /// <param name="trackChanges">Enable trackchanges</param>
  431. /// <param name="options">Regex options</param>
  432. /// <param name="newFormatting"></param>
  433. /// <param name="matchFormatting"></param>
  434. /// <param name="formattingOptions"></param>
  435. public virtual void ReplaceText(string searchValue, Func<string, string> regexMatchHandler, bool trackChanges = false, RegexOptions options = RegexOptions.None, Formatting newFormatting = null, Formatting matchFormatting = null, MatchFormattingOptions formattingOptions = MatchFormattingOptions.SubsetMatch)
  436. {
  437. if (string.IsNullOrEmpty(searchValue))
  438. throw new ArgumentException("oldValue cannot be null or empty", "searchValue");
  439. if (regexMatchHandler == null)
  440. throw new ArgumentException("regexMatchHandler cannot be null", "regexMatchHandler");
  441. // ReplaceText in Headers/Footers of the document.
  442. var containerList = new List<IParagraphContainer> {
  443. Document.Headers.first, Document.Headers.even, Document.Headers.odd,
  444. Document.Footers.first, Document.Footers.even, Document.Footers.odd };
  445. foreach (var container in containerList)
  446. if (container != null)
  447. foreach (var paragraph in container.Paragraphs)
  448. paragraph.ReplaceText(searchValue, regexMatchHandler, trackChanges, options, newFormatting, matchFormatting, formattingOptions);
  449. // ReplaceText int main body of document.
  450. foreach (var paragraph in Paragraphs)
  451. paragraph.ReplaceText(searchValue, regexMatchHandler, trackChanges, options, newFormatting, matchFormatting, formattingOptions);
  452. }
  453. /// <summary>
  454. /// Removes all items with required formatting
  455. /// </summary>
  456. /// <returns>Numer of texts removed</returns>
  457. public int RemoveTextInGivenFormat(Formatting matchFormatting, MatchFormattingOptions fo = MatchFormattingOptions.SubsetMatch)
  458. {
  459. var deletedCount = 0;
  460. foreach (var x in Xml.Elements())
  461. {
  462. deletedCount += RemoveTextWithFormatRecursive(x, matchFormatting, fo);
  463. }
  464. return deletedCount;
  465. }
  466. internal int RemoveTextWithFormatRecursive(XElement element, Formatting matchFormatting, MatchFormattingOptions fo)
  467. {
  468. var deletedCount = 0;
  469. foreach (var x in element.Elements())
  470. {
  471. if ("rPr".Equals(x.Name.LocalName))
  472. {
  473. if (HelperFunctions.ContainsEveryChildOf(matchFormatting.Xml, x, fo))
  474. {
  475. x.Parent.Remove();
  476. ++deletedCount;
  477. }
  478. }
  479. deletedCount += RemoveTextWithFormatRecursive(x, matchFormatting, fo);
  480. }
  481. return deletedCount;
  482. }
  483. public virtual void InsertAtBookmark(string toInsert, string bookmarkName)
  484. {
  485. if (bookmarkName.IsNullOrWhiteSpace())
  486. throw new ArgumentException("bookmark cannot be null or empty", "bookmarkName");
  487. var headerCollection = Document.Headers;
  488. var headers = new List<Header> { headerCollection.first, headerCollection.even, headerCollection.odd };
  489. foreach (var header in headers.Where(x => x != null))
  490. foreach (var paragraph in header.Paragraphs)
  491. paragraph.InsertAtBookmark(toInsert, bookmarkName);
  492. foreach (var paragraph in Paragraphs)
  493. paragraph.InsertAtBookmark(toInsert, bookmarkName);
  494. var footerCollection = Document.Footers;
  495. var footers = new List<Footer> { footerCollection.first, footerCollection.even, footerCollection.odd };
  496. foreach (var footer in footers.Where(x => x != null))
  497. foreach (var paragraph in footer.Paragraphs)
  498. paragraph.InsertAtBookmark(toInsert, bookmarkName);
  499. }
  500. public string[] ValidateBookmarks(params string[] bookmarkNames)
  501. {
  502. var headers = new[] { Document.Headers.first, Document.Headers.even, Document.Headers.odd }.Where(h => h != null).ToList();
  503. var footers = new[] { Document.Footers.first, Document.Footers.even, Document.Footers.odd }.Where(f => f != null).ToList();
  504. var nonMatching = new List<string>();
  505. foreach (var bookmarkName in bookmarkNames)
  506. {
  507. if (headers.SelectMany(h => h.Paragraphs).Any(p => p.ValidateBookmark(bookmarkName))) return new string[0];
  508. if (footers.SelectMany(h => h.Paragraphs).Any(p => p.ValidateBookmark(bookmarkName))) return new string[0];
  509. if (Paragraphs.Any(p => p.ValidateBookmark(bookmarkName))) return new string[0];
  510. nonMatching.Add(bookmarkName);
  511. }
  512. return nonMatching.ToArray();
  513. }
  514. public virtual Paragraph InsertParagraph(int index, string text, bool trackChanges)
  515. {
  516. return InsertParagraph(index, text, trackChanges, null);
  517. }
  518. public virtual Paragraph InsertParagraph()
  519. {
  520. return InsertParagraph(string.Empty, false);
  521. }
  522. public virtual Paragraph InsertParagraph(int index, Paragraph p)
  523. {
  524. XElement newXElement = new XElement(p.Xml);
  525. p.Xml = newXElement;
  526. Paragraph paragraph = HelperFunctions.GetFirstParagraphEffectedByInsert(Document, index);
  527. if (paragraph == null)
  528. Xml.Add(p.Xml);
  529. else
  530. {
  531. XElement[] split = HelperFunctions.SplitParagraph(paragraph, index - paragraph.startIndex);
  532. paragraph.Xml.ReplaceWith
  533. (
  534. split[0],
  535. newXElement,
  536. split[1]
  537. );
  538. }
  539. GetParent(p);
  540. return p;
  541. }
  542. public virtual Paragraph InsertParagraph(Paragraph p)
  543. {
  544. #region Styles
  545. XDocument style_document;
  546. if (p.styles.Count() > 0)
  547. {
  548. Uri style_package_uri = new Uri("/word/styles.xml", UriKind.Relative);
  549. if (!Document.package.PartExists(style_package_uri))
  550. {
  551. PackagePart style_package = Document.package.CreatePart(style_package_uri, "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml", CompressionOption.Maximum);
  552. using (TextWriter tw = new StreamWriter(new PackagePartStream(style_package.GetStream())))
  553. {
  554. style_document = new XDocument
  555. (
  556. new XDeclaration("1.0", "UTF-8", "yes"),
  557. new XElement(XName.Get("styles", DocX.w.NamespaceName))
  558. );
  559. style_document.Save(tw);
  560. }
  561. }
  562. PackagePart styles_document = Document.package.GetPart(style_package_uri);
  563. using (TextReader tr = new StreamReader(styles_document.GetStream()))
  564. {
  565. style_document = XDocument.Load(tr);
  566. XElement styles_element = style_document.Element(XName.Get("styles", DocX.w.NamespaceName));
  567. var ids = from d in styles_element.Descendants(XName.Get("style", DocX.w.NamespaceName))
  568. let a = d.Attribute(XName.Get("styleId", DocX.w.NamespaceName))
  569. where a != null
  570. select a.Value;
  571. foreach (XElement style in p.styles)
  572. {
  573. // If styles_element does not contain this element, then add it.
  574. if (!ids.Contains(style.Attribute(XName.Get("styleId", DocX.w.NamespaceName)).Value))
  575. styles_element.Add(style);
  576. }
  577. }
  578. using (TextWriter tw = new StreamWriter(new PackagePartStream(styles_document.GetStream())))
  579. style_document.Save(tw);
  580. }
  581. #endregion
  582. XElement newXElement = new XElement(p.Xml);
  583. Xml.Add(newXElement);
  584. int index = 0;
  585. if (Document.paragraphLookup.Keys.Count() > 0)
  586. {
  587. index = Document.paragraphLookup.Last().Key;
  588. if (Document.paragraphLookup.Last().Value.Text.Length == 0)
  589. index++;
  590. else
  591. index += Document.paragraphLookup.Last().Value.Text.Length;
  592. }
  593. Paragraph newParagraph = new Paragraph(Document, newXElement, index);
  594. Document.paragraphLookup.Add(index, newParagraph);
  595. GetParent(newParagraph);
  596. return newParagraph;
  597. }
  598. public virtual Paragraph InsertParagraph(int index, string text, bool trackChanges, Formatting formatting)
  599. {
  600. Paragraph newParagraph = new Paragraph(Document, new XElement(DocX.w + "p"), index);
  601. newParagraph.InsertText(0, text, trackChanges, formatting);
  602. Paragraph firstPar = HelperFunctions.GetFirstParagraphEffectedByInsert(Document, index);
  603. if (firstPar != null)
  604. {
  605. var splitindex = index - firstPar.startIndex;
  606. if (splitindex <= 0)
  607. {
  608. firstPar.Xml.ReplaceWith(newParagraph.Xml, firstPar.Xml);
  609. }
  610. else
  611. {
  612. XElement[] splitParagraph = HelperFunctions.SplitParagraph(firstPar, splitindex);
  613. firstPar.Xml.ReplaceWith
  614. (
  615. splitParagraph[0],
  616. newParagraph.Xml,
  617. splitParagraph[1]
  618. );
  619. }
  620. }
  621. else
  622. Xml.Add(newParagraph);
  623. GetParent(newParagraph);
  624. return newParagraph;
  625. }
  626. private ContainerType GetParentFromXmlName(string xmlName)
  627. {
  628. ContainerType parent;
  629. switch (xmlName)
  630. {
  631. case "body":
  632. parent = ContainerType.Body;
  633. break;
  634. case "p":
  635. parent = ContainerType.Paragraph;
  636. break;
  637. case "tbl":
  638. parent = ContainerType.Table;
  639. break;
  640. case "sectPr":
  641. parent = ContainerType.Section;
  642. break;
  643. case "tc":
  644. parent = ContainerType.Cell;
  645. break;
  646. default:
  647. parent = ContainerType.None;
  648. break;
  649. }
  650. return parent;
  651. }
  652. private void GetParent(Paragraph newParagraph)
  653. {
  654. var containerType = GetType();
  655. switch (containerType.Name)
  656. {
  657. case "Body":
  658. newParagraph.ParentContainer = ContainerType.Body;
  659. break;
  660. case "Table":
  661. newParagraph.ParentContainer = ContainerType.Table;
  662. break;
  663. case "TOC":
  664. newParagraph.ParentContainer = ContainerType.TOC;
  665. break;
  666. case "Section":
  667. newParagraph.ParentContainer = ContainerType.Section;
  668. break;
  669. case "Cell":
  670. newParagraph.ParentContainer = ContainerType.Cell;
  671. break;
  672. case "Header":
  673. newParagraph.ParentContainer = ContainerType.Header;
  674. break;
  675. case "Footer":
  676. newParagraph.ParentContainer = ContainerType.Footer;
  677. break;
  678. case "Paragraph":
  679. newParagraph.ParentContainer = ContainerType.Paragraph;
  680. break;
  681. }
  682. }
  683. private ListItemType GetListItemType(string styleName)
  684. {
  685. ListItemType listItemType;
  686. switch (styleName)
  687. {
  688. case "bullet":
  689. listItemType = ListItemType.Bulleted;
  690. break;
  691. default:
  692. listItemType = ListItemType.Numbered;
  693. break;
  694. }
  695. return listItemType;
  696. }
  697. public virtual void InsertSection()
  698. {
  699. InsertSection(false);
  700. }
  701. public virtual void InsertSection(bool trackChanges)
  702. {
  703. var newParagraphSection = new XElement
  704. (
  705. XName.Get("p", DocX.w.NamespaceName), new XElement(XName.Get("pPr", DocX.w.NamespaceName), new XElement(XName.Get("sectPr", DocX.w.NamespaceName), new XElement(XName.Get("type", DocX.w.NamespaceName), new XAttribute(DocX.w + "val", "continuous"))))
  706. );
  707. if (trackChanges)
  708. newParagraphSection = HelperFunctions.CreateEdit(EditType.ins, DateTime.Now, newParagraphSection);
  709. Xml.Add(newParagraphSection);
  710. }
  711. public virtual void InsertSectionPageBreak(bool trackChanges = false)
  712. {
  713. var newParagraphSection = new XElement
  714. (
  715. XName.Get("p", DocX.w.NamespaceName), new XElement(XName.Get("pPr", DocX.w.NamespaceName), new XElement(XName.Get("sectPr", DocX.w.NamespaceName)))
  716. );
  717. if (trackChanges)
  718. newParagraphSection = HelperFunctions.CreateEdit(EditType.ins, DateTime.Now, newParagraphSection);
  719. Xml.Add(newParagraphSection);
  720. }
  721. public virtual Paragraph InsertParagraph(string text)
  722. {
  723. return InsertParagraph(text, false, new Formatting());
  724. }
  725. public virtual Paragraph InsertParagraph(string text, bool trackChanges)
  726. {
  727. return InsertParagraph(text, trackChanges, new Formatting());
  728. }
  729. public virtual Paragraph InsertParagraph(string text, bool trackChanges, Formatting formatting)
  730. {
  731. XElement newParagraph = new XElement
  732. (
  733. XName.Get("p", DocX.w.NamespaceName), new XElement(XName.Get("pPr", DocX.w.NamespaceName)), HelperFunctions.FormatInput(text, formatting.Xml)
  734. );
  735. if (trackChanges)
  736. newParagraph = HelperFunctions.CreateEdit(EditType.ins, DateTime.Now, newParagraph);
  737. Xml.Add(newParagraph);
  738. var paragraphAdded = new Paragraph(Document, newParagraph, 0);
  739. if (this is Cell)
  740. {
  741. var cell = this as Cell;
  742. paragraphAdded.PackagePart = cell.mainPart;
  743. }
  744. else if (this is DocX)
  745. {
  746. paragraphAdded.PackagePart = Document.mainPart;
  747. }
  748. else if (this is Footer)
  749. {
  750. var f = this as Footer;
  751. paragraphAdded.mainPart = f.mainPart;
  752. }
  753. else if (this is Header)
  754. {
  755. var h = this as Header;
  756. paragraphAdded.mainPart = h.mainPart;
  757. }
  758. else
  759. {
  760. Console.WriteLine("No idea what we are {0}", this);
  761. paragraphAdded.PackagePart = Document.mainPart;
  762. }
  763. GetParent(paragraphAdded);
  764. return paragraphAdded;
  765. }
  766. public virtual Paragraph InsertEquation(string equation)
  767. {
  768. Paragraph p = InsertParagraph();
  769. p.AppendEquation(equation);
  770. return p;
  771. }
  772. public virtual Paragraph InsertBookmark(String bookmarkName)
  773. {
  774. var p = InsertParagraph();
  775. p.AppendBookmark(bookmarkName);
  776. return p;
  777. }
  778. public virtual Table InsertTable(int rowCount, int columnCount) //Dmitchern, changed to virtual, and overrided in Table.Cell
  779. {
  780. XElement newTable = HelperFunctions.CreateTable(rowCount, columnCount);
  781. Xml.Add(newTable);
  782. return new Table(Document, newTable) { mainPart = mainPart };
  783. }
  784. public Table InsertTable(int index, int rowCount, int columnCount)
  785. {
  786. XElement newTable = HelperFunctions.CreateTable(rowCount, columnCount);
  787. Paragraph p = HelperFunctions.GetFirstParagraphEffectedByInsert(Document, index);
  788. if (p == null)
  789. Xml.Elements().First().AddFirst(newTable);
  790. else
  791. {
  792. XElement[] split = HelperFunctions.SplitParagraph(p, index - p.startIndex);
  793. p.Xml.ReplaceWith
  794. (
  795. split[0],
  796. newTable,
  797. split[1]
  798. );
  799. }
  800. return new Table(Document, newTable) { mainPart = mainPart };
  801. }
  802. public Table InsertTable(Table t)
  803. {
  804. XElement newXElement = new XElement(t.Xml);
  805. Xml.Add(newXElement);
  806. Table newTable = new Table(Document, newXElement)
  807. {
  808. mainPart = mainPart,
  809. Design = t.Design
  810. };
  811. return newTable;
  812. }
  813. public Table InsertTable(int index, Table t)
  814. {
  815. Paragraph p = HelperFunctions.GetFirstParagraphEffectedByInsert(Document, index);
  816. XElement[] split = HelperFunctions.SplitParagraph(p, index - p.startIndex);
  817. XElement newXElement = new XElement(t.Xml);
  818. p.Xml.ReplaceWith
  819. (
  820. split[0],
  821. newXElement,
  822. split[1]
  823. );
  824. Table newTable = new Table(Document, newXElement)
  825. {
  826. mainPart = mainPart,
  827. Design = t.Design
  828. };
  829. return newTable;
  830. }
  831. internal Container(DocX document, XElement xml)
  832. : base(document, xml)
  833. {
  834. }
  835. public List InsertList(List list)
  836. {
  837. foreach (var item in list.Items)
  838. {
  839. Xml.Add(item.Xml);
  840. }
  841. return list;
  842. }
  843. public List InsertList(List list, double fontSize)
  844. {
  845. foreach (var item in list.Items)
  846. {
  847. item.FontSize(fontSize);
  848. Xml.Add(item.Xml);
  849. }
  850. return list;
  851. }
  852. public List InsertList(List list, Font fontFamily, double fontSize)
  853. {
  854. foreach (var item in list.Items)
  855. {
  856. item.Font(fontFamily);
  857. item.FontSize(fontSize);
  858. Xml.Add(item.Xml);
  859. }
  860. return list;
  861. }
  862. public List InsertList(int index, List list)
  863. {
  864. Paragraph p = HelperFunctions.GetFirstParagraphEffectedByInsert(Document, index);
  865. XElement[] split = HelperFunctions.SplitParagraph(p, index - p.startIndex);
  866. var elements = new List<XElement> { split[0] };
  867. elements.AddRange(list.Items.Select(i => new XElement(i.Xml)));
  868. elements.Add(split[1]);
  869. p.Xml.ReplaceWith(elements.ToArray());
  870. return list;
  871. }
  872. }
  873. }