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

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.IO.Packaging;
  5. using System.Linq;
  6. using System.Security.Cryptography;
  7. using System.Text;
  8. using System.Text.RegularExpressions;
  9. using System.Xml;
  10. using System.Xml.Linq;
  11. using System.Collections.ObjectModel;
  12. namespace Novacode
  13. {
  14. /// <summary>
  15. /// Represents a document.
  16. /// </summary>
  17. public class DocX : Container, IDisposable
  18. {
  19. #region Namespaces
  20. static internal XNamespace w = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
  21. static internal XNamespace rel = "http://schemas.openxmlformats.org/package/2006/relationships";
  22. static internal XNamespace r = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
  23. static internal XNamespace m = "http://schemas.openxmlformats.org/officeDocument/2006/math";
  24. static internal XNamespace customPropertiesSchema = "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties";
  25. static internal XNamespace customVTypesSchema = "http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes";
  26. static internal XNamespace wp = "http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing";
  27. static internal XNamespace a = "http://schemas.openxmlformats.org/drawingml/2006/main";
  28. static internal XNamespace c = "http://schemas.openxmlformats.org/drawingml/2006/chart";
  29. static internal XNamespace v = "urn:schemas-microsoft-com:vml";
  30. internal static XNamespace n = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering";
  31. #endregion
  32. internal float getMarginAttribute(XName name)
  33. {
  34. XElement body = mainDoc.Root.Element(XName.Get("body", DocX.w.NamespaceName));
  35. XElement sectPr = body.Element(XName.Get("sectPr", DocX.w.NamespaceName));
  36. if (sectPr != null)
  37. {
  38. XElement pgMar = sectPr.Element(XName.Get("pgMar", DocX.w.NamespaceName));
  39. if (pgMar != null)
  40. {
  41. XAttribute top = pgMar.Attribute(name);
  42. if (top != null)
  43. {
  44. float f;
  45. if (float.TryParse(top.Value, out f))
  46. return (int)(f / 20.0f);
  47. }
  48. }
  49. }
  50. return 0;
  51. }
  52. internal void setMarginAttribute(XName xName, float value)
  53. {
  54. XElement body = mainDoc.Root.Element(XName.Get("body", DocX.w.NamespaceName));
  55. XElement sectPr = body.Element(XName.Get("sectPr", DocX.w.NamespaceName));
  56. if (sectPr != null)
  57. {
  58. XElement pgMar = sectPr.Element(XName.Get("pgMar", DocX.w.NamespaceName));
  59. if (pgMar != null)
  60. {
  61. XAttribute top = pgMar.Attribute(xName);
  62. if (top != null)
  63. {
  64. top.SetValue(value * 20);
  65. }
  66. }
  67. }
  68. }
  69. public BookmarkCollection Bookmarks
  70. {
  71. get
  72. {
  73. BookmarkCollection bookmarks = new BookmarkCollection();
  74. foreach (Paragraph paragraph in Paragraphs)
  75. bookmarks.AddRange(paragraph.GetBookmarks());
  76. return bookmarks;
  77. }
  78. }
  79. /// <summary>
  80. /// Top margin value in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point.
  81. /// </summary>
  82. public float MarginTop
  83. {
  84. get
  85. {
  86. return getMarginAttribute(XName.Get("top", DocX.w.NamespaceName));
  87. }
  88. set
  89. {
  90. setMarginAttribute(XName.Get("top", DocX.w.NamespaceName), value);
  91. }
  92. }
  93. /// <summary>
  94. /// Bottom margin value in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point.
  95. /// </summary>
  96. public float MarginBottom
  97. {
  98. get
  99. {
  100. return getMarginAttribute(XName.Get("bottom", DocX.w.NamespaceName));
  101. }
  102. set
  103. {
  104. setMarginAttribute(XName.Get("bottom", DocX.w.NamespaceName), value);
  105. }
  106. }
  107. /// <summary>
  108. /// Left margin value in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point.
  109. /// </summary>
  110. public float MarginLeft
  111. {
  112. get
  113. {
  114. return getMarginAttribute(XName.Get("left", DocX.w.NamespaceName));
  115. }
  116. set
  117. {
  118. setMarginAttribute(XName.Get("left", DocX.w.NamespaceName), value);
  119. }
  120. }
  121. /// <summary>
  122. /// Right margin value in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point.
  123. /// </summary>
  124. public float MarginRight
  125. {
  126. get
  127. {
  128. return getMarginAttribute(XName.Get("right", DocX.w.NamespaceName));
  129. }
  130. set
  131. {
  132. setMarginAttribute(XName.Get("right", DocX.w.NamespaceName), value);
  133. }
  134. }
  135. /// <summary>
  136. /// Page width value in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point.
  137. /// </summary>
  138. public float PageWidth
  139. {
  140. get
  141. {
  142. XElement body = mainDoc.Root.Element(XName.Get("body", DocX.w.NamespaceName));
  143. XElement sectPr = body.Element(XName.Get("sectPr", DocX.w.NamespaceName));
  144. if (sectPr != null)
  145. {
  146. XElement pgSz = sectPr.Element(XName.Get("pgSz", DocX.w.NamespaceName));
  147. if (pgSz != null)
  148. {
  149. XAttribute w = pgSz.Attribute(XName.Get("w", DocX.w.NamespaceName));
  150. if (w != null)
  151. {
  152. float f;
  153. if (float.TryParse(w.Value, out f))
  154. return (int)(f / 20.0f);
  155. }
  156. }
  157. }
  158. return (12240.0f / 20.0f);
  159. }
  160. set
  161. {
  162. XElement body = mainDoc.Root.Element(XName.Get("body", DocX.w.NamespaceName));
  163. if (body != null)
  164. {
  165. XElement sectPr = body.Element(XName.Get("sectPr", DocX.w.NamespaceName));
  166. if (sectPr != null)
  167. {
  168. XElement pgSz = sectPr.Element(XName.Get("pgSz", DocX.w.NamespaceName));
  169. if (pgSz != null)
  170. {
  171. pgSz.SetAttributeValue(XName.Get("w", DocX.w.NamespaceName), value * 20);
  172. }
  173. }
  174. }
  175. }
  176. }
  177. /// <summary>
  178. /// Page height value in points. 1pt = 1/72 of an inch. Word internally writes docx using units = 1/20th of a point.
  179. /// </summary>
  180. public float PageHeight
  181. {
  182. get
  183. {
  184. XElement body = mainDoc.Root.Element(XName.Get("body", DocX.w.NamespaceName));
  185. XElement sectPr = body.Element(XName.Get("sectPr", DocX.w.NamespaceName));
  186. if (sectPr != null)
  187. {
  188. XElement pgSz = sectPr.Element(XName.Get("pgSz", DocX.w.NamespaceName));
  189. if (pgSz != null)
  190. {
  191. XAttribute w = pgSz.Attribute(XName.Get("h", DocX.w.NamespaceName));
  192. if (w != null)
  193. {
  194. float f;
  195. if (float.TryParse(w.Value, out f))
  196. return (int)(f / 20.0f);
  197. }
  198. }
  199. }
  200. return (15840.0f / 20.0f);
  201. }
  202. set
  203. {
  204. XElement body = mainDoc.Root.Element(XName.Get("body", DocX.w.NamespaceName));
  205. if (body != null)
  206. {
  207. XElement sectPr = body.Element(XName.Get("sectPr", DocX.w.NamespaceName));
  208. if (sectPr != null)
  209. {
  210. XElement pgSz = sectPr.Element(XName.Get("pgSz", DocX.w.NamespaceName));
  211. if (pgSz != null)
  212. {
  213. pgSz.SetAttributeValue(XName.Get("h", DocX.w.NamespaceName), value * 20);
  214. }
  215. }
  216. }
  217. }
  218. }
  219. /// <summary>
  220. /// Returns true if any editing restrictions are imposed on this document.
  221. /// </summary>
  222. /// <example>
  223. /// <code>
  224. /// // Create a new document.
  225. /// using (DocX document = DocX.Create(@"Test.docx"))
  226. /// {
  227. /// if(document.isProtected)
  228. /// Console.WriteLine("Protected");
  229. /// else
  230. /// Console.WriteLine("Not protected");
  231. ///
  232. /// // Save the document.
  233. /// document.Save();
  234. /// }
  235. /// </code>
  236. /// </example>
  237. /// <seealso cref="AddProtection(EditRestrictions)"/>
  238. /// <seealso cref="RemoveProtection"/>
  239. /// <seealso cref="GetProtectionType"/>
  240. public bool isProtected
  241. {
  242. get
  243. {
  244. return settings.Descendants(XName.Get("documentProtection", DocX.w.NamespaceName)).Count() > 0;
  245. }
  246. }
  247. /// <summary>
  248. /// Returns the type of editing protection imposed on this document.
  249. /// </summary>
  250. /// <returns>The type of editing protection imposed on this document.</returns>
  251. /// <example>
  252. /// <code>
  253. /// Create a new document.
  254. /// using (DocX document = DocX.Create(@"Test.docx"))
  255. /// {
  256. /// // Make sure the document is protected before checking the protection type.
  257. /// if (document.isProtected)
  258. /// {
  259. /// EditRestrictions protection = document.GetProtectionType();
  260. /// Console.WriteLine("Document is protected using " + protection.ToString());
  261. /// }
  262. ///
  263. /// else
  264. /// Console.WriteLine("Document is not protected.");
  265. ///
  266. /// // Save the document.
  267. /// document.Save();
  268. /// }
  269. /// </code>
  270. /// </example>
  271. /// <seealso cref="AddProtection(EditRestrictions)"/>
  272. /// <seealso cref="RemoveProtection"/>
  273. /// <seealso cref="isProtected"/>
  274. public EditRestrictions GetProtectionType()
  275. {
  276. if (isProtected)
  277. {
  278. XElement documentProtection = settings.Descendants(XName.Get("documentProtection", DocX.w.NamespaceName)).FirstOrDefault();
  279. string edit_type = documentProtection.Attribute(XName.Get("edit", DocX.w.NamespaceName)).Value;
  280. return (EditRestrictions)Enum.Parse(typeof(EditRestrictions), edit_type);
  281. }
  282. return EditRestrictions.none;
  283. }
  284. /// <summary>
  285. /// Add editing protection to this document.
  286. /// </summary>
  287. /// <param name="er">The type of protection to add to this document.</param>
  288. /// <example>
  289. /// <code>
  290. /// // Create a new document.
  291. /// using (DocX document = DocX.Create(@"Test.docx"))
  292. /// {
  293. /// // Allow no editing, only the adding of comment.
  294. /// document.AddProtection(EditRestrictions.comments);
  295. ///
  296. /// // Save the document.
  297. /// document.Save();
  298. /// }
  299. /// </code>
  300. /// </example>
  301. /// <seealso cref="RemoveProtection"/>
  302. /// <seealso cref="GetProtectionType"/>
  303. /// <seealso cref="isProtected"/>
  304. public void AddProtection(EditRestrictions er)
  305. {
  306. // Call remove protection before adding a new protection element.
  307. RemoveProtection();
  308. if (er == EditRestrictions.none)
  309. return;
  310. XElement documentProtection = new XElement(XName.Get("documentProtection", DocX.w.NamespaceName));
  311. documentProtection.Add(new XAttribute(XName.Get("edit", DocX.w.NamespaceName), er.ToString()));
  312. documentProtection.Add(new XAttribute(XName.Get("enforcement", DocX.w.NamespaceName), "1"));
  313. settings.Root.AddFirst(documentProtection);
  314. }
  315. public void AddProtection(EditRestrictions er, string strPassword)
  316. {
  317. // http://blogs.msdn.com/b/vsod/archive/2010/04/05/how-to-set-the-editing-restrictions-in-word-using-open-xml-sdk-2-0.aspx
  318. // Call remove protection before adding a new protection element.
  319. RemoveProtection();
  320. if (er == EditRestrictions.none)
  321. return;
  322. XElement documentProtection = new XElement(XName.Get("documentProtection", DocX.w.NamespaceName));
  323. documentProtection.Add(new XAttribute(XName.Get("edit", DocX.w.NamespaceName), er.ToString()));
  324. documentProtection.Add(new XAttribute(XName.Get("enforcement", DocX.w.NamespaceName), "1"));
  325. int[] InitialCodeArray = { 0xE1F0, 0x1D0F, 0xCC9C, 0x84C0, 0x110C, 0x0E10, 0xF1CE, 0x313E, 0x1872, 0xE139, 0xD40F, 0x84F9, 0x280C, 0xA96A, 0x4EC3 };
  326. int[,] EncryptionMatrix = new int[15, 7]
  327. {
  328. /* char 1 */ {0xAEFC, 0x4DD9, 0x9BB2, 0x2745, 0x4E8A, 0x9D14, 0x2A09},
  329. /* char 2 */ {0x7B61, 0xF6C2, 0xFDA5, 0xEB6B, 0xC6F7, 0x9DCF, 0x2BBF},
  330. /* char 3 */ {0x4563, 0x8AC6, 0x05AD, 0x0B5A, 0x16B4, 0x2D68, 0x5AD0},
  331. /* char 4 */ {0x0375, 0x06EA, 0x0DD4, 0x1BA8, 0x3750, 0x6EA0, 0xDD40},
  332. /* char 5 */ {0xD849, 0xA0B3, 0x5147, 0xA28E, 0x553D, 0xAA7A, 0x44D5},
  333. /* char 6 */ {0x6F45, 0xDE8A, 0xAD35, 0x4A4B, 0x9496, 0x390D, 0x721A},
  334. /* char 7 */ {0xEB23, 0xC667, 0x9CEF, 0x29FF, 0x53FE, 0xA7FC, 0x5FD9},
  335. /* char 8 */ {0x47D3, 0x8FA6, 0x0F6D, 0x1EDA, 0x3DB4, 0x7B68, 0xF6D0},
  336. /* char 9 */ {0xB861, 0x60E3, 0xC1C6, 0x93AD, 0x377B, 0x6EF6, 0xDDEC},
  337. /* char 10 */ {0x45A0, 0x8B40, 0x06A1, 0x0D42, 0x1A84, 0x3508, 0x6A10},
  338. /* char 11 */ {0xAA51, 0x4483, 0x8906, 0x022D, 0x045A, 0x08B4, 0x1168},
  339. /* char 12 */ {0x76B4, 0xED68, 0xCAF1, 0x85C3, 0x1BA7, 0x374E, 0x6E9C},
  340. /* char 13 */ {0x3730, 0x6E60, 0xDCC0, 0xA9A1, 0x4363, 0x86C6, 0x1DAD},
  341. /* char 14 */ {0x3331, 0x6662, 0xCCC4, 0x89A9, 0x0373, 0x06E6, 0x0DCC},
  342. /* char 15 */ {0x1021, 0x2042, 0x4084, 0x8108, 0x1231, 0x2462, 0x48C4}
  343. };
  344. // Generate the Salt
  345. byte[] arrSalt = new byte[16];
  346. RandomNumberGenerator rand = new RNGCryptoServiceProvider();
  347. rand.GetNonZeroBytes(arrSalt);
  348. //Array to hold Key Values
  349. byte[] generatedKey = new byte[4];
  350. //Maximum length of the password is 15 chars.
  351. int intMaxPasswordLength = 15;
  352. if (!String.IsNullOrEmpty(strPassword))
  353. {
  354. strPassword = strPassword.Substring(0, Math.Min(strPassword.Length, intMaxPasswordLength));
  355. byte[] arrByteChars = new byte[strPassword.Length];
  356. for (int intLoop = 0; intLoop < strPassword.Length; intLoop++)
  357. {
  358. int intTemp = Convert.ToInt32(strPassword[intLoop]);
  359. arrByteChars[intLoop] = Convert.ToByte(intTemp & 0x00FF);
  360. if (arrByteChars[intLoop] == 0)
  361. arrByteChars[intLoop] = Convert.ToByte((intTemp & 0xFF00) >> 8);
  362. }
  363. int intHighOrderWord = InitialCodeArray[arrByteChars.Length - 1];
  364. for (int intLoop = 0; intLoop < arrByteChars.Length; intLoop++)
  365. {
  366. int tmp = intMaxPasswordLength - arrByteChars.Length + intLoop;
  367. for (int intBit = 0; intBit < 7; intBit++)
  368. {
  369. if ((arrByteChars[intLoop] & (0x0001 << intBit)) != 0)
  370. {
  371. intHighOrderWord ^= EncryptionMatrix[tmp, intBit];
  372. }
  373. }
  374. }
  375. int intLowOrderWord = 0;
  376. // For each character in the strPassword, going backwards
  377. for (int intLoopChar = arrByteChars.Length - 1; intLoopChar >= 0; intLoopChar--)
  378. {
  379. intLowOrderWord = (((intLowOrderWord >> 14) & 0x0001) | ((intLowOrderWord << 1) & 0x7FFF)) ^ arrByteChars[intLoopChar];
  380. }
  381. intLowOrderWord = (((intLowOrderWord >> 14) & 0x0001) | ((intLowOrderWord << 1) & 0x7FFF)) ^ arrByteChars.Length ^ 0xCE4B;
  382. // Combine the Low and High Order Word
  383. int intCombinedkey = (intHighOrderWord << 16) + intLowOrderWord;
  384. // The byte order of the result shall be reversed [Example: 0x64CEED7E becomes 7EEDCE64. end example],
  385. // and that value shall be hashed as defined by the attribute values.
  386. for (int intTemp = 0; intTemp < 4; intTemp++)
  387. {
  388. generatedKey[intTemp] = Convert.ToByte(((uint)(intCombinedkey & (0x000000FF << (intTemp * 8)))) >> (intTemp * 8));
  389. }
  390. }
  391. StringBuilder sb = new StringBuilder();
  392. for (int intTemp = 0; intTemp < 4; intTemp++)
  393. {
  394. sb.Append(Convert.ToString(generatedKey[intTemp], 16));
  395. }
  396. generatedKey = Encoding.Unicode.GetBytes(sb.ToString().ToUpper());
  397. byte[] tmpArray1 = generatedKey;
  398. byte[] tmpArray2 = arrSalt;
  399. byte[] tempKey = new byte[tmpArray1.Length + tmpArray2.Length];
  400. Buffer.BlockCopy(tmpArray2, 0, tempKey, 0, tmpArray2.Length);
  401. Buffer.BlockCopy(tmpArray1, 0, tempKey, tmpArray2.Length, tmpArray1.Length);
  402. generatedKey = tempKey;
  403. int iterations = 100000;
  404. HashAlgorithm sha1 = new SHA1Managed();
  405. generatedKey = sha1.ComputeHash(generatedKey);
  406. byte[] iterator = new byte[4];
  407. for (int intTmp = 0; intTmp < iterations; intTmp++)
  408. {
  409. iterator[0] = Convert.ToByte((intTmp & 0x000000FF) >> 0);
  410. iterator[1] = Convert.ToByte((intTmp & 0x0000FF00) >> 8);
  411. iterator[2] = Convert.ToByte((intTmp & 0x00FF0000) >> 16);
  412. iterator[3] = Convert.ToByte((intTmp & 0xFF000000) >> 24);
  413. generatedKey = concatByteArrays(iterator, generatedKey);
  414. generatedKey = sha1.ComputeHash(generatedKey);
  415. }
  416. documentProtection.Add(new XAttribute(XName.Get("cryptProviderType", DocX.w.NamespaceName), "rsaFull"));
  417. documentProtection.Add(new XAttribute(XName.Get("cryptAlgorithmClass", DocX.w.NamespaceName), "hash"));
  418. documentProtection.Add(new XAttribute(XName.Get("cryptAlgorithmType", DocX.w.NamespaceName), "typeAny"));
  419. documentProtection.Add(new XAttribute(XName.Get("cryptAlgorithmSid", DocX.w.NamespaceName), "4")); // SHA1
  420. documentProtection.Add(new XAttribute(XName.Get("cryptSpinCount", DocX.w.NamespaceName), iterations.ToString()));
  421. documentProtection.Add(new XAttribute(XName.Get("hash", DocX.w.NamespaceName), Convert.ToBase64String(generatedKey)));
  422. documentProtection.Add(new XAttribute(XName.Get("salt", DocX.w.NamespaceName), Convert.ToBase64String(arrSalt)));
  423. settings.Root.AddFirst(documentProtection);
  424. }
  425. private byte[] concatByteArrays(byte[] array1, byte[] array2)
  426. {
  427. byte[] result = new byte[array1.Length + array2.Length];
  428. Buffer.BlockCopy(array2, 0, result, 0, array2.Length);
  429. Buffer.BlockCopy(array1, 0, result, array2.Length, array1.Length);
  430. return result;
  431. }
  432. /// <summary>
  433. /// Remove editing protection from this document.
  434. /// </summary>
  435. /// <example>
  436. /// <code>
  437. /// // Create a new document.
  438. /// using (DocX document = DocX.Create(@"Test.docx"))
  439. /// {
  440. /// // Remove any editing restrictions that are imposed on this document.
  441. /// document.RemoveProtection();
  442. ///
  443. /// // Save the document.
  444. /// document.Save();
  445. /// }
  446. /// </code>
  447. /// </example>
  448. /// <seealso cref="AddProtection(EditRestrictions)"/>
  449. /// <seealso cref="GetProtectionType"/>
  450. /// <seealso cref="isProtected"/>
  451. public void RemoveProtection()
  452. {
  453. // Remove every node of type documentProtection.
  454. settings.Descendants(XName.Get("documentProtection", DocX.w.NamespaceName)).Remove();
  455. }
  456. public PageLayout PageLayout
  457. {
  458. get
  459. {
  460. XElement sectPr = Xml.Element(XName.Get("sectPr", DocX.w.NamespaceName));
  461. if (sectPr == null)
  462. {
  463. Xml.SetElementValue(XName.Get("sectPr", DocX.w.NamespaceName), string.Empty);
  464. sectPr = Xml.Element(XName.Get("sectPr", DocX.w.NamespaceName));
  465. }
  466. return new PageLayout(this, sectPr);
  467. }
  468. }
  469. /// <summary>
  470. /// Returns a collection of Headers in this Document.
  471. /// A document typically contains three Headers.
  472. /// A default one (odd), one for the first page and one for even pages.
  473. /// </summary>
  474. /// <example>
  475. /// <code>
  476. /// // Create a document.
  477. /// using (DocX document = DocX.Create(@"Test.docx"))
  478. /// {
  479. /// // Add header support to this document.
  480. /// document.AddHeaders();
  481. ///
  482. /// // Get a collection of all headers in this document.
  483. /// Headers headers = document.Headers;
  484. ///
  485. /// // The header used for the first page of this document.
  486. /// Header first = headers.first;
  487. ///
  488. /// // The header used for odd pages of this document.
  489. /// Header odd = headers.odd;
  490. ///
  491. /// // The header used for even pages of this document.
  492. /// Header even = headers.even;
  493. /// }
  494. /// </code>
  495. /// </example>
  496. public Headers Headers
  497. {
  498. get
  499. {
  500. return headers;
  501. }
  502. }
  503. private Headers headers;
  504. /// <summary>
  505. /// Returns a collection of Footers in this Document.
  506. /// A document typically contains three Footers.
  507. /// A default one (odd), one for the first page and one for even pages.
  508. /// </summary>
  509. /// <example>
  510. /// <code>
  511. /// // Create a document.
  512. /// using (DocX document = DocX.Create(@"Test.docx"))
  513. /// {
  514. /// // Add footer support to this document.
  515. /// document.AddFooters();
  516. ///
  517. /// // Get a collection of all footers in this document.
  518. /// Footers footers = document.Footers;
  519. ///
  520. /// // The footer used for the first page of this document.
  521. /// Footer first = footers.first;
  522. ///
  523. /// // The footer used for odd pages of this document.
  524. /// Footer odd = footers.odd;
  525. ///
  526. /// // The footer used for even pages of this document.
  527. /// Footer even = footers.even;
  528. /// }
  529. /// </code>
  530. /// </example>
  531. public Footers Footers
  532. {
  533. get
  534. {
  535. return footers;
  536. }
  537. }
  538. private Footers footers;
  539. /// <summary>
  540. /// Should the Document use different Headers and Footers for odd and even pages?
  541. /// </summary>
  542. /// <example>
  543. /// <code>
  544. /// // Create a document.
  545. /// using (DocX document = DocX.Create(@"Test.docx"))
  546. /// {
  547. /// // Add header support to this document.
  548. /// document.AddHeaders();
  549. ///
  550. /// // Get a collection of all headers in this document.
  551. /// Headers headers = document.Headers;
  552. ///
  553. /// // The header used for odd pages of this document.
  554. /// Header odd = headers.odd;
  555. ///
  556. /// // The header used for even pages of this document.
  557. /// Header even = headers.even;
  558. ///
  559. /// // Force the document to use a different header for odd and even pages.
  560. /// document.DifferentOddAndEvenPages = true;
  561. ///
  562. /// // Content can be added to the Headers in the same manor that it would be added to the main document.
  563. /// Paragraph p1 = odd.InsertParagraph();
  564. /// p1.Append("This is the odd pages header.");
  565. ///
  566. /// Paragraph p2 = even.InsertParagraph();
  567. /// p2.Append("This is the even pages header.");
  568. ///
  569. /// // Save all changes to this document.
  570. /// document.Save();
  571. /// }// Release this document from memory.
  572. /// </code>
  573. /// </example>
  574. public bool DifferentOddAndEvenPages
  575. {
  576. get
  577. {
  578. XDocument settings;
  579. using (TextReader tr = new StreamReader(settingsPart.GetStream()))
  580. settings = XDocument.Load(tr);
  581. XElement evenAndOddHeaders = settings.Root.Element(w + "evenAndOddHeaders");
  582. return evenAndOddHeaders != null;
  583. }
  584. set
  585. {
  586. XDocument settings;
  587. using (TextReader tr = new StreamReader(settingsPart.GetStream()))
  588. settings = XDocument.Load(tr);
  589. XElement evenAndOddHeaders = settings.Root.Element(w + "evenAndOddHeaders");
  590. if (evenAndOddHeaders == null)
  591. {
  592. if (value)
  593. settings.Root.AddFirst(new XElement(w + "evenAndOddHeaders"));
  594. }
  595. else
  596. {
  597. if (!value)
  598. evenAndOddHeaders.Remove();
  599. }
  600. using (TextWriter tw = new StreamWriter(settingsPart.GetStream()))
  601. settings.Save(tw);
  602. }
  603. }
  604. /// <summary>
  605. /// Should the Document use an independent Header and Footer for the first page?
  606. /// </summary>
  607. /// <example>
  608. /// // Create a document.
  609. /// using (DocX document = DocX.Create(@"Test.docx"))
  610. /// {
  611. /// // Add header support to this document.
  612. /// document.AddHeaders();
  613. ///
  614. /// // The header used for the first page of this document.
  615. /// Header first = document.Headers.first;
  616. ///
  617. /// // Force the document to use a different header for first page.
  618. /// document.DifferentFirstPage = true;
  619. ///
  620. /// // Content can be added to the Headers in the same manor that it would be added to the main document.
  621. /// Paragraph p = first.InsertParagraph();
  622. /// p.Append("This is the first pages header.");
  623. ///
  624. /// // Save all changes to this document.
  625. /// document.Save();
  626. /// }// Release this document from memory.
  627. /// </example>
  628. public bool DifferentFirstPage
  629. {
  630. get
  631. {
  632. XElement body = mainDoc.Root.Element(w + "body");
  633. XElement sectPr = body.Element(w + "sectPr");
  634. if (sectPr != null)
  635. {
  636. XElement titlePg = sectPr.Element(w + "titlePg");
  637. if (titlePg != null)
  638. return true;
  639. }
  640. return false;
  641. }
  642. set
  643. {
  644. XElement body = mainDoc.Root.Element(w + "body");
  645. XElement sectPr = null;
  646. XElement titlePg = null;
  647. if (sectPr == null)
  648. body.Add(new XElement(w + "sectPr", string.Empty));
  649. sectPr = body.Element(w + "sectPr");
  650. titlePg = sectPr.Element(w + "titlePg");
  651. if (titlePg == null)
  652. {
  653. if (value)
  654. sectPr.Add(new XElement(w + "titlePg", string.Empty));
  655. }
  656. else
  657. {
  658. if (!value)
  659. titlePg.Remove();
  660. }
  661. }
  662. }
  663. private Header GetHeaderByType(string type)
  664. {
  665. return (Header)GetHeaderOrFooterByType(type, true);
  666. }
  667. private Footer GetFooterByType(string type)
  668. {
  669. return (Footer)GetHeaderOrFooterByType(type, false);
  670. }
  671. private object GetHeaderOrFooterByType(string type, bool isHeader)
  672. {
  673. // Switch which handles either case Header\Footer, this just cuts down on code duplication.
  674. string reference = "footerReference";
  675. if (isHeader)
  676. reference = "headerReference";
  677. // Get the Id of the [default, even or first] [Header or Footer]
  678. string Id =
  679. (
  680. from e in mainDoc.Descendants(XName.Get("body", DocX.w.NamespaceName)).Descendants()
  681. where (e.Name.LocalName == reference) && (e.Attribute(w + "type").Value == type)
  682. select e.Attribute(r + "id").Value
  683. ).LastOrDefault();
  684. if (Id != null)
  685. {
  686. // Get the Xml file for this Header or Footer.
  687. Uri partUri = mainPart.GetRelationship(Id).TargetUri;
  688. // Weird problem with PackaePart API.
  689. if (!partUri.OriginalString.StartsWith("/word/"))
  690. partUri = new Uri("/word/" + partUri.OriginalString, UriKind.Relative);
  691. // Get the Part and open a stream to get the Xml file.
  692. PackagePart part = package.GetPart(partUri);
  693. XDocument doc;
  694. using (TextReader tr = new StreamReader(part.GetStream()))
  695. {
  696. doc = XDocument.Load(tr);
  697. // Header and Footer extend Container.
  698. Container c;
  699. if (isHeader)
  700. c = new Header(this, doc.Element(w + "hdr"), part);
  701. else
  702. c = new Footer(this, doc.Element(w + "ftr"), part);
  703. return c;
  704. }
  705. }
  706. // If we got this far something went wrong.
  707. return null;
  708. }
  709. public List<Section> GetSections()
  710. {
  711. var allParas = Paragraphs;
  712. var parasInASection = new List<Paragraph>();
  713. var sections = new List<Section>();
  714. foreach (var para in allParas)
  715. {
  716. var sectionInPara = para.Xml.Descendants().FirstOrDefault(s => s.Name.LocalName == "sectPr");
  717. if (sectionInPara == null)
  718. {
  719. parasInASection.Add(para);
  720. }
  721. else
  722. {
  723. parasInASection.Add(para);
  724. var section = new Section(Document, sectionInPara) { SectionParagraphs = parasInASection };
  725. sections.Add(section);
  726. parasInASection = new List<Paragraph>();
  727. }
  728. }
  729. XElement body = mainDoc.Root.Element(XName.Get("body", DocX.w.NamespaceName));
  730. XElement baseSectionXml = body.Element(XName.Get("sectPr", DocX.w.NamespaceName));
  731. var baseSection = new Section(Document, baseSectionXml) { SectionParagraphs = parasInASection };
  732. sections.Add(baseSection);
  733. return sections;
  734. }
  735. // Get the word\settings.xml part
  736. internal PackagePart settingsPart;
  737. internal PackagePart endnotesPart;
  738. internal PackagePart footnotesPart;
  739. internal PackagePart stylesPart;
  740. internal PackagePart stylesWithEffectsPart;
  741. internal PackagePart numberingPart;
  742. internal PackagePart fontTablePart;
  743. #region Internal variables defined foreach DocX object
  744. // Object representation of the .docx
  745. internal Package package;
  746. // The mainDocument is loaded into a XDocument object for easy querying and editing
  747. internal XDocument mainDoc;
  748. internal XDocument settings;
  749. internal XDocument endnotes;
  750. internal XDocument footnotes;
  751. internal XDocument styles;
  752. internal XDocument stylesWithEffects;
  753. internal XDocument numbering;
  754. internal XDocument fontTable;
  755. internal XDocument header1;
  756. internal XDocument header2;
  757. internal XDocument header3;
  758. // A lookup for the Paragraphs in this document.
  759. internal Dictionary<int, Paragraph> paragraphLookup = new Dictionary<int, Paragraph>();
  760. // Every document is stored in a MemoryStream, all edits made to a document are done in memory.
  761. internal MemoryStream memoryStream;
  762. // The filename that this document was loaded from
  763. internal string filename;
  764. // The stream that this document was loaded from
  765. internal Stream stream;
  766. #endregion
  767. internal DocX(DocX document, XElement xml)
  768. : base(document, xml)
  769. {
  770. }
  771. /// <summary>
  772. /// Returns a list of Images in this document.
  773. /// </summary>
  774. /// <example>
  775. /// Get the unique Id of every Image in this document.
  776. /// <code>
  777. /// // Load a document.
  778. /// DocX document = DocX.Load(@"C:\Example\Test.docx");
  779. ///
  780. /// // Loop through each Image in this document.
  781. /// foreach (Novacode.Image i in document.Images)
  782. /// {
  783. /// // Get the unique Id which identifies this Image.
  784. /// string uniqueId = i.Id;
  785. /// }
  786. ///
  787. /// </code>
  788. /// </example>
  789. /// <seealso cref="AddImage(string)"/>
  790. /// <seealso cref="AddImage(Stream)"/>
  791. /// <seealso cref="Paragraph.Pictures"/>
  792. /// <seealso cref="Paragraph.InsertPicture"/>
  793. public List<Image> Images
  794. {
  795. get
  796. {
  797. PackageRelationshipCollection imageRelationships = mainPart.GetRelationshipsByType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/image");
  798. if (imageRelationships.Count() > 0)
  799. {
  800. return
  801. (
  802. from i in imageRelationships
  803. select new Image(this, i)
  804. ).ToList();
  805. }
  806. return new List<Image>();
  807. }
  808. }
  809. /// <summary>
  810. /// Returns a list of custom properties in this document.
  811. /// </summary>
  812. /// <example>
  813. /// Method 1: Get the name, type and value of each CustomProperty in this document.
  814. /// <code>
  815. /// // Load Example.docx
  816. /// DocX document = DocX.Load(@"C:\Example\Test.docx");
  817. ///
  818. /// /*
  819. /// * No two custom properties can have the same name,
  820. /// * so a Dictionary is the perfect data structure to store them in.
  821. /// * Each custom property can be accessed using its name.
  822. /// */
  823. /// foreach (string name in document.CustomProperties.Keys)
  824. /// {
  825. /// // Grab a custom property using its name.
  826. /// CustomProperty cp = document.CustomProperties[name];
  827. ///
  828. /// // Write this custom properties details to Console.
  829. /// Console.WriteLine(string.Format("Name: '{0}', Value: {1}", cp.Name, cp.Value));
  830. /// }
  831. ///
  832. /// Console.WriteLine("Press any key...");
  833. ///
  834. /// // Wait for the user to press a key before closing the Console.
  835. /// Console.ReadKey();
  836. /// </code>
  837. /// </example>
  838. /// <example>
  839. /// Method 2: Get the name, type and value of each CustomProperty in this document.
  840. /// <code>
  841. /// // Load Example.docx
  842. /// DocX document = DocX.Load(@"C:\Example\Test.docx");
  843. ///
  844. /// /*
  845. /// * No two custom properties can have the same name,
  846. /// * so a Dictionary is the perfect data structure to store them in.
  847. /// * The values of this Dictionary are CustomProperties.
  848. /// */
  849. /// foreach (CustomProperty cp in document.CustomProperties.Values)
  850. /// {
  851. /// // Write this custom properties details to Console.
  852. /// Console.WriteLine(string.Format("Name: '{0}', Value: {1}", cp.Name, cp.Value));
  853. /// }
  854. ///
  855. /// Console.WriteLine("Press any key...");
  856. ///
  857. /// // Wait for the user to press a key before closing the Console.
  858. /// Console.ReadKey();
  859. /// </code>
  860. /// </example>
  861. /// <seealso cref="AddCustomProperty"/>
  862. public Dictionary<string, CustomProperty> CustomProperties
  863. {
  864. get
  865. {
  866. if (package.PartExists(new Uri("/docProps/custom.xml", UriKind.Relative)))
  867. {
  868. PackagePart docProps_custom = package.GetPart(new Uri("/docProps/custom.xml", UriKind.Relative));
  869. XDocument customPropDoc;
  870. using (TextReader tr = new StreamReader(docProps_custom.GetStream(FileMode.Open, FileAccess.Read)))
  871. customPropDoc = XDocument.Load(tr, LoadOptions.PreserveWhitespace);
  872. // Get all of the custom properties in this document
  873. return
  874. (
  875. from p in customPropDoc.Descendants(XName.Get("property", customPropertiesSchema.NamespaceName))
  876. let Name = p.Attribute(XName.Get("name")).Value
  877. let Type = p.Descendants().Single().Name.LocalName
  878. let Value = p.Descendants().Single().Value
  879. select new CustomProperty(Name, Type, Value)
  880. ).ToDictionary(p => p.Name, StringComparer.CurrentCultureIgnoreCase);
  881. }
  882. return new Dictionary<string, CustomProperty>();
  883. }
  884. }
  885. ///<summary>
  886. /// Returns the list of document core properties with corresponding values.
  887. ///</summary>
  888. public Dictionary<string, string> CoreProperties
  889. {
  890. get
  891. {
  892. if (package.PartExists(new Uri("/docProps/core.xml", UriKind.Relative)))
  893. {
  894. PackagePart docProps_Core = package.GetPart(new Uri("/docProps/core.xml", UriKind.Relative));
  895. XDocument corePropDoc;
  896. using (TextReader tr = new StreamReader(docProps_Core.GetStream(FileMode.Open, FileAccess.Read)))
  897. corePropDoc = XDocument.Load(tr, LoadOptions.PreserveWhitespace);
  898. // Get all of the core properties in this document
  899. return (from docProperty in corePropDoc.Root.Elements()
  900. select
  901. new KeyValuePair<string, string>(
  902. string.Format(
  903. "{0}:{1}",
  904. corePropDoc.Root.GetPrefixOfNamespace(docProperty.Name.Namespace),
  905. docProperty.Name.LocalName),
  906. docProperty.Value)).ToDictionary(p => p.Key, v => v.Value);
  907. }
  908. return new Dictionary<string, string>();
  909. }
  910. }
  911. /// <summary>
  912. /// Get the Text of this document.
  913. /// </summary>
  914. /// <example>
  915. /// Write to Console the Text from this document.
  916. /// <code>
  917. /// // Load a document
  918. /// DocX document = DocX.Load(@"C:\Example\Test.docx");
  919. ///
  920. /// // Get the text of this document.
  921. /// string text = document.Text;
  922. ///
  923. /// // Write the text of this document to Console.
  924. /// Console.Write(text);
  925. ///
  926. /// // Wait for the user to press a key before closing the console window.
  927. /// Console.ReadKey();
  928. /// </code>
  929. /// </example>
  930. public string Text
  931. {
  932. get
  933. {
  934. return HelperFunctions.GetText(Xml);
  935. }
  936. }
  937. /// <summary>
  938. /// Get the text of each footnote from this document
  939. /// </summary>
  940. public IEnumerable<string> FootnotesText
  941. {
  942. get
  943. {
  944. foreach (XElement footnote in footnotes.Root.Elements(w + "footnote"))
  945. {
  946. yield return HelperFunctions.GetText(footnote);
  947. }
  948. }
  949. }
  950. /// <summary>
  951. /// Get the text of each endnote from this document
  952. /// </summary>
  953. public IEnumerable<string> EndnotesText
  954. {
  955. get
  956. {
  957. foreach (XElement endnote in endnotes.Root.Elements(w + "endnote"))
  958. {
  959. yield return HelperFunctions.GetText(endnote);
  960. }
  961. }
  962. }
  963. internal string GetCollectiveText(List<PackagePart> list)
  964. {
  965. string text = string.Empty;
  966. foreach (var hp in list)
  967. {
  968. using (TextReader tr = new StreamReader(hp.GetStream()))
  969. {
  970. XDocument d = XDocument.Load(tr);
  971. StringBuilder sb = new StringBuilder();
  972. // Loop through each text item in this run
  973. foreach (XElement descendant in d.Descendants())
  974. {
  975. switch (descendant.Name.LocalName)
  976. {
  977. case "tab":
  978. sb.Append("\t");
  979. break;
  980. case "br":
  981. sb.Append("\n");
  982. break;
  983. case "t":
  984. goto case "delText";
  985. case "delText":
  986. sb.Append(descendant.Value);
  987. break;
  988. default: break;
  989. }
  990. }
  991. text += "\n" + sb.ToString();
  992. }
  993. }
  994. return text;
  995. }
  996. /// <summary>
  997. /// Insert the contents of another document at the end of this document.
  998. /// </summary>
  999. /// <param name="remote_document">The document to insert at the end of this document.</param>
  1000. /// <param name="append">If true, document is inserted at the end, otherwise document is inserted at the beginning.</param>
  1001. /// <example>
  1002. /// Create a new document and insert an old document into it.
  1003. /// <code>
  1004. /// // Create a new document.
  1005. /// using (DocX newDocument = DocX.Create(@"NewDocument.docx"))
  1006. /// {
  1007. /// // Load an old document.
  1008. /// using (DocX oldDocument = DocX.Load(@"OldDocument.docx"))
  1009. /// {
  1010. /// // Insert the old document into the new document.
  1011. /// newDocument.InsertDocument(oldDocument);
  1012. ///
  1013. /// // Save the new document.
  1014. /// newDocument.Save();
  1015. /// }// Release the old document from memory.
  1016. /// }// Release the new document from memory.
  1017. /// </code>
  1018. /// <remarks>
  1019. /// 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.
  1020. /// </remarks>
  1021. /// </example>
  1022. public void InsertDocument(DocX remote_document, bool append = true)
  1023. {
  1024. // We don't want to effect the origional XDocument, so create a new one from the old one.
  1025. XDocument remote_mainDoc = new XDocument(remote_document.mainDoc);
  1026. XDocument remote_footnotes = null;
  1027. if (remote_document.footnotes != null)
  1028. remote_footnotes = new XDocument(remote_document.footnotes);
  1029. XDocument remote_endnotes = null;
  1030. if (remote_document.endnotes != null)
  1031. remote_endnotes = new XDocument(remote_document.endnotes);
  1032. // Remove all header and footer references.
  1033. remote_mainDoc.Descendants(XName.Get("headerReference", DocX.w.NamespaceName)).Remove();
  1034. remote_mainDoc.Descendants(XName.Get("footerReference", DocX.w.NamespaceName)).Remove();
  1035. // Get the body of the remote document.
  1036. XElement remote_body = remote_mainDoc.Root.Element(XName.Get("body", DocX.w.NamespaceName));
  1037. // Every file that is missing from the local document will have to be copied, every file that already exists will have to be merged.
  1038. PackagePartCollection ppc = remote_document.package.GetParts();
  1039. List<String> ignoreContentTypes = new List<string>
  1040. {
  1041. "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml",
  1042. "application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml",
  1043. "application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml",
  1044. "application/vnd.openxmlformats-package.core-properties+xml",
  1045. "application/vnd.openxmlformats-officedocument.extended-properties+xml",
  1046. "application/vnd.openxmlformats-package.relationships+xml",
  1047. };
  1048. List<String> imageContentTypes = new List<string>
  1049. {
  1050. "image/jpeg",
  1051. "image/jpg",
  1052. "image/png",
  1053. "image/bmp",
  1054. "image/gif",
  1055. "image/tiff",
  1056. "image/icon",
  1057. "image/pcx",
  1058. "image/emf",
  1059. "image/wmf"
  1060. };
  1061. // Check if each PackagePart pp exists in this document.
  1062. foreach (PackagePart remote_pp in ppc)
  1063. {
  1064. if (ignoreContentTypes.Contains(remote_pp.ContentType) || imageContentTypes.Contains(remote_pp.ContentType))
  1065. continue;
  1066. // If this external PackagePart already exits then we must merge them.
  1067. if (package.PartExists(remote_pp.Uri))
  1068. {
  1069. PackagePart local_pp = package.GetPart(remote_pp.Uri);
  1070. switch (remote_pp.ContentType)
  1071. {
  1072. case "application/vnd.openxmlformats-officedocument.custom-properties+xml":
  1073. merge_customs(remote_pp, local_pp, remote_mainDoc);
  1074. break;
  1075. // Merge footnotes (and endnotes) before merging styles, then set the remote_footnotes to the just updated footnotes
  1076. case "application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml":
  1077. merge_footnotes(remote_pp, local_pp, remote_mainDoc, remote_document, remote_footnotes);
  1078. remote_footnotes = footnotes;
  1079. break;
  1080. case "application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml":
  1081. merge_endnotes(remote_pp, local_pp, remote_mainDoc, remote_document, remote_endnotes);
  1082. remote_endnotes = endnotes;
  1083. break;
  1084. case "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml":
  1085. merge_styles(remote_pp, local_pp, remote_mainDoc, remote_document, remote_footnotes, remote_endnotes);
  1086. break;
  1087. // Merge styles after merging the footnotes, so the changes will be applied to the correct document/footnotes
  1088. case "application/vnd.ms-word.stylesWithEffects+xml":
  1089. merge_styles(remote_pp, local_pp, remote_mainDoc, remote_document, remote_footnotes, remote_endnotes);
  1090. break;
  1091. case "application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml":
  1092. merge_fonts(remote_pp, local_pp, remote_mainDoc, remote_document);
  1093. break;
  1094. case "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml":
  1095. merge_numbering(remote_pp, local_pp, remote_mainDoc, remote_document);
  1096. break;
  1097. default:
  1098. break;
  1099. }
  1100. }
  1101. // If this external PackagePart does not exits in the internal document then we can simply copy it.
  1102. else
  1103. {
  1104. var packagePart = clonePackagePart(remote_pp);
  1105. switch (remote_pp.ContentType)
  1106. {
  1107. case "application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml":
  1108. endnotesPart = packagePart;
  1109. endnotes = remote_endnotes;
  1110. break;
  1111. case "application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml":
  1112. footnotesPart = packagePart;
  1113. footnotes = remote_footnotes;
  1114. break;
  1115. case "application/vnd.openxmlformats-officedocument.custom-properties+xml":
  1116. break;
  1117. case "application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml":
  1118. stylesPart = packagePart;
  1119. using (TextReader tr = new StreamReader(stylesPart.GetStream()))
  1120. styles = XDocument.Load(tr);
  1121. break;
  1122. case "application/vnd.ms-word.stylesWithEffects+xml":
  1123. stylesWithEffectsPart = packagePart;
  1124. using (TextReader tr = new StreamReader(stylesWithEffectsPart.GetStream()))
  1125. stylesWithEffects = XDocument.Load(tr);
  1126. break;
  1127. case "application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml":
  1128. fontTablePart = packagePart;
  1129. using (TextReader tr = new StreamReader(fontTablePart.GetStream()))
  1130. fontTable = XDocument.Load(tr);
  1131. break;
  1132. case "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml":
  1133. numberingPart = packagePart;
  1134. using (TextReader tr = new StreamReader(numberingPart.GetStream()))
  1135. numbering = XDocument.Load(tr);
  1136. break;
  1137. }
  1138. clonePackageRelationship(remote_document, remote_pp, remote_mainDoc);
  1139. }
  1140. }
  1141. foreach (var hyperlink_rel in remote_document.mainPart.GetRelationshipsByType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"))
  1142. {
  1143. var old_rel_Id = hyperlink_rel.Id;
  1144. var new_rel_Id = mainPart.CreateRelationship(hyperlink_rel.TargetUri, hyperlink_rel.TargetMode, hyperlink_rel.RelationshipType).Id;
  1145. var hyperlink_refs = remote_mainDoc.Descendants(XName.Get("hyperlink", DocX.w.NamespaceName));
  1146. foreach (var hyperlink_ref in hyperlink_refs)
  1147. {
  1148. XAttribute a0 = hyperlink_ref.Attribute(XName.Get("id", DocX.r.NamespaceName));
  1149. if (a0 != null && a0.Value == old_rel_Id)
  1150. {
  1151. a0.SetValue(new_rel_Id);
  1152. }
  1153. }
  1154. }
  1155. ////ole object links
  1156. foreach (var oleObject_rel in remote_document.mainPart.GetRelationshipsByType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject"))
  1157. {
  1158. var old_rel_Id = oleObject_rel.Id;
  1159. var new_rel_Id = mainPart.CreateRelationship(oleObject_rel.TargetUri, oleObject_rel.TargetMode, oleObject_rel.RelationshipType).Id;
  1160. var oleObject_refs = remote_mainDoc.Descendants(XName.Get("OLEObject", "urn:schemas-microsoft-com:office:office"));
  1161. foreach (var oleObject_ref in oleObject_refs)
  1162. {
  1163. XAttribute a0 = oleObject_ref.Attribute(XName.Get("id", DocX.r.NamespaceName));
  1164. if (a0 != null && a0.Value == old_rel_Id)
  1165. {
  1166. a0.SetValue(new_rel_Id);
  1167. }
  1168. }
  1169. }
  1170. foreach (PackagePart remote_pp in ppc)
  1171. {
  1172. if (imageContentTypes.Contains(remote_pp.ContentType))
  1173. {
  1174. merge_images(remote_pp, remote_document, remote_mainDoc, remote_pp.ContentType);
  1175. }
  1176. }
  1177. int id = 0;
  1178. var local_docPrs = mainDoc.Root.Descendants(XName.Get("docPr", DocX.wp.NamespaceName));
  1179. foreach (var local_docPr in local_docPrs)
  1180. {
  1181. XAttribute a_id = local_docPr.Attribute(XName.Get("id"));
  1182. int a_id_value;
  1183. if (a_id != null && int.TryParse(a_id.Value, out a_id_value))
  1184. if (a_id_value > id)
  1185. id = a_id_value;
  1186. }
  1187. id++;
  1188. // docPr must be sequential
  1189. var docPrs = remote_body.Descendants(XName.Get("docPr", DocX.wp.NamespaceName));
  1190. foreach (var docPr in docPrs)
  1191. {
  1192. docPr.SetAttributeValue(XName.Get("id"), id);
  1193. id++;
  1194. }
  1195. // Add the remote documents contents to this document.
  1196. XElement local_body = mainDoc.Root.Element(XName.Get("body", DocX.w.NamespaceName));
  1197. if (append)
  1198. local_body.Add(remote_body.Elements());
  1199. else
  1200. local_body.AddFirst(remote_body.Elements());
  1201. // Copy any missing root attributes to the local document.
  1202. foreach (XAttribute a in remote_mainDoc.Root.Attributes())
  1203. {
  1204. if (mainDoc.Root.Attribute(a.Name) == null)
  1205. {
  1206. mainDoc.Root.SetAttributeValue(a.Name, a.Value);
  1207. }
  1208. }
  1209. }
  1210. private void merge_images(PackagePart remote_pp, DocX remote_document, XDocument remote_mainDoc, String contentType)
  1211. {
  1212. // Before doing any other work, check to see if this image is actually referenced in the document.
  1213. // In my testing I have found cases of Images inside documents that are not referenced
  1214. var remote_rel = remote_document.mainPart.GetRelationships().Where(r => r.TargetUri.OriginalString.Equals(remote_pp.Uri.OriginalString.Replace("/word/", ""))).FirstOrDefault();
  1215. if (remote_rel == null) {
  1216. remote_rel = remote_document.mainPart.GetRelationships().Where(r => r.TargetUri.OriginalString.Equals(remote_pp.Uri.OriginalString)).FirstOrDefault();
  1217. if (remote_rel == null)
  1218. return;
  1219. }
  1220. String remote_Id = remote_rel.Id;
  1221. String remote_hash = ComputeMD5HashString(remote_pp.GetStream());
  1222. var image_parts = package.GetParts().Where(pp => pp.ContentType.Equals(contentType));
  1223. bool found = false;
  1224. foreach (var part in image_parts)
  1225. {
  1226. String local_hash = ComputeMD5HashString(part.GetStream());
  1227. if (local_hash.Equals(remote_hash))
  1228. {
  1229. // This image already exists in this document.
  1230. found = true;
  1231. var local_rel = mainPart.GetRelationships().Where(r => r.TargetUri.OriginalString.Equals(part.Uri.OriginalString.Replace("/word/", ""))).FirstOrDefault();
  1232. if (local_rel == null)
  1233. {
  1234. local_rel = mainPart.GetRelationships().Where(r => r.TargetUri.OriginalString.Equals(part.Uri.OriginalString)).FirstOrDefault();
  1235. }
  1236. if (local_rel != null)
  1237. {
  1238. String new_Id = local_rel.Id;
  1239. // Replace all instances of remote_Id in the local document with local_Id
  1240. var elems = remote_mainDoc.Descendants(XName.Get("blip", DocX.a.NamespaceName));
  1241. foreach (var elem in elems)
  1242. {
  1243. XAttribute embed = elem.Attribute(XName.Get("embed", DocX.r.NamespaceName));
  1244. if (embed != null && embed.Value == remote_Id)
  1245. {
  1246. embed.SetValue(new_Id);
  1247. }
  1248. }
  1249. // Replace all instances of remote_Id in the local document with local_Id (for shapes as well)
  1250. var v_elems = remote_mainDoc.Descendants(XName.Get("imagedata", DocX.v.NamespaceName));
  1251. foreach (var elem in v_elems)
  1252. {
  1253. XAttribute id = elem.Attribute(XName.Get("id", DocX.r.NamespaceName));
  1254. if (id != null && id.Value == remote_Id)
  1255. {
  1256. id.SetValue(new_Id);
  1257. }
  1258. }
  1259. }
  1260. break;
  1261. }
  1262. }
  1263. // This image does not exist in this document.
  1264. if (!found)
  1265. {
  1266. String new_uri = remote_pp.Uri.OriginalString;
  1267. new_uri = new_uri.Remove(new_uri.LastIndexOf("/"));
  1268. //new_uri = new_uri.Replace("word/", "");
  1269. new_uri += "/" + Guid.NewGuid().ToString() + contentType.Replace("image/", ".");
  1270. if (!new_uri.StartsWith("/"))
  1271. new_uri = "/" + new_uri;
  1272. PackagePart new_pp = package.CreatePart(new Uri(new_uri, UriKind.Relative), remote_pp.ContentType, CompressionOption.Normal);
  1273. using (Stream s_read = remote_pp.GetStream())
  1274. {
  1275. using (Stream s_write = new_pp.GetStream(FileMode.Create))
  1276. {
  1277. byte[] buffer = new byte[32768];
  1278. int read;
  1279. while ((read = s_read.Read(buffer, 0, buffer.Length)) > 0)
  1280. {
  1281. s_write.Write(buffer, 0, read);
  1282. }
  1283. }
  1284. }
  1285. PackageRelationship pr = mainPart.CreateRelationship(new Uri(new_uri, UriKind.Relative), TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image");
  1286. String new_Id = pr.Id;
  1287. //Check if the remote relationship id is a default rId from Word
  1288. Match defRelId = Regex.Match(remote_Id, @"rId\d+", RegexOptions.IgnoreCase);
  1289. // Replace all instances of remote_Id in the local document with local_Id
  1290. var elems = remote_mainDoc.Descendants(XName.Get("blip", DocX.a.NamespaceName));
  1291. foreach (var elem in elems)
  1292. {
  1293. XAttribute embed = elem.Attribute(XName.Get("embed", DocX.r.NamespaceName));
  1294. if (embed != null && embed.Value == remote_Id)
  1295. {
  1296. embed.SetValue(new_Id);
  1297. }
  1298. }
  1299. if (!defRelId.Success)
  1300. {
  1301. // Replace all instances of remote_Id in the local document with local_Id
  1302. var elems_local = mainDoc.Descendants(XName.Get("blip", DocX.a.NamespaceName));
  1303. foreach (var elem in elems_local)
  1304. {
  1305. XAttribute embed = elem.Attribute(XName.Get("embed", DocX.r.NamespaceName));
  1306. if (embed != null && embed.Value == remote_Id)
  1307. {
  1308. embed.SetValue(new_Id);
  1309. }
  1310. }
  1311. // Replace all instances of remote_Id in the local document with local_Id
  1312. var v_elems_local = mainDoc.Descendants(XName.Get("imagedata", DocX.v.NamespaceName));
  1313. foreach (var elem in v_elems_local)
  1314. {
  1315. XAttribute id = elem.Attribute(XName.Get("id", DocX.r.NamespaceName));
  1316. if (id != null && id.Value == remote_Id)
  1317. {
  1318. id.SetValue(new_Id);
  1319. }
  1320. }
  1321. }
  1322. // Replace all instances of remote_Id in the local document with local_Id (for shapes as well)
  1323. var v_elems = remote_mainDoc.Descendants(XName.Get("imagedata", DocX.v.NamespaceName));
  1324. foreach (var elem in v_elems)
  1325. {
  1326. XAttribute id = elem.Attribute(XName.Get("id", DocX.r.NamespaceName));
  1327. if (id != null && id.Value == remote_Id)
  1328. {
  1329. id.SetValue(new_Id);
  1330. }
  1331. }
  1332. }
  1333. }
  1334. private string ComputeMD5HashString(Stream stream)
  1335. {
  1336. MD5 md5 = MD5.Create();
  1337. byte[] hash = md5.ComputeHash(stream);
  1338. StringBuilder sb = new StringBuilder();
  1339. for (int i = 0; i < hash.Length; i++)
  1340. sb.Append(hash[i].ToString("X2"));
  1341. return sb.ToString();
  1342. }
  1343. private void merge_endnotes(PackagePart remote_pp, PackagePart local_pp, XDocument remote_mainDoc, DocX remote, XDocument remote_endnotes)
  1344. {
  1345. IEnumerable<int> ids =
  1346. (
  1347. from d in endnotes.Root.Descendants()
  1348. where d.Name.LocalName == "endnote"
  1349. select int.Parse(d.Attribute(XName.Get("id", DocX.w.NamespaceName)).Value)
  1350. );
  1351. int max_id = ids.Max() + 1;
  1352. var endnoteReferences = remote_mainDoc.Descendants(XName.Get("endnoteReference", DocX.w.NamespaceName));
  1353. foreach (var endnote in remote_endnotes.Root.Elements().OrderBy(fr => fr.Attribute(XName.Get("id", DocX.r.NamespaceName))).Reverse())
  1354. {
  1355. XAttribute id = endnote.Attribute(XName.Get("id", DocX.w.NamespaceName));
  1356. int i;
  1357. if (id != null && int.TryParse(id.Value, out i))
  1358. {
  1359. if (i > 0)
  1360. {
  1361. foreach (var endnoteRef in endnoteReferences)
  1362. {
  1363. XAttribute a = endnoteRef.Attribute(XName.Get("id", DocX.w.NamespaceName));
  1364. if (a != null && int.Parse(a.Value).Equals(i))
  1365. {
  1366. a.SetValue(max_id);
  1367. }
  1368. }
  1369. // We care about copying this footnote.
  1370. endnote.SetAttributeValue(XName.Get("id", DocX.w.NamespaceName), max_id);
  1371. endnotes.Root.Add(endnote);
  1372. max_id++;
  1373. }
  1374. }
  1375. }
  1376. }
  1377. private void merge_footnotes(PackagePart remote_pp, PackagePart local_pp, XDocument remote_mainDoc, DocX remote, XDocument remote_footnotes)
  1378. {
  1379. IEnumerable<int> ids =
  1380. (
  1381. from d in footnotes.Root.Descendants()
  1382. where d.Name.LocalName == "footnote"
  1383. select int.Parse(d.Attribute(XName.Get("id", DocX.w.NamespaceName)).Value)
  1384. );
  1385. int max_id = ids.Max() + 1;
  1386. var footnoteReferences = remote_mainDoc.Descendants(XName.Get("footnoteReference", DocX.w.NamespaceName));
  1387. foreach (var footnote in remote_footnotes.Root.Elements().OrderBy(fr => fr.Attribute(XName.Get("id", DocX.r.NamespaceName))).Reverse())
  1388. {
  1389. XAttribute id = footnote.Attribute(XName.Get("id", DocX.w.NamespaceName));
  1390. int i;
  1391. if (id != null && int.TryParse(id.Value, out i))
  1392. {
  1393. if (i > 0)
  1394. {
  1395. foreach (var footnoteRef in footnoteReferences)
  1396. {
  1397. XAttribute a = footnoteRef.Attribute(XName.Get("id", DocX.w.NamespaceName));
  1398. if (a != null && int.Parse(a.Value).Equals(i))
  1399. {
  1400. a.SetValue(max_id);
  1401. }
  1402. }
  1403. // We care about copying this footnote.
  1404. footnote.SetAttributeValue(XName.Get("id", DocX.w.NamespaceName), max_id);
  1405. footnotes.Root.Add(footnote);
  1406. max_id++;
  1407. }
  1408. }
  1409. }
  1410. }
  1411. private void merge_customs(PackagePart remote_pp, PackagePart local_pp, XDocument remote_mainDoc)
  1412. {
  1413. // Get the remote documents custom.xml file.
  1414. XDocument remote_custom_document;
  1415. using (TextReader tr = new StreamReader(remote_pp.GetStream()))
  1416. remote_custom_document = XDocument.Load(tr);
  1417. // Get the local documents custom.xml file.
  1418. XDocument local_custom_document;
  1419. using (TextReader tr = new StreamReader(local_pp.GetStream()))
  1420. local_custom_document = XDocument.Load(tr);
  1421. IEnumerable<int> pids =
  1422. (
  1423. from d in remote_custom_document.Root.Descendants()
  1424. where d.Name.LocalName == "property"
  1425. select int.Parse(d.Attribute(XName.Get("pid")).Value)
  1426. );
  1427. int pid = pids.Max() + 1;
  1428. foreach (XElement remote_property in remote_custom_document.Root.Elements())
  1429. {
  1430. bool found = false;
  1431. foreach (XElement local_property in local_custom_document.Root.Elements())
  1432. {
  1433. XAttribute remote_property_name = remote_property.Attribute(XName.Get("name"));
  1434. XAttribute local_property_name = local_property.Attribute(XName.Get("name"));
  1435. if (remote_property != null && local_property_name != null && remote_property_name.Value.Equals(local_property_name.Value))
  1436. found = true;
  1437. }
  1438. if (!found)
  1439. {
  1440. remote_property.SetAttributeValue(XName.Get("pid"), pid);
  1441. local_custom_document.Root.Add(remote_property);
  1442. pid++;
  1443. }
  1444. }
  1445. // Save the modified local custom styles.xml file.
  1446. using (TextWriter tw = new StreamWriter(local_pp.GetStream(FileMode.Create, FileAccess.Write)))
  1447. local_custom_document.Save(tw, SaveOptions.None);
  1448. }
  1449. private void merge_numbering(PackagePart remote_pp, PackagePart local_pp, XDocument remote_mainDoc, DocX remote)
  1450. {
  1451. // Add each remote numbering to this document.
  1452. IEnumerable<XElement> remote_abstractNums = remote.numbering.Root.Elements(XName.Get("abstractNum", DocX.w.NamespaceName));
  1453. int guidd = 0;
  1454. foreach (var an in remote_abstractNums)
  1455. {
  1456. XAttribute a = an.Attribute(XName.Get("abstractNumId", DocX.w.NamespaceName));
  1457. if (a != null)
  1458. {
  1459. int i;
  1460. if (int.TryParse(a.Value, out i))
  1461. {
  1462. if (i > guidd)
  1463. guidd = i;
  1464. }
  1465. }
  1466. }
  1467. guidd++;
  1468. IEnumerable<XElement> remote_nums = remote.numbering.Root.Elements(XName.Get("num", DocX.w.NamespaceName));
  1469. int guidd2 = 0;
  1470. foreach (var an in remote_nums)
  1471. {
  1472. XAttribute a = an.Attribute(XName.Get("numId", DocX.w.NamespaceName));
  1473. if (a != null)
  1474. {
  1475. int i;
  1476. if (int.TryParse(a.Value, out i))
  1477. {
  1478. if (i > guidd2)
  1479. guidd2 = i;
  1480. }
  1481. }
  1482. }
  1483. guidd2++;
  1484. foreach (XElement remote_abstractNum in remote_abstractNums)
  1485. {
  1486. XAttribute abstractNumId = remote_abstractNum.Attribute(XName.Get("abstractNumId", DocX.w.NamespaceName));
  1487. if (abstractNumId != null)
  1488. {
  1489. String abstractNumIdValue = abstractNumId.Value;
  1490. abstractNumId.SetValue(guidd);
  1491. foreach (XElement remote_num in remote_nums)
  1492. {
  1493. var numIds = remote_mainDoc.Descendants(XName.Get("numId", DocX.w.NamespaceName));
  1494. foreach (var numId in numIds)
  1495. {
  1496. XAttribute attr = numId.Attribute(XName.Get("val", DocX.w.NamespaceName));
  1497. if (attr != null && attr.Value.Equals(remote_num.Attribute(XName.Get("numId", DocX.w.NamespaceName)).Value))
  1498. {
  1499. attr.SetValue(guidd2);
  1500. }
  1501. }
  1502. remote_num.SetAttributeValue(XName.Get("numId", DocX.w.NamespaceName), guidd2);
  1503. XElement e = remote_num.Element(XName.Get("abstractNumId", DocX.w.NamespaceName));
  1504. if (e != null)
  1505. {
  1506. XAttribute a2 = e.Attribute(XName.Get("val", DocX.w.NamespaceName));
  1507. if (a2 != null && a2.Value.Equals(abstractNumIdValue))
  1508. a2.SetValue(guidd);
  1509. }
  1510. guidd2++;
  1511. }
  1512. }
  1513. guidd++;
  1514. }
  1515. // Checking whether there were more than 0 elements, helped me get rid of exceptions thrown while using InsertDocument
  1516. if (numbering.Root.Elements(XName.Get("abstractNum", DocX.w.NamespaceName)).Count() > 0)
  1517. numbering.Root.Elements(XName.Get("abstractNum", DocX.w.NamespaceName)).Last().AddAfterSelf(remote_abstractNums);
  1518. if (numbering.Root.Elements(XName.Get("num", DocX.w.NamespaceName)).Count() > 0)
  1519. numbering.Root.Elements(XName.Get("num", DocX.w.NamespaceName)).Last().AddAfterSelf(remote_nums);
  1520. }
  1521. private void merge_fonts(PackagePart remote_pp, PackagePart local_pp, XDocument remote_mainDoc, DocX remote)
  1522. {
  1523. // Add each remote font to this document.
  1524. IEnumerable<XElement> remote_fonts = remote.fontTable.Root.Elements(XName.Get("font", DocX.w.NamespaceName));
  1525. IEnumerable<XElement> local_fonts = fontTable.Root.Elements(XName.Get("font", DocX.w.NamespaceName));
  1526. foreach (XElement remote_font in remote_fonts)
  1527. {
  1528. bool flag_addFont = true;
  1529. foreach (XElement local_font in local_fonts)
  1530. {
  1531. if (local_font.Attribute(XName.Get("name", DocX.w.NamespaceName)).Value == remote_font.Attribute(XName.Get("name", DocX.w.NamespaceName)).Value)
  1532. {
  1533. flag_addFont = false;
  1534. break;
  1535. }
  1536. }
  1537. if (flag_addFont)
  1538. {
  1539. fontTable.Root.Add(remote_font);
  1540. }
  1541. }
  1542. }
  1543. private void merge_styles(PackagePart remote_pp, PackagePart local_pp, XDocument remote_mainDoc, DocX remote, XDocument remote_footnotes, XDocument remote_endnotes)
  1544. {
  1545. Dictionary<String, String> local_styles = new Dictionary<string, string>();
  1546. foreach (XElement local_style in styles.Root.Elements(XName.Get("style", DocX.w.NamespaceName)))
  1547. {
  1548. XElement temp = new XElement(local_style);
  1549. XAttribute styleId = temp.Attribute(XName.Get("styleId", DocX.w.NamespaceName));
  1550. String value = styleId.Value;
  1551. styleId.Remove();
  1552. String key = Regex.Replace(temp.ToString(), @"\s+", "");
  1553. if (!local_styles.ContainsKey(key)) local_styles.Add(key, value);
  1554. }
  1555. // Add each remote style to this document.
  1556. IEnumerable<XElement> remote_styles = remote.styles.Root.Elements(XName.Get("style", DocX.w.NamespaceName));
  1557. foreach (XElement remote_style in remote_styles)
  1558. {
  1559. XElement temp = new XElement(remote_style);
  1560. XAttribute styleId = temp.Attribute(XName.Get("styleId", DocX.w.NamespaceName));
  1561. String value = styleId.Value;
  1562. styleId.Remove();
  1563. String key = Regex.Replace(temp.ToString(), @"\s+", "");
  1564. String guuid;
  1565. // Check to see if the local document already contains the remote style.
  1566. if (local_styles.ContainsKey(key))
  1567. {
  1568. String local_value;
  1569. local_styles.TryGetValue(key, out local_value);
  1570. // If the styleIds are the same then nothing needs to be done.
  1571. if (local_value == value)
  1572. continue;
  1573. // All we need to do is update the styleId.
  1574. else
  1575. {
  1576. guuid = local_value;
  1577. }
  1578. }
  1579. else
  1580. {
  1581. guuid = Guid.NewGuid().ToString();
  1582. // Set the styleId in the remote_style to this new Guid
  1583. // [Fixed the issue that my document referred to a new Guid while my styles still had the old value ("Titel")]
  1584. remote_style.SetAttributeValue(XName.Get("styleId", DocX.w.NamespaceName), guuid);
  1585. }
  1586. foreach (XElement e in remote_mainDoc.Root.Descendants(XName.Get("pStyle", DocX.w.NamespaceName)))
  1587. {
  1588. XAttribute e_styleId = e.Attribute(XName.Get("val", DocX.w.NamespaceName));
  1589. if (e_styleId != null && e_styleId.Value.Equals(styleId.Value))
  1590. {
  1591. e_styleId.SetValue(guuid);
  1592. }
  1593. }
  1594. foreach (XElement e in remote_mainDoc.Root.Descendants(XName.Get("rStyle", DocX.w.NamespaceName)))
  1595. {
  1596. XAttribute e_styleId = e.Attribute(XName.Get("val", DocX.w.NamespaceName));
  1597. if (e_styleId != null && e_styleId.Value.Equals(styleId.Value))
  1598. {
  1599. e_styleId.SetValue(guuid);
  1600. }
  1601. }
  1602. foreach (XElement e in remote_mainDoc.Root.Descendants(XName.Get("tblStyle", DocX.w.NamespaceName)))
  1603. {
  1604. XAttribute e_styleId = e.Attribute(XName.Get("val", DocX.w.NamespaceName));
  1605. if (e_styleId != null && e_styleId.Value.Equals(styleId.Value))
  1606. {
  1607. e_styleId.SetValue(guuid);
  1608. }
  1609. }
  1610. if (remote_endnotes != null)
  1611. {
  1612. foreach (XElement e in remote_endnotes.Root.Descendants(XName.Get("rStyle", DocX.w.NamespaceName)))
  1613. {
  1614. XAttribute e_styleId = e.Attribute(XName.Get("val", DocX.w.NamespaceName));
  1615. if (e_styleId != null && e_styleId.Value.Equals(styleId.Value))
  1616. {
  1617. e_styleId.SetValue(guuid);
  1618. }
  1619. }
  1620. foreach (XElement e in remote_endnotes.Root.Descendants(XName.Get("pStyle", DocX.w.NamespaceName)))
  1621. {
  1622. XAttribute e_styleId = e.Attribute(XName.Get("val", DocX.w.NamespaceName));
  1623. if (e_styleId != null && e_styleId.Value.Equals(styleId.Value))
  1624. {
  1625. e_styleId.SetValue(guuid);
  1626. }
  1627. }
  1628. }
  1629. if (remote_footnotes != null)
  1630. {
  1631. foreach (XElement e in remote_footnotes.Root.Descendants(XName.Get("rStyle", DocX.w.NamespaceName)))
  1632. {
  1633. XAttribute e_styleId = e.Attribute(XName.Get("val", DocX.w.NamespaceName));
  1634. if (e_styleId != null && e_styleId.Value.Equals(styleId.Value))
  1635. {
  1636. e_styleId.SetValue(guuid);
  1637. }
  1638. }
  1639. foreach (XElement e in remote_footnotes.Root.Descendants(XName.Get("pStyle", DocX.w.NamespaceName)))
  1640. {
  1641. XAttribute e_styleId = e.Attribute(XName.Get("val", DocX.w.NamespaceName));
  1642. if (e_styleId != null && e_styleId.Value.Equals(styleId.Value))
  1643. {
  1644. e_styleId.SetValue(guuid);
  1645. }
  1646. }
  1647. }
  1648. // Make sure they don't clash by using a uuid.
  1649. styleId.SetValue(guuid);
  1650. styles.Root.Add(remote_style);
  1651. }
  1652. }
  1653. protected void clonePackageRelationship(DocX remote_document, PackagePart pp, XDocument remote_mainDoc)
  1654. {
  1655. string url = pp.Uri.OriginalString.Replace("/", "");
  1656. var remote_rels = remote_document.mainPart.GetRelationships();
  1657. foreach (var remote_rel in remote_rels)
  1658. {
  1659. if (url.Equals("word" + remote_rel.TargetUri.OriginalString.Replace("/", "")))
  1660. {
  1661. String remote_Id = remote_rel.Id;
  1662. String local_Id = mainPart.CreateRelationship(remote_rel.TargetUri, remote_rel.TargetMode, remote_rel.RelationshipType).Id;
  1663. // Replace all instances of remote_Id in the local document with local_Id
  1664. var elems = remote_mainDoc.Descendants(XName.Get("blip", DocX.a.NamespaceName));
  1665. foreach (var elem in elems)
  1666. {
  1667. XAttribute embed = elem.Attribute(XName.Get("embed", DocX.r.NamespaceName));
  1668. if (embed != null && embed.Value == remote_Id)
  1669. {
  1670. embed.SetValue(local_Id);
  1671. }
  1672. }
  1673. // Replace all instances of remote_Id in the local document with local_Id (for shapes as well)
  1674. var v_elems = remote_mainDoc.Descendants(XName.Get("imagedata", DocX.v.NamespaceName));
  1675. foreach (var elem in v_elems)
  1676. {
  1677. XAttribute id = elem.Attribute(XName.Get("id", DocX.r.NamespaceName));
  1678. if (id != null && id.Value == remote_Id)
  1679. {
  1680. id.SetValue(local_Id);
  1681. }
  1682. }
  1683. break;
  1684. }
  1685. }
  1686. }
  1687. protected PackagePart clonePackagePart(PackagePart pp)
  1688. {
  1689. PackagePart new_pp = package.CreatePart(pp.Uri, pp.ContentType, CompressionOption.Normal);
  1690. using (Stream s_read = pp.GetStream())
  1691. {
  1692. using (Stream s_write = new_pp.GetStream(FileMode.Create))
  1693. {
  1694. byte[] buffer = new byte[32768];
  1695. int read;
  1696. while ((read = s_read.Read(buffer, 0, buffer.Length)) > 0)
  1697. {
  1698. s_write.Write(buffer, 0, read);
  1699. }
  1700. }
  1701. }
  1702. return new_pp;
  1703. }
  1704. protected string GetMD5HashFromStream(Stream stream)
  1705. {
  1706. MD5 md5 = new MD5CryptoServiceProvider();
  1707. byte[] retVal = md5.ComputeHash(stream);
  1708. StringBuilder sb = new StringBuilder();
  1709. for (int i = 0; i < retVal.Length; i++)
  1710. {
  1711. sb.Append(retVal[i].ToString("x2"));
  1712. }
  1713. return sb.ToString();
  1714. }
  1715. /// <summary>
  1716. /// Insert a new Table at the end of this document.
  1717. /// </summary>
  1718. /// <param name="columnCount">The number of columns to create.</param>
  1719. /// <param name="rowCount">The number of rows to create.</param>
  1720. /// <returns>A new Table.</returns>
  1721. /// <example>
  1722. /// Insert a new Table with 2 columns and 3 rows, at the end of a document.
  1723. /// <code>
  1724. /// // Create a document.
  1725. /// using (DocX document = DocX.Create(@"C:\Example\Test.docx"))
  1726. /// {
  1727. /// // Create a new Table with 2 columns and 3 rows.
  1728. /// Table newTable = document.InsertTable(2, 3);
  1729. ///
  1730. /// // Set the design of this Table.
  1731. /// newTable.Design = TableDesign.LightShadingAccent2;
  1732. ///
  1733. /// // Set the column names.
  1734. /// newTable.Rows[0].Cells[0].Paragraph.InsertText("Ice Cream", false);
  1735. /// newTable.Rows[0].Cells[1].Paragraph.InsertText("Price", false);
  1736. ///
  1737. /// // Fill row 1
  1738. /// newTable.Rows[1].Cells[0].Paragraph.InsertText("Chocolate", false);
  1739. /// newTable.Rows[1].Cells[1].Paragraph.InsertText("€3:50", false);
  1740. ///
  1741. /// // Fill row 2
  1742. /// newTable.Rows[2].Cells[0].Paragraph.InsertText("Vanilla", false);
  1743. /// newTable.Rows[2].Cells[1].Paragraph.InsertText("€3:00", false);
  1744. ///
  1745. /// // Save all changes made to document b.
  1746. /// document.Save();
  1747. /// }// Release this document from memory.
  1748. /// </code>
  1749. /// </example>
  1750. public new Table InsertTable(int rowCount, int columnCount)
  1751. {
  1752. if (rowCount < 1 || columnCount < 1)
  1753. throw new ArgumentOutOfRangeException("Row and Column count must be greater than zero.");
  1754. Table t = base.InsertTable(rowCount, columnCount);
  1755. t.mainPart = mainPart;
  1756. return t;
  1757. }
  1758. public Table AddTable(int rowCount, int columnCount)
  1759. {
  1760. if (rowCount < 1 || columnCount < 1)
  1761. throw new ArgumentOutOfRangeException("Row and Column count must be greater than zero.");
  1762. Table t = new Table(this, HelperFunctions.CreateTable(rowCount, columnCount));
  1763. t.mainPart = mainPart;
  1764. return t;
  1765. }
  1766. /// <summary>
  1767. /// Create a new list with a list item.
  1768. /// </summary>
  1769. /// <param name="listText">The text of the first element in the created list.</param>
  1770. /// <param name="level">The indentation level of the element in the list.</param>
  1771. /// <param name="listType">The type of list to be created: Bulleted or Numbered.</param>
  1772. /// <param name="startNumber">The number start number for the list. </param>
  1773. /// <param name="trackChanges">Enable change tracking</param>
  1774. /// <param name="continueNumbering">Set to true if you want to continue numbering from the previous numbered list</param>
  1775. /// <returns>
  1776. /// The created List. Call AddListItem(...) to add more elements to the list.
  1777. /// Write the list to the Document with InsertList(...) once the list has all the desired
  1778. /// elements, otherwise the list will not be included in the working Document.
  1779. /// </returns>
  1780. public List AddList(string listText = null, int level = 0, ListItemType listType = ListItemType.Numbered, int? startNumber = null, bool trackChanges = false, bool continueNumbering = false)
  1781. {
  1782. return AddListItem(new List(this, null), listText, level, listType, startNumber, trackChanges, continueNumbering);
  1783. }
  1784. /// <summary>
  1785. /// Add a list item to an already existing list.
  1786. /// </summary>
  1787. /// <param name="list">The list to add the new list item to.</param>
  1788. /// <param name="listText">The run text that should be in the new list item.</param>
  1789. /// <param name="level">The indentation level of the new list element.</param>
  1790. /// <param name="startNumber">The number start number for the list. </param>
  1791. /// <param name="trackChanges">Enable change tracking</param>
  1792. /// <param name="listType">Numbered or Bulleted list type. </param>
  1793. /// /// <param name="continueNumbering">Set to true if you want to continue numbering from the previous numbered list</param>
  1794. /// <returns>
  1795. /// The created List. Call AddListItem(...) to add more elements to the list.
  1796. /// Write the list to the Document with InsertList(...) once the list has all the desired
  1797. /// elements, otherwise the list will not be included in the working Document.
  1798. /// </returns>
  1799. public List AddListItem(List list, string listText, int level = 0, ListItemType listType = ListItemType.Numbered, int? startNumber = null, bool trackChanges = false, bool continueNumbering = false)
  1800. {
  1801. if (startNumber.HasValue && continueNumbering) throw new InvalidOperationException("Cannot specify a start number and at the same time continue numbering from another list");
  1802. var listToReturn = HelperFunctions.CreateItemInList(list, listText, level, listType, startNumber, trackChanges, continueNumbering);
  1803. var lastItem = listToReturn.Items.LastOrDefault();
  1804. if (lastItem != null)
  1805. {
  1806. lastItem.PackagePart = mainPart;
  1807. }
  1808. return listToReturn;
  1809. }
  1810. /// <summary>
  1811. /// Insert list into the document.
  1812. /// </summary>
  1813. /// <param name="list">The list to insert into the document.</param>
  1814. /// <returns>The list that was inserted into the document.</returns>
  1815. public new List InsertList(List list)
  1816. {
  1817. base.InsertList(list);
  1818. return list;
  1819. }
  1820. public new List InsertList(List list, System.Drawing.FontFamily fontFamily, double fontSize)
  1821. {
  1822. base.InsertList(list, fontFamily, fontSize);
  1823. return list;
  1824. }
  1825. public new List InsertList(List list, double fontSize)
  1826. {
  1827. base.InsertList(list, fontSize);
  1828. return list;
  1829. }
  1830. /// <summary>
  1831. /// Insert a list at an index location in the document.
  1832. /// </summary>
  1833. /// <param name="index">Index in document to insert the list.</param>
  1834. /// <param name="list">The list that was inserted into the document.</param>
  1835. /// <returns></returns>
  1836. public new List InsertList(int index, List list)
  1837. {
  1838. base.InsertList(index, list);
  1839. return list;
  1840. }
  1841. internal XDocument AddStylesForList()
  1842. {
  1843. var wordStylesUri = new Uri("/word/styles.xml", UriKind.Relative);
  1844. // If the internal document contains no /word/styles.xml create one.
  1845. if (!package.PartExists(wordStylesUri))
  1846. HelperFunctions.AddDefaultStylesXml(package);
  1847. // Load the styles.xml into memory.
  1848. XDocument wordStyles;
  1849. using (TextReader tr = new StreamReader(package.GetPart(wordStylesUri).GetStream()))
  1850. wordStyles = XDocument.Load(tr);
  1851. bool listStyleExists =
  1852. (
  1853. from s in wordStyles.Element(w + "styles").Elements()
  1854. let styleId = s.Attribute(XName.Get("styleId", w.NamespaceName))
  1855. where (styleId != null && styleId.Value == "ListParagraph")
  1856. select s
  1857. ).Any();
  1858. if (!listStyleExists)
  1859. {
  1860. var style = new XElement
  1861. (
  1862. w + "style",
  1863. new XAttribute(w + "type", "paragraph"),
  1864. new XAttribute(w + "styleId", "ListParagraph"),
  1865. new XElement(w + "name", new XAttribute(w + "val", "List Paragraph")),
  1866. new XElement(w + "basedOn", new XAttribute(w + "val", "Normal")),
  1867. new XElement(w + "uiPriority", new XAttribute(w + "val", "34")),
  1868. new XElement(w + "qformat"),
  1869. new XElement(w + "rsid", new XAttribute(w + "val", "00832EE1")),
  1870. new XElement
  1871. (
  1872. w + "rPr",
  1873. new XElement(w + "ind", new XAttribute(w + "left", "720")),
  1874. new XElement
  1875. (
  1876. w + "contextualSpacing"
  1877. )
  1878. )
  1879. );
  1880. wordStyles.Element(w + "styles").Add(style);
  1881. // Save the styles document.
  1882. using (TextWriter tw = new StreamWriter(package.GetPart(wordStylesUri).GetStream()))
  1883. wordStyles.Save(tw);
  1884. }
  1885. return wordStyles;
  1886. }
  1887. /// <summary>
  1888. /// Insert a Table into this document. The Table's source can be a completely different document.
  1889. /// </summary>
  1890. /// <param name="t">The Table to insert.</param>
  1891. /// <param name="index">The index to insert this Table at.</param>
  1892. /// <returns>The Table now associated with this document.</returns>
  1893. /// <example>
  1894. /// Extract a Table from document a and insert it into document b, at index 10.
  1895. /// <code>
  1896. /// // Place holder for a Table.
  1897. /// Table t;
  1898. ///
  1899. /// // Load document a.
  1900. /// using (DocX documentA = DocX.Load(@"C:\Example\a.docx"))
  1901. /// {
  1902. /// // Get the first Table from this document.
  1903. /// t = documentA.Tables[0];
  1904. /// }
  1905. ///
  1906. /// // Load document b.
  1907. /// using (DocX documentB = DocX.Load(@"C:\Example\b.docx"))
  1908. /// {
  1909. /// /*
  1910. /// * Insert the Table that was extracted from document a, into document b.
  1911. /// * This creates a new Table that is now associated with document b.
  1912. /// */
  1913. /// Table newTable = documentB.InsertTable(10, t);
  1914. ///
  1915. /// // Save all changes made to document b.
  1916. /// documentB.Save();
  1917. /// }// Release this document from memory.
  1918. /// </code>
  1919. /// </example>
  1920. public new Table InsertTable(int index, Table t)
  1921. {
  1922. Table t2 = base.InsertTable(index, t);
  1923. t2.mainPart = mainPart;
  1924. return t2;
  1925. }
  1926. /// <summary>
  1927. /// Insert a Table into this document. The Table's source can be a completely different document.
  1928. /// </summary>
  1929. /// <param name="t">The Table to insert.</param>
  1930. /// <returns>The Table now associated with this document.</returns>
  1931. /// <example>
  1932. /// Extract a Table from document a and insert it at the end of document b.
  1933. /// <code>
  1934. /// // Place holder for a Table.
  1935. /// Table t;
  1936. ///
  1937. /// // Load document a.
  1938. /// using (DocX documentA = DocX.Load(@"C:\Example\a.docx"))
  1939. /// {
  1940. /// // Get the first Table from this document.
  1941. /// t = documentA.Tables[0];
  1942. /// }
  1943. ///
  1944. /// // Load document b.
  1945. /// using (DocX documentB = DocX.Load(@"C:\Example\b.docx"))
  1946. /// {
  1947. /// /*
  1948. /// * Insert the Table that was extracted from document a, into document b.
  1949. /// * This creates a new Table that is now associated with document b.
  1950. /// */
  1951. /// Table newTable = documentB.InsertTable(t);
  1952. ///
  1953. /// // Save all changes made to document b.
  1954. /// documentB.Save();
  1955. /// }// Release this document from memory.
  1956. /// </code>
  1957. /// </example>
  1958. public new Table InsertTable(Table t)
  1959. {
  1960. t = base.InsertTable(t);
  1961. t.mainPart = mainPart;
  1962. return t;
  1963. }
  1964. /// <summary>
  1965. /// Insert a new Table at the end of this document.
  1966. /// </summary>
  1967. /// <param name="columnCount">The number of columns to create.</param>
  1968. /// <param name="rowCount">The number of rows to create.</param>
  1969. /// <param name="index">The index to insert this Table at.</param>
  1970. /// <returns>A new Table.</returns>
  1971. /// <example>
  1972. /// Insert a new Table with 2 columns and 3 rows, at index 37 in this document.
  1973. /// <code>
  1974. /// // Create a document.
  1975. /// using (DocX document = DocX.Load(@"C:\Example\Test.docx"))
  1976. /// {
  1977. /// // Create a new Table with 3 rows and 2 columns. Insert this Table at index 37.
  1978. /// Table newTable = document.InsertTable(37, 3, 2);
  1979. ///
  1980. /// // Set the design of this Table.
  1981. /// newTable.Design = TableDesign.LightShadingAccent3;
  1982. ///
  1983. /// // Set the column names.
  1984. /// newTable.Rows[0].Cells[0].Paragraph.InsertText("Ice Cream", false);
  1985. /// newTable.Rows[0].Cells[1].Paragraph.InsertText("Price", false);
  1986. ///
  1987. /// // Fill row 1
  1988. /// newTable.Rows[1].Cells[0].Paragraph.InsertText("Chocolate", false);
  1989. /// newTable.Rows[1].Cells[1].Paragraph.InsertText("€3:50", false);
  1990. ///
  1991. /// // Fill row 2
  1992. /// newTable.Rows[2].Cells[0].Paragraph.InsertText("Vanilla", false);
  1993. /// newTable.Rows[2].Cells[1].Paragraph.InsertText("€3:00", false);
  1994. ///
  1995. /// // Save all changes made to document b.
  1996. /// document.Save();
  1997. /// }// Release this document from memory.
  1998. /// </code>
  1999. /// </example>
  2000. public new Table InsertTable(int index, int rowCount, int columnCount)
  2001. {
  2002. if (rowCount < 1 || columnCount < 1)
  2003. throw new ArgumentOutOfRangeException("Row and Column count must be greater than zero.");
  2004. Table t = base.InsertTable(index, rowCount, columnCount);
  2005. t.mainPart = mainPart;
  2006. return t;
  2007. }
  2008. /// <summary>
  2009. /// Creates a document using a Stream.
  2010. /// </summary>
  2011. /// <param name="stream">The Stream to create the document from.</param>
  2012. /// <param name="documentType"></param>
  2013. /// <returns>Returns a DocX object which represents the document.</returns>
  2014. /// <example>
  2015. /// Creating a document from a FileStream.
  2016. /// <code>
  2017. /// // Use a FileStream fs to create a new document.
  2018. /// using(FileStream fs = new FileStream(@"C:\Example\Test.docx", FileMode.Create))
  2019. /// {
  2020. /// // Load the document using fs
  2021. /// using (DocX document = DocX.Create(fs))
  2022. /// {
  2023. /// // Do something with the document here.
  2024. ///
  2025. /// // Save all changes made to this document.
  2026. /// document.Save();
  2027. /// }// Release this document from memory.
  2028. /// }
  2029. /// </code>
  2030. /// </example>
  2031. /// <example>
  2032. /// Creating a document in a SharePoint site.
  2033. /// <code>
  2034. /// using(SPSite mySite = new SPSite("http://server/sites/site"))
  2035. /// {
  2036. /// // Open a connection to the SharePoint site
  2037. /// using(SPWeb myWeb = mySite.OpenWeb())
  2038. /// {
  2039. /// // Create a MemoryStream ms.
  2040. /// using (MemoryStream ms = new MemoryStream())
  2041. /// {
  2042. /// // Create a document using ms.
  2043. /// using (DocX document = DocX.Create(ms))
  2044. /// {
  2045. /// // Do something with the document here.
  2046. ///
  2047. /// // Save all changes made to this document.
  2048. /// document.Save();
  2049. /// }// Release this document from memory
  2050. ///
  2051. /// // Add the document to the SharePoint site
  2052. /// web.Files.Add("filename", ms.ToArray(), true);
  2053. /// }
  2054. /// }
  2055. /// }
  2056. /// </code>
  2057. /// </example>
  2058. /// <seealso cref="DocX.Load(System.IO.Stream)"/>
  2059. /// <seealso cref="DocX.Load(string)"/>
  2060. /// <seealso cref="DocX.Save()"/>
  2061. public static DocX Create(Stream stream, DocumentTypes documentType = DocumentTypes.Document)
  2062. {
  2063. // Store this document in memory
  2064. MemoryStream ms = new MemoryStream();
  2065. // Create the docx package
  2066. Package package = Package.Open(ms, FileMode.Create, FileAccess.ReadWrite);
  2067. PostCreation(package, documentType);
  2068. DocX document = DocX.Load(ms);
  2069. document.stream = stream;
  2070. return document;
  2071. }
  2072. /// <summary>
  2073. /// Creates a document using a fully qualified or relative filename.
  2074. /// </summary>
  2075. /// <param name="filename">The fully qualified or relative filename.</param>
  2076. /// <param name="documentType"></param>
  2077. /// <returns>Returns a DocX object which represents the document.</returns>
  2078. /// <example>
  2079. /// <code>
  2080. /// // Create a document using a relative filename.
  2081. /// using (DocX document = DocX.Create(@"..\Test.docx"))
  2082. /// {
  2083. /// // Do something with the document here.
  2084. ///
  2085. /// // Save all changes made to this document.
  2086. /// document.Save();
  2087. /// }// Release this document from memory
  2088. /// </code>
  2089. /// <code>
  2090. /// // Create a document using a relative filename.
  2091. /// using (DocX document = DocX.Create(@"..\Test.docx"))
  2092. /// {
  2093. /// // Do something with the document here.
  2094. ///
  2095. /// // Save all changes made to this document.
  2096. /// document.Save();
  2097. /// }// Release this document from memory
  2098. /// </code>
  2099. /// <seealso cref="DocX.Load(System.IO.Stream)"/>
  2100. /// <seealso cref="DocX.Load(string)"/>
  2101. /// <seealso cref="DocX.Save()"/>
  2102. /// </example>
  2103. public static DocX Create(string filename, DocumentTypes documentType = DocumentTypes.Document)
  2104. {
  2105. // Store this document in memory
  2106. MemoryStream ms = new MemoryStream();
  2107. // Create the docx package
  2108. //WordprocessingDocument wdDoc = WordprocessingDocument.Create(ms, DocumentFormat.OpenXml.WordprocessingDocumentType.Document);
  2109. Package package = Package.Open(ms, FileMode.Create, FileAccess.ReadWrite);
  2110. PostCreation(package, documentType);
  2111. DocX document = DocX.Load(ms);
  2112. document.filename = filename;
  2113. return document;
  2114. }
  2115. internal static void PostCreation(Package package, DocumentTypes documentType = DocumentTypes.Document)
  2116. {
  2117. XDocument mainDoc, stylesDoc, numberingDoc;
  2118. #region MainDocumentPart
  2119. // Create the main document part for this package
  2120. PackagePart mainDocumentPart;
  2121. if (documentType == DocumentTypes.Document)
  2122. {
  2123. mainDocumentPart = package.CreatePart(new Uri("/word/document.xml", UriKind.Relative), "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml", CompressionOption.Normal);
  2124. }
  2125. else
  2126. {
  2127. mainDocumentPart = package.CreatePart(new Uri("/word/document.xml", UriKind.Relative), "application/vnd.openxmlformats-officedocument.wordprocessingml.template.main+xml", CompressionOption.Normal);
  2128. }
  2129. package.CreateRelationship(mainDocumentPart.Uri, TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument");
  2130. // Load the document part into a XDocument object
  2131. using (TextReader tr = new StreamReader(mainDocumentPart.GetStream(FileMode.Create, FileAccess.ReadWrite)))
  2132. {
  2133. mainDoc = XDocument.Parse
  2134. (@"<?xml version=""1.0"" encoding=""UTF-8"" standalone=""yes""?>
  2135. <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"" xmlns:a=""http://schemas.openxmlformats.org/drawingml/2006/main"" xmlns:c=""http://schemas.openxmlformats.org/drawingml/2006/chart"">
  2136. <w:body>
  2137. <w:sectPr w:rsidR=""003E25F4"" w:rsidSect=""00FC3028"">
  2138. <w:pgSz w:w=""11906"" w:h=""16838""/>
  2139. <w:pgMar w:top=""1440"" w:right=""1440"" w:bottom=""1440"" w:left=""1440"" w:header=""708"" w:footer=""708"" w:gutter=""0""/>
  2140. <w:cols w:space=""708""/>
  2141. <w:docGrid w:linePitch=""360""/>
  2142. </w:sectPr>
  2143. </w:body>
  2144. </w:document>"
  2145. );
  2146. }
  2147. // Save the main document
  2148. using (TextWriter tw = new StreamWriter(mainDocumentPart.GetStream(FileMode.Create, FileAccess.Write)))
  2149. mainDoc.Save(tw, SaveOptions.None);
  2150. #endregion
  2151. #region StylePart
  2152. stylesDoc = HelperFunctions.AddDefaultStylesXml(package);
  2153. #endregion
  2154. #region NumberingPart
  2155. numberingDoc = HelperFunctions.AddDefaultNumberingXml(package);
  2156. #endregion
  2157. package.Close();
  2158. }
  2159. internal static DocX PostLoad(ref Package package)
  2160. {
  2161. DocX document = new DocX(null, null);
  2162. document.package = package;
  2163. document.Document = document;
  2164. #region MainDocumentPart
  2165. document.mainPart = package.GetParts().Where
  2166. (
  2167. p => p.ContentType.Equals(HelperFunctions.DOCUMENT_DOCUMENTTYPE, StringComparison.CurrentCultureIgnoreCase) ||
  2168. p.ContentType.Equals(HelperFunctions.TEMPLATE_DOCUMENTTYPE, StringComparison.CurrentCultureIgnoreCase)
  2169. ).Single();
  2170. using (TextReader tr = new StreamReader(document.mainPart.GetStream(FileMode.Open, FileAccess.Read)))
  2171. document.mainDoc = XDocument.Load(tr, LoadOptions.PreserveWhitespace);
  2172. #endregion
  2173. PopulateDocument(document, package);
  2174. using (TextReader tr = new StreamReader(document.settingsPart.GetStream()))
  2175. document.settings = XDocument.Load(tr);
  2176. document.paragraphLookup.Clear();
  2177. foreach (var paragraph in document.Paragraphs)
  2178. {
  2179. if (!document.paragraphLookup.ContainsKey(paragraph.endIndex))
  2180. document.paragraphLookup.Add(paragraph.endIndex, paragraph);
  2181. }
  2182. return document;
  2183. }
  2184. private static void PopulateDocument(DocX document, Package package)
  2185. {
  2186. Headers headers = new Headers();
  2187. headers.odd = document.GetHeaderByType("default");
  2188. headers.even = document.GetHeaderByType("even");
  2189. headers.first = document.GetHeaderByType("first");
  2190. Footers footers = new Footers();
  2191. footers.odd = document.GetFooterByType("default");
  2192. footers.even = document.GetFooterByType("even");
  2193. footers.first = document.GetFooterByType("first");
  2194. //// Get the sectPr for this document.
  2195. //XElement sect = document.mainDoc.Descendants(XName.Get("sectPr", DocX.w.NamespaceName)).Single();
  2196. //if (sectPr != null)
  2197. //{
  2198. // // Extract the even header reference
  2199. // var header_even_ref = sectPr.Elements().SingleOrDefault(x => x.Name.LocalName == "headerReference" && x.Attribute(XName.Get("type", DocX.w.NamespaceName)) != null && x.Attribute(XName.Get("type", DocX.w.NamespaceName)).Value == "even");
  2200. // string id = header_even_ref.Attribute(XName.Get("id", DocX.r.NamespaceName)).Value;
  2201. // var res = document.mainPart.GetRelationship(id);
  2202. // string ans = res.SourceUri.OriginalString;
  2203. // headers.even.xml_filename = ans;
  2204. // // Extract the odd header reference
  2205. // var header_odd_ref = sectPr.Elements().SingleOrDefault(x => x.Name.LocalName == "headerReference" && x.Attribute(XName.Get("type", DocX.w.NamespaceName)) != null && x.Attribute(XName.Get("type", DocX.w.NamespaceName)).Value == "default");
  2206. // string id2 = header_odd_ref.Attribute(XName.Get("id", DocX.r.NamespaceName)).Value;
  2207. // var res2 = document.mainPart.GetRelationship(id2);
  2208. // string ans2 = res2.SourceUri.OriginalString;
  2209. // headers.odd.xml_filename = ans2;
  2210. // // Extract the first header reference
  2211. // var header_first_ref = sectPr.Elements().SingleOrDefault(x => x.Name.LocalName == "h
  2212. //eaderReference" && x.Attribute(XName.Get("type", DocX.w.NamespaceName)) != null && x.Attribute(XName.Get("type", DocX.w.NamespaceName)).Value == "first");
  2213. // string id3 = header_first_ref.Attribute(XName.Get("id", DocX.r.NamespaceName)).Value;
  2214. // var res3 = document.mainPart.GetRelationship(id3);
  2215. // string ans3 = res3.SourceUri.OriginalString;
  2216. // headers.first.xml_filename = ans3;
  2217. // // Extract the even footer reference
  2218. // var footer_even_ref = sectPr.Elements().SingleOrDefault(x => x.Name.LocalName == "footerReference" && x.Attribute(XName.Get("type", DocX.w.NamespaceName)) != null && x.Attribute(XName.Get("type", DocX.w.NamespaceName)).Value == "even");
  2219. // string id4 = footer_even_ref.Attribute(XName.Get("id", DocX.r.NamespaceName)).Value;
  2220. // var res4 = document.mainPart.GetRelationship(id4);
  2221. // string ans4 = res4.SourceUri.OriginalString;
  2222. // footers.even.xml_filename = ans4;
  2223. // // Extract the odd footer reference
  2224. // var footer_odd_ref = sectPr.Elements().SingleOrDefault(x => x.Name.LocalName == "footerReference" && x.Attribute(XName.Get("type", DocX.w.NamespaceName)) != null && x.Attribute(XName.Get("type", DocX.w.NamespaceName)).Value == "default");
  2225. // string id5 = footer_odd_ref.Attribute(XName.Get("id", DocX.r.NamespaceName)).Value;
  2226. // var res5 = document.mainPart.GetRelationship(id5);
  2227. // string ans5 = res5.SourceUri.OriginalString;
  2228. // footers.odd.xml_filename = ans5;
  2229. // // Extract the first footer reference
  2230. // var footer_first_ref = sectPr.Elements().SingleOrDefault(x => x.Name.LocalName == "footerReference" && x.Attribute(XName.Get("type", DocX.w.NamespaceName)) != null && x.Attribute(XName.Get("type", DocX.w.NamespaceName)).Value == "first");
  2231. // string id6 = footer_first_ref.Attribute(XName.Get("id", DocX.r.NamespaceName)).Value;
  2232. // var res6 = document.mainPart.GetRelationship(id6);
  2233. // string ans6 = res6.SourceUri.OriginalString;
  2234. // footers.first.xml_filename = ans6;
  2235. //}
  2236. document.Xml = document.mainDoc.Root.Element(w + "body");
  2237. document.headers = headers;
  2238. document.footers = footers;
  2239. document.settingsPart = HelperFunctions.CreateOrGetSettingsPart(package);
  2240. var ps = package.GetParts();
  2241. //document.endnotesPart = HelperFunctions.GetPart();
  2242. foreach (var rel in document.mainPart.GetRelationships())
  2243. {
  2244. switch (rel.RelationshipType)
  2245. {
  2246. case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/endnotes":
  2247. document.endnotesPart = package.GetPart(new Uri("/word/" + rel.TargetUri.OriginalString.Replace("/word/", ""), UriKind.Relative));
  2248. using (TextReader tr = new StreamReader(document.endnotesPart.GetStream()))
  2249. document.endnotes = XDocument.Load(tr);
  2250. break;
  2251. case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes":
  2252. document.footnotesPart = package.GetPart(new Uri("/word/" + rel.TargetUri.OriginalString.Replace("/word/", ""), UriKind.Relative));
  2253. using (TextReader tr = new StreamReader(document.footnotesPart.GetStream()))
  2254. document.footnotes = XDocument.Load(tr);
  2255. break;
  2256. case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles":
  2257. document.stylesPart = package.GetPart(new Uri("/word/" + rel.TargetUri.OriginalString.Replace("/word/", ""), UriKind.Relative));
  2258. using (TextReader tr = new StreamReader(document.stylesPart.GetStream()))
  2259. document.styles = XDocument.Load(tr);
  2260. break;
  2261. case "http://schemas.microsoft.com/office/2007/relationships/stylesWithEffects":
  2262. document.stylesWithEffectsPart = package.GetPart(new Uri("/word/" + rel.TargetUri.OriginalString.Replace("/word/", ""), UriKind.Relative));
  2263. using (TextReader tr = new StreamReader(document.stylesWithEffectsPart.GetStream()))
  2264. document.stylesWithEffects = XDocument.Load(tr);
  2265. break;
  2266. case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable":
  2267. document.fontTablePart = package.GetPart(new Uri("/word/" + rel.TargetUri.OriginalString.Replace("/word/", ""), UriKind.Relative));
  2268. using (TextReader tr = new StreamReader(document.fontTablePart.GetStream()))
  2269. document.fontTable = XDocument.Load(tr);
  2270. break;
  2271. case "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering":
  2272. document.numberingPart = package.GetPart(new Uri("/word/" + rel.TargetUri.OriginalString.Replace("/word/", ""), UriKind.Relative));
  2273. using (TextReader tr = new StreamReader(document.numberingPart.GetStream()))
  2274. document.numbering = XDocument.Load(tr);
  2275. break;
  2276. default:
  2277. break;
  2278. }
  2279. }
  2280. }
  2281. /// <summary>
  2282. /// Saves and copies the document into a new DocX object
  2283. /// </summary>
  2284. /// <returns>
  2285. /// Returns a new DocX object with an identical document
  2286. /// </returns>
  2287. /// <example>
  2288. /// <seealso cref="DocX.Load(System.IO.Stream)"/>
  2289. /// <seealso cref="DocX.Save()"/>
  2290. /// </example>
  2291. public DocX Copy()
  2292. {
  2293. MemoryStream ms = new MemoryStream();
  2294. SaveAs(ms);
  2295. ms.Seek(0, SeekOrigin.Begin);
  2296. return DocX.Load(ms);
  2297. }
  2298. /// <summary>
  2299. /// Loads a document into a DocX object using a Stream.
  2300. /// </summary>
  2301. /// <param name="stream">The Stream to load the document from.</param>
  2302. /// <returns>
  2303. /// Returns a DocX object which represents the document.
  2304. /// </returns>
  2305. /// <example>
  2306. /// Loading a document from a FileStream.
  2307. /// <code>
  2308. /// // Open a FileStream fs to a document.
  2309. /// using (FileStream fs = new FileStream(@"C:\Example\Test.docx", FileMode.Open))
  2310. /// {
  2311. /// // Load the document using fs.
  2312. /// using (DocX document = DocX.Load(fs))
  2313. /// {
  2314. /// // Do something with the document here.
  2315. ///
  2316. /// // Save all changes made to the document.
  2317. /// document.Save();
  2318. /// }// Release this document from memory.
  2319. /// }
  2320. /// </code>
  2321. /// </example>
  2322. /// <example>
  2323. /// Loading a document from a SharePoint site.
  2324. /// <code>
  2325. /// // Get the SharePoint site that you want to access.
  2326. /// using (SPSite mySite = new SPSite("http://server/sites/site"))
  2327. /// {
  2328. /// // Open a connection to the SharePoint site
  2329. /// using (SPWeb myWeb = mySite.OpenWeb())
  2330. /// {
  2331. /// // Grab a document stored on this site.
  2332. /// SPFile file = web.GetFile("Source_Folder_Name/Source_File");
  2333. ///
  2334. /// // DocX.Load requires a Stream, so open a Stream to this document.
  2335. /// Stream str = new MemoryStream(file.OpenBinary());
  2336. ///
  2337. /// // Load the file using the Stream str.
  2338. /// using (DocX document = DocX.Load(str))
  2339. /// {
  2340. /// // Do something with the document here.
  2341. ///
  2342. /// // Save all changes made to the document.
  2343. /// document.Save();
  2344. /// }// Release this document from memory.
  2345. /// }
  2346. /// }
  2347. /// </code>
  2348. /// </example>
  2349. /// <seealso cref="DocX.Load(string)"/>
  2350. /// <seealso cref="DocX.Save()"/>
  2351. public static DocX Load(Stream stream)
  2352. {
  2353. MemoryStream ms = new MemoryStream();
  2354. stream.Position = 0;
  2355. byte[] data = new byte[stream.Length];
  2356. stream.Read(data, 0, (int)stream.Length);
  2357. ms.Write(data, 0, (int)stream.Length);
  2358. // Open the docx package
  2359. Package package = Package.Open(ms, FileMode.Open, FileAccess.ReadWrite);
  2360. DocX document = PostLoad(ref package);
  2361. document.package = package;
  2362. document.memoryStream = ms;
  2363. document.stream = stream;
  2364. return document;
  2365. }
  2366. /// <summary>
  2367. /// Loads a document into a DocX object using a fully qualified or relative filename.
  2368. /// </summary>
  2369. /// <param name="filename">The fully qualified or relative filename.</param>
  2370. /// <returns>
  2371. /// Returns a DocX object which represents the document.
  2372. /// </returns>
  2373. /// <example>
  2374. /// <code>
  2375. /// // Load a document using its fully qualified filename
  2376. /// using (DocX document = DocX.Load(@"C:\Example\Test.docx"))
  2377. /// {
  2378. /// // Do something with the document here
  2379. ///
  2380. /// // Save all changes made to document.
  2381. /// document.Save();
  2382. /// }// Release this document from memory.
  2383. /// </code>
  2384. /// <code>
  2385. /// // Load a document using its relative filename.
  2386. /// using(DocX document = DocX.Load(@"..\..\Test.docx"))
  2387. /// {
  2388. /// // Do something with the document here.
  2389. ///
  2390. /// // Save all changes made to document.
  2391. /// document.Save();
  2392. /// }// Release this document from memory.
  2393. /// </code>
  2394. /// <seealso cref="DocX.Load(System.IO.Stream)"/>
  2395. /// <seealso cref="DocX.Save()"/>
  2396. /// </example>
  2397. public static DocX Load(string filename)
  2398. {
  2399. if (!File.Exists(filename))
  2400. throw new FileNotFoundException(string.Format("File could not be found {0}", filename));
  2401. MemoryStream ms = new MemoryStream();
  2402. using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read))
  2403. {
  2404. byte[] data = new byte[fs.Length];
  2405. fs.Read(data, 0, (int)fs.Length);
  2406. ms.Write(data, 0, (int)fs.Length);
  2407. }
  2408. // Open the docx package
  2409. Package package = Package.Open(ms, FileMode.Open, FileAccess.ReadWrite);
  2410. DocX document = PostLoad(ref package);
  2411. document.package = package;
  2412. document.filename = filename;
  2413. document.memoryStream = ms;
  2414. return document;
  2415. }
  2416. ///<summary>
  2417. /// Applies document template to the document. Document template may include styles, headers, footers, properties, etc. as well as text content.
  2418. ///</summary>
  2419. ///<param name="templateFilePath">The path to the document template file.</param>
  2420. ///<exception cref="FileNotFoundException">The document template file not found.</exception>
  2421. public void ApplyTemplate(string templateFilePath)
  2422. {
  2423. ApplyTemplate(templateFilePath, true);
  2424. }
  2425. ///<summary>
  2426. /// Applies document template to the document. Document template may include styles, headers, footers, properties, etc. as well as text content.
  2427. ///</summary>
  2428. ///<param name="templateFilePath">The path to the document template file.</param>
  2429. ///<param name="includeContent">Whether to copy the document template text content to document.</param>
  2430. ///<exception cref="FileNotFoundException">The document template file not found.</exception>
  2431. public void ApplyTemplate(string templateFilePath, bool includeContent)
  2432. {
  2433. if (!File.Exists(templateFilePath))
  2434. {
  2435. throw new FileNotFoundException(string.Format("File could not be found {0}", templateFilePath));
  2436. }
  2437. using (FileStream packageStream = new FileStream(templateFilePath, FileMode.Open, FileAccess.Read))
  2438. {
  2439. ApplyTemplate(packageStream, includeContent);
  2440. }
  2441. }
  2442. ///<summary>
  2443. /// Applies document template to the document. Document template may include styles, headers, footers, properties, etc. as well as text content.
  2444. ///</summary>
  2445. ///<param name="templateStream">The stream of the document template file.</param>
  2446. public void ApplyTemplate(Stream templateStream)
  2447. {
  2448. ApplyTemplate(templateStream, true);
  2449. }
  2450. ///<summary>
  2451. /// Applies document template to the document. Document template may include styles, headers, footers, properties, etc. as well as text content.
  2452. ///</summary>
  2453. ///<param name="templateStream">The stream of the document template file.</param>
  2454. ///<param name="includeContent">Whether to copy the document template text content to document.</param>
  2455. public void ApplyTemplate(Stream templateStream, bool includeContent)
  2456. {
  2457. Package templatePackage = Package.Open(templateStream);
  2458. try
  2459. {
  2460. PackagePart documentPart = null;
  2461. XDocument documentDoc = null;
  2462. foreach (PackagePart packagePart in templatePackage.GetParts())
  2463. {
  2464. switch (packagePart.Uri.ToString())
  2465. {
  2466. case "/word/document.xml":
  2467. documentPart = packagePart;
  2468. using (XmlReader xr = XmlReader.Create(packagePart.GetStream(FileMode.Open, FileAccess.Read)))
  2469. {
  2470. documentDoc = XDocument.Load(xr);
  2471. }
  2472. break;
  2473. case "/_rels/.rels":
  2474. if (!this.package.PartExists(packagePart.Uri))
  2475. {
  2476. this.package.CreatePart(packagePart.Uri, packagePart.ContentType, packagePart.CompressionOption);
  2477. }
  2478. PackagePart globalRelsPart = this.package.GetPart(packagePart.Uri);
  2479. using (
  2480. StreamReader tr = new StreamReader(
  2481. packagePart.GetStream(FileMode.Open, FileAccess.Read), Encoding.UTF8))
  2482. {
  2483. using (
  2484. StreamWriter tw = new StreamWriter(
  2485. globalRelsPart.GetStream(FileMode.Create, FileAccess.Write), Encoding.UTF8))
  2486. {
  2487. tw.Write(tr.ReadToEnd());
  2488. }
  2489. }
  2490. break;
  2491. case "/word/_rels/document.xml.rels":
  2492. break;
  2493. default:
  2494. if (!this.package.PartExists(packagePart.Uri))
  2495. {
  2496. this.package.CreatePart(packagePart.Uri, packagePart.ContentType, packagePart.CompressionOption);
  2497. }
  2498. Encoding packagePartEncoding = Encoding.Default;
  2499. if (packagePart.Uri.ToString().EndsWith(".xml") || packagePart.Uri.ToString().EndsWith(".rels"))
  2500. {
  2501. packagePartEncoding = Encoding.UTF8;
  2502. }
  2503. PackagePart nativePart = this.package.GetPart(packagePart.Uri);
  2504. using (
  2505. StreamReader tr = new StreamReader(
  2506. packagePart.GetStream(FileMode.Open, FileAccess.Read), packagePartEncoding))
  2507. {
  2508. using (
  2509. StreamWriter tw = new StreamWriter(
  2510. nativePart.GetStream(FileMode.Create, FileAccess.Write), tr.CurrentEncoding))
  2511. {
  2512. tw.Write(tr.ReadToEnd());
  2513. }
  2514. }
  2515. break;
  2516. }
  2517. }
  2518. if (documentPart != null)
  2519. {
  2520. string mainContentType = documentPart.ContentType.Replace("template.main", "document.main");
  2521. if (this.package.PartExists(documentPart.Uri))
  2522. {
  2523. this.package.DeletePart(documentPart.Uri);
  2524. }
  2525. PackagePart documentNewPart = this.package.CreatePart(
  2526. documentPart.Uri, mainContentType, documentPart.CompressionOption);
  2527. using (XmlWriter xw = XmlWriter.Create(documentNewPart.GetStream(FileMode.Create, FileAccess.Write)))
  2528. {
  2529. documentDoc.WriteTo(xw);
  2530. }
  2531. foreach (PackageRelationship documentPartRel in documentPart.GetRelationships())
  2532. {
  2533. documentNewPart.CreateRelationship(
  2534. documentPartRel.TargetUri,
  2535. documentPartRel.TargetMode,
  2536. documentPartRel.RelationshipType,
  2537. documentPartRel.Id);
  2538. }
  2539. this.mainPart = documentNewPart;
  2540. this.mainDoc = documentDoc;
  2541. PopulateDocument(this, templatePackage);
  2542. // DragonFire: I added next line and recovered ApplyTemplate method.
  2543. // I do it, becouse PopulateDocument(...) writes into field "settingsPart" the part of Template's package
  2544. // and after line "templatePackage.Close();" in finally, field "settingsPart" becomes not available and method "Save" throw an exception...
  2545. // That's why I recreated settingsParts and unlinked it from Template's package =)
  2546. settingsPart = HelperFunctions.CreateOrGetSettingsPart(package);
  2547. }
  2548. if (!includeContent)
  2549. {
  2550. foreach (Paragraph paragraph in this.Paragraphs)
  2551. {
  2552. paragraph.Remove(false);
  2553. }
  2554. }
  2555. }
  2556. finally
  2557. {
  2558. this.package.Flush();
  2559. var documentRelsPart = this.package.GetPart(new Uri("/word/_rels/document.xml.rels", UriKind.Relative));
  2560. using (TextReader tr = new StreamReader(documentRelsPart.GetStream(FileMode.Open, FileAccess.Read)))
  2561. {
  2562. tr.Read();
  2563. }
  2564. templatePackage.Close();
  2565. PopulateDocument(Document, package);
  2566. }
  2567. }
  2568. /// <summary>
  2569. /// Add an Image into this document from a fully qualified or relative filename.
  2570. /// </summary>
  2571. /// <param name="filename">The fully qualified or relative filename.</param>
  2572. /// <returns>An Image file.</returns>
  2573. /// <example>
  2574. /// Add an Image into this document from a fully qualified filename.
  2575. /// <code>
  2576. /// // Load a document.
  2577. /// using (DocX document = DocX.Load(@"C:\Example\Test.docx"))
  2578. /// {
  2579. /// // Add an Image from a file.
  2580. /// document.AddImage(@"C:\Example\Image.png");
  2581. ///
  2582. /// // Save all changes made to this document.
  2583. /// document.Save();
  2584. /// }// Release this document from memory.
  2585. /// </code>
  2586. /// </example>
  2587. /// <seealso cref="AddImage(System.IO.Stream)"/>
  2588. /// <seealso cref="Paragraph.InsertPicture"/>
  2589. public Image AddImage(string filename)
  2590. {
  2591. string contentType = "";
  2592. // The extension this file has will be taken to be its format.
  2593. switch (Path.GetExtension(filename))
  2594. {
  2595. case ".tiff": contentType = "image/tif"; break;
  2596. case ".tif": contentType = "image/tif"; break;
  2597. case ".png": contentType = "image/png"; break;
  2598. case ".bmp": contentType = "image/png"; break;
  2599. case ".gif": contentType = "image/gif"; break;
  2600. case ".jpg": contentType = "image/jpg"; break;
  2601. case ".jpeg": contentType = "image/jpeg"; break;
  2602. default: contentType = "image/jpg"; break;
  2603. }
  2604. return AddImage(filename as object, contentType);
  2605. }
  2606. /// <summary>
  2607. /// Add an Image into this document from a Stream.
  2608. /// </summary>
  2609. /// <param name="stream">A Stream stream.</param>
  2610. /// <returns>An Image file.</returns>
  2611. /// <example>
  2612. /// Add an Image into a document using a Stream.
  2613. /// <code>
  2614. /// // Open a FileStream fs to an Image.
  2615. /// using (FileStream fs = new FileStream(@"C:\Example\Image.jpg", FileMode.Open))
  2616. /// {
  2617. /// // Load a document.
  2618. /// using (DocX document = DocX.Load(@"C:\Example\Test.docx"))
  2619. /// {
  2620. /// // Add an Image from a filestream fs.
  2621. /// document.AddImage(fs);
  2622. ///
  2623. /// // Save all changes made to this document.
  2624. /// document.Save();
  2625. /// }// Release this document from memory.
  2626. /// }
  2627. /// </code>
  2628. /// </example>
  2629. /// <seealso cref="AddImage(string)"/>
  2630. /// <seealso cref="Paragraph.InsertPicture"/>
  2631. public Image AddImage(Stream stream)
  2632. {
  2633. return AddImage(stream as object);
  2634. }
  2635. /// <summary>
  2636. /// Adds a hyperlink to a document and creates a Paragraph which uses it.
  2637. /// </summary>
  2638. /// <param name="text">The text as displayed by the hyperlink.</param>
  2639. /// <param name="uri">The hyperlink itself.</param>
  2640. /// <returns>Returns a hyperlink that can be inserted into a Paragraph.</returns>
  2641. /// <example>
  2642. /// Adds a hyperlink to a document and creates a Paragraph which uses it.
  2643. /// <code>
  2644. /// // Create a document.
  2645. /// using (DocX document = DocX.Create(@"Test.docx"))
  2646. /// {
  2647. /// // Add a hyperlink to this document.
  2648. /// Hyperlink h = document.AddHyperlink("Google", new Uri("http://www.google.com"));
  2649. ///
  2650. /// // Add a new Paragraph to this document.
  2651. /// Paragraph p = document.InsertParagraph();
  2652. /// p.Append("My favourite search engine is ");
  2653. /// p.AppendHyperlink(h);
  2654. /// p.Append(", I think it's great.");
  2655. ///
  2656. /// // Save all changes made to this document.
  2657. /// document.Save();
  2658. /// }
  2659. /// </code>
  2660. /// </example>
  2661. public Hyperlink AddHyperlink(string text, Uri uri)
  2662. {
  2663. XElement i = new XElement
  2664. (
  2665. XName.Get("hyperlink", DocX.w.NamespaceName),
  2666. new XAttribute(r + "id", string.Empty),
  2667. new XAttribute(w + "history", "1"),
  2668. new XElement(XName.Get("r", DocX.w.NamespaceName),
  2669. new XElement(XName.Get("rPr", DocX.w.NamespaceName),
  2670. new XElement(XName.Get("rStyle", DocX.w.NamespaceName),
  2671. new XAttribute(w + "val", "Hyperlink"))),
  2672. new XElement(XName.Get("t", DocX.w.NamespaceName), text))
  2673. );
  2674. Hyperlink h = new Hyperlink(this, mainPart, i);
  2675. h.text = text;
  2676. h.uri = uri;
  2677. AddHyperlinkStyleIfNotPresent();
  2678. return h;
  2679. }
  2680. internal void AddHyperlinkStyleIfNotPresent()
  2681. {
  2682. Uri word_styles_Uri = new Uri("/word/styles.xml", UriKind.Relative);
  2683. // If the internal document contains no /word/styles.xml create one.
  2684. if (!package.PartExists(word_styles_Uri))
  2685. HelperFunctions.AddDefaultStylesXml(package);
  2686. // Load the styles.xml into memory.
  2687. XDocument word_styles;
  2688. using (TextReader tr = new StreamReader(package.GetPart(word_styles_Uri).GetStream()))
  2689. word_styles = XDocument.Load(tr);
  2690. bool hyperlinkStyleExists =
  2691. (
  2692. from s in word_styles.Element(w + "styles").Elements()
  2693. let styleId = s.Attribute(XName.Get("styleId", w.NamespaceName))
  2694. where (styleId != null && styleId.Value == "Hyperlink")
  2695. select s
  2696. ).Count() > 0;
  2697. if (!hyperlinkStyleExists)
  2698. {
  2699. XElement style = new XElement
  2700. (
  2701. w + "style",
  2702. new XAttribute(w + "type", "character"),
  2703. new XAttribute(w + "styleId", "Hyperlink"),
  2704. new XElement(w + "name", new XAttribute(w + "val", "Hyperlink")),
  2705. new XElement(w + "basedOn", new XAttribute(w + "val", "DefaultParagraphFont")),
  2706. new XElement(w + "uiPriority", new XAttribute(w + "val", "99")),
  2707. new XElement(w + "unhideWhenUsed"),
  2708. new XElement(w + "rsid", new XAttribute(w + "val", "0005416C")),
  2709. new XElement
  2710. (
  2711. w + "rPr",
  2712. new XElement(w + "color", new XAttribute(w + "val", "0000FF"), new XAttribute(w + "themeColor", "hyperlink")),
  2713. new XElement
  2714. (
  2715. w + "u",
  2716. new XAttribute(w + "val", "single")
  2717. )
  2718. )
  2719. );
  2720. word_styles.Element(w + "styles").Add(style);
  2721. // Save the styles document.
  2722. using (TextWriter tw = new StreamWriter(package.GetPart(word_styles_Uri).GetStream()))
  2723. word_styles.Save(tw);
  2724. }
  2725. }
  2726. private string GetNextFreeRelationshipID()
  2727. {
  2728. int id = (
  2729. from r in mainPart.GetRelationships()
  2730. where r.Id.Substring(0, 3).Equals("rId")
  2731. select int.Parse(r.Id.Substring(3))
  2732. ).DefaultIfEmpty().Max();
  2733. // The conventiom for ids is rid01, rid02, etc
  2734. string newId = id.ToString();
  2735. int result;
  2736. if (int.TryParse(newId, out result))
  2737. return ("rId" + (result + 1));
  2738. else
  2739. {
  2740. String guid = String.Empty;
  2741. do
  2742. {
  2743. guid = Guid.NewGuid().ToString();
  2744. } while (Char.IsDigit(guid[0]));
  2745. return guid;
  2746. }
  2747. }
  2748. /// <summary>
  2749. /// Adds three new Headers to this document. One for the first page, one for odd pages and one for even pages.
  2750. /// </summary>
  2751. /// <example>
  2752. /// // Create a document.
  2753. /// using (DocX document = DocX.Create(@"Test.docx"))
  2754. /// {
  2755. /// // Add header support to this document.
  2756. /// document.AddHeaders();
  2757. ///
  2758. /// // Get a collection of all headers in this document.
  2759. /// Headers headers = document.Headers;
  2760. ///
  2761. /// // The header used for the first page of this document.
  2762. /// Header first = headers.first;
  2763. ///
  2764. /// // The header used for odd pages of this document.
  2765. /// Header odd = headers.odd;
  2766. ///
  2767. /// // The header used for even pages of this document.
  2768. /// Header even = headers.even;
  2769. ///
  2770. /// // Force the document to use a different header for first, odd and even pages.
  2771. /// document.DifferentFirstPage = true;
  2772. /// document.DifferentOddAndEvenPages = true;
  2773. ///
  2774. /// // Content can be added to the Headers in the same manor that it would be added to the main document.
  2775. /// Paragraph p = first.InsertParagraph();
  2776. /// p.Append("This is the first pages header.");
  2777. ///
  2778. /// // Save all changes to this document.
  2779. /// document.Save();
  2780. /// }// Release this document from memory.
  2781. /// </example>
  2782. public void AddHeaders()
  2783. {
  2784. AddHeadersOrFooters(true);
  2785. headers.odd = Document.GetHeaderByType("default");
  2786. headers.even = Document.GetHeaderByType("even");
  2787. headers.first = Document.GetHeaderByType("first");
  2788. }
  2789. /// <summary>
  2790. /// Adds three new Footers to this document. One for the first page, one for odd pages and one for even pages.
  2791. /// </summary>
  2792. /// <example>
  2793. /// // Create a document.
  2794. /// using (DocX document = DocX.Create(@"Test.docx"))
  2795. /// {
  2796. /// // Add footer support to this document.
  2797. /// document.AddFooters();
  2798. ///
  2799. /// // Get a collection of all footers in this document.
  2800. /// Footers footers = document.Footers;
  2801. ///
  2802. /// // The footer used for the first page of this document.
  2803. /// Footer first = footers.first;
  2804. ///
  2805. /// // The footer used for odd pages of this document.
  2806. /// Footer odd = footers.odd;
  2807. ///
  2808. /// // The footer used for even pages of this document.
  2809. /// Footer even = footers.even;
  2810. ///
  2811. /// // Force the document to use a different footer for first, odd and even pages.
  2812. /// document.DifferentFirstPage = true;
  2813. /// document.DifferentOddAndEvenPages = true;
  2814. ///
  2815. /// // Content can be added to the Footers in the same manor that it would be added to the main document.
  2816. /// Paragraph p = first.InsertParagraph();
  2817. /// p.Append("This is the first pages footer.");
  2818. ///
  2819. /// // Save all changes to this document.
  2820. /// document.Save();
  2821. /// }// Release this document from memory.
  2822. /// </example>
  2823. public void AddFooters()
  2824. {
  2825. AddHeadersOrFooters(false);
  2826. footers.odd = Document.GetFooterByType("default");
  2827. footers.even = Document.GetFooterByType("even");
  2828. footers.first = Document.GetFooterByType("first");
  2829. }
  2830. /// <summary>
  2831. /// Adds a Header to a document.
  2832. /// If the document already contains a Header it will be replaced.
  2833. /// </summary>
  2834. /// <returns>The Header that was added to the document.</returns>
  2835. internal void AddHeadersOrFooters(bool b)
  2836. {
  2837. string element = "ftr";
  2838. string reference = "footer";
  2839. if (b)
  2840. {
  2841. element = "hdr";
  2842. reference = "header";
  2843. }
  2844. DeleteHeadersOrFooters(b);
  2845. XElement sectPr = mainDoc.Root.Element(w + "body").Element(w + "sectPr");
  2846. for (int i = 1; i < 4; i++)
  2847. {
  2848. string header_uri = string.Format("/word/{0}{1}.xml", reference, i);
  2849. PackagePart headerPart = package.CreatePart(new Uri(header_uri, UriKind.Relative), string.Format("application/vnd.openxmlformats-officedocument.wordprocessingml.{0}+xml", reference), CompressionOption.Normal);
  2850. PackageRelationship headerRelationship = mainPart.CreateRelationship(headerPart.Uri, TargetMode.Internal, string.Format("http://schemas.openxmlformats.org/officeDocument/2006/relationships/{0}", reference));
  2851. XDocument header;
  2852. // Load the document part into a XDocument object
  2853. using (TextReader tr = new StreamReader(headerPart.GetStream(FileMode.Create, FileAccess.ReadWrite)))
  2854. {
  2855. header = XDocument.Parse
  2856. (string.Format(@"<?xml version=""1.0"" encoding=""utf-16"" standalone=""yes""?>
  2857. <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"">
  2858. <w:p w:rsidR=""009D472B"" w:rsidRDefault=""009D472B"">
  2859. <w:pPr>
  2860. <w:pStyle w:val=""{1}"" />
  2861. </w:pPr>
  2862. </w:p>
  2863. </w:{0}>", element, reference)
  2864. );
  2865. }
  2866. // Save the main document
  2867. using (TextWriter tw = new StreamWriter(headerPart.GetStream(FileMode.Create, FileAccess.Write)))
  2868. header.Save(tw, SaveOptions.None);
  2869. string type;
  2870. switch (i)
  2871. {
  2872. case 1: type = "default"; break;
  2873. case 2: type = "even"; break;
  2874. case 3: type = "first"; break;
  2875. default: throw new ArgumentOutOfRangeException();
  2876. }
  2877. sectPr.Add
  2878. (
  2879. new XElement
  2880. (
  2881. w + string.Format("{0}Reference", reference),
  2882. new XAttribute(w + "type", type),
  2883. new XAttribute(r + "id", headerRelationship.Id)
  2884. )
  2885. );
  2886. }
  2887. }
  2888. internal void DeleteHeadersOrFooters(bool b)
  2889. {
  2890. string reference = "footer";
  2891. if (b)
  2892. reference = "header";
  2893. // Get all header Relationships in this document.
  2894. var header_relationships = mainPart.GetRelationshipsByType(string.Format("http://schemas.openxmlformats.org/officeDocument/2006/relationships/{0}", reference));
  2895. foreach (PackageRelationship header_relationship in header_relationships)
  2896. {
  2897. // Get the TargetUri for this Part.
  2898. Uri header_uri = header_relationship.TargetUri;
  2899. // Check to see if the document actually contains the Part.
  2900. if (!header_uri.OriginalString.StartsWith("/word/"))
  2901. header_uri = new Uri("/word/" + header_uri.OriginalString, UriKind.Relative);
  2902. if (package.PartExists(header_uri))
  2903. {
  2904. // Delete the Part
  2905. package.DeletePart(header_uri);
  2906. // Get all references to this Relationship in the document.
  2907. var query =
  2908. (
  2909. from e in mainDoc.Descendants(XName.Get("body", DocX.w.NamespaceName)).Descendants()
  2910. where (e.Name.LocalName == string.Format("{0}Reference", reference)) && (e.Attribute(r + "id").Value == header_relationship.Id)
  2911. select e
  2912. );
  2913. // Remove all references to this Relationship in the document.
  2914. for (int i = 0; i < query.Count(); i++)
  2915. query.ElementAt(i).Remove();
  2916. // Delete the Relationship.
  2917. package.DeleteRelationship(header_relationship.Id);
  2918. }
  2919. }
  2920. }
  2921. internal Image AddImage(object o, string contentType = "image/jpeg")
  2922. {
  2923. // Open a Stream to the new image being added.
  2924. Stream newImageStream;
  2925. if (o is string)
  2926. newImageStream = new FileStream(o as string, FileMode.Open, FileAccess.Read);
  2927. else
  2928. newImageStream = o as Stream;
  2929. // Get all image parts in word\document.xml
  2930. PackageRelationshipCollection relationshipsByImages = mainPart.GetRelationshipsByType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/image");
  2931. List<PackagePart> imageParts = relationshipsByImages.Select(ir => package.GetParts().FirstOrDefault(p => p.Uri.ToString().EndsWith(ir.TargetUri.ToString()))).Where(e => e != null).ToList();
  2932. foreach (PackagePart relsPart in package.GetParts().Where(part => part.Uri.ToString().Contains("/word/")).Where(part => part.ContentType.Equals("application/vnd.openxmlformats-package.relationships+xml")))
  2933. {
  2934. XDocument relsPartContent;
  2935. using (TextReader tr = new StreamReader(relsPart.GetStream(FileMode.Open, FileAccess.Read)))
  2936. relsPartContent = XDocument.Load(tr);
  2937. IEnumerable<XElement> imageRelationships =
  2938. relsPartContent.Root.Elements().Where
  2939. (
  2940. imageRel =>
  2941. imageRel.Attribute(XName.Get("Type")).Value.Equals("http://schemas.openxmlformats.org/officeDocument/2006/relationships/image")
  2942. );
  2943. foreach (XElement imageRelationship in imageRelationships)
  2944. {
  2945. if (imageRelationship.Attribute(XName.Get("Target")) != null)
  2946. {
  2947. string targetMode = string.Empty;
  2948. XAttribute targetModeAttibute = imageRelationship.Attribute(XName.Get("TargetMode"));
  2949. if (targetModeAttibute != null)
  2950. {
  2951. targetMode = targetModeAttibute.Value;
  2952. }
  2953. if (!targetMode.Equals("External"))
  2954. {
  2955. string imagePartUri = Path.Combine(Path.GetDirectoryName(relsPart.Uri.ToString()), imageRelationship.Attribute(XName.Get("Target")).Value);
  2956. imagePartUri = Path.GetFullPath(imagePartUri.Replace("\\_rels", string.Empty));
  2957. imagePartUri = imagePartUri.Replace(Path.GetFullPath("\\"), string.Empty).Replace("\\", "/");
  2958. if (!imagePartUri.StartsWith("/"))
  2959. imagePartUri = "/" + imagePartUri;
  2960. PackagePart imagePart = package.GetPart(new Uri(imagePartUri, UriKind.Relative));
  2961. imageParts.Add(imagePart);
  2962. }
  2963. }
  2964. }
  2965. }
  2966. // Loop through each image part in this document.
  2967. foreach (PackagePart pp in imageParts)
  2968. {
  2969. // Open a tempory Stream to this image part.
  2970. using (Stream tempStream = pp.GetStream(FileMode.Open, FileAccess.Read))
  2971. {
  2972. // Compare this image to the new image being added.
  2973. if (HelperFunctions.IsSameFile(tempStream, newImageStream))
  2974. {
  2975. // Get the image object for this image part
  2976. string id = mainPart.GetRelationshipsByType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/image")
  2977. .Where(r => r.TargetUri == pp.Uri)
  2978. .Select(r => r.Id).First();
  2979. // Return the Image object
  2980. return Images.Where(i => i.Id == id).First();
  2981. }
  2982. }
  2983. }
  2984. string imgPartUriPath = string.Empty;
  2985. string extension = contentType.Substring(contentType.LastIndexOf("/") + 1);
  2986. do
  2987. {
  2988. // Create a new image part.
  2989. imgPartUriPath = string.Format
  2990. (
  2991. "/word/media/{0}.{1}",
  2992. Guid.NewGuid().ToString(), // The unique part.
  2993. extension
  2994. );
  2995. } while (package.PartExists(new Uri(imgPartUriPath, UriKind.Relative)));
  2996. // We are now guareenteed that imgPartUriPath is unique.
  2997. PackagePart img = package.CreatePart(new Uri(imgPartUriPath, UriKind.Relative), contentType, CompressionOption.Normal);
  2998. // Create a new image relationship
  2999. PackageRelationship rel = mainPart.CreateRelationship(img.Uri, TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image");
  3000. // Open a Stream to the newly created Image part.
  3001. using (Stream stream = img.GetStream(FileMode.Create, FileAccess.Write))
  3002. {
  3003. // Using the Stream to the real image, copy this streams data into the newly create Image part.
  3004. using (newImageStream)
  3005. {
  3006. byte[] bytes = new byte[newImageStream.Length];
  3007. newImageStream.Read(bytes, 0, (int)newImageStream.Length);
  3008. stream.Write(bytes, 0, (int)newImageStream.Length);
  3009. }// Close the Stream to the new image.
  3010. }// Close the Stream to the new image part.
  3011. return new Image(this, rel);
  3012. }
  3013. /// <summary>
  3014. /// Save this document back to the location it was loaded from.
  3015. /// </summary>
  3016. /// <example>
  3017. /// <code>
  3018. /// // Load a document.
  3019. /// using (DocX document = DocX.Load(@"C:\Example\Test.docx"))
  3020. /// {
  3021. /// // Add an Image from a file.
  3022. /// document.AddImage(@"C:\Example\Image.jpg");
  3023. ///
  3024. /// // Save all changes made to this document.
  3025. /// document.Save();
  3026. /// }// Release this document from memory.
  3027. /// </code>
  3028. /// </example>
  3029. /// <seealso cref="DocX.SaveAs(string)"/>
  3030. /// <seealso cref="DocX.Load(System.IO.Stream)"/>
  3031. /// <seealso cref="DocX.Load(string)"/>
  3032. /// <!--
  3033. /// Bug found and fixed by krugs525 on August 12 2009.
  3034. /// Use TFS compare to see exact code change.
  3035. /// -->
  3036. public void Save()
  3037. {
  3038. Headers headers = Headers;
  3039. // Save the main document
  3040. using (TextWriter tw = new StreamWriter(mainPart.GetStream(FileMode.Create, FileAccess.Write)))
  3041. mainDoc.Save(tw, SaveOptions.None);
  3042. if (settings == null)
  3043. {
  3044. using (TextReader tr = new StreamReader(settingsPart.GetStream()))
  3045. settings = XDocument.Load(tr);
  3046. }
  3047. XElement body = mainDoc.Root.Element(w + "body");
  3048. XElement sectPr = body.Descendants(w + "sectPr").FirstOrDefault();
  3049. if (sectPr != null)
  3050. {
  3051. var evenHeaderRef =
  3052. (
  3053. from e in mainDoc.Descendants(w + "headerReference")
  3054. let type = e.Attribute(w + "type")
  3055. where type != null && type.Value.Equals("even", StringComparison.CurrentCultureIgnoreCase)
  3056. select e.Attribute(r + "id").Value
  3057. ).LastOrDefault();
  3058. if (evenHeaderRef != null)
  3059. {
  3060. XElement even = headers.even.Xml;
  3061. Uri target = PackUriHelper.ResolvePartUri
  3062. (
  3063. mainPart.Uri,
  3064. mainPart.GetRelationship(evenHeaderRef).TargetUri
  3065. );
  3066. using (TextWriter tw = new StreamWriter(package.GetPart(target).GetStream(FileMode.Create, FileAccess.Write)))
  3067. {
  3068. new XDocument
  3069. (
  3070. new XDeclaration("1.0", "UTF-8", "yes"),
  3071. even
  3072. ).Save(tw, SaveOptions.None);
  3073. }
  3074. }
  3075. var oddHeaderRef =
  3076. (
  3077. from e in mainDoc.Descendants(w + "headerReference")
  3078. let type = e.Attribute(w + "type")
  3079. where type != null && type.Value.Equals("default", StringComparison.CurrentCultureIgnoreCase)
  3080. select e.Attribute(r + "id").Value
  3081. ).LastOrDefault();
  3082. if (oddHeaderRef != null)
  3083. {
  3084. XElement odd = headers.odd.Xml;
  3085. Uri target = PackUriHelper.ResolvePartUri
  3086. (
  3087. mainPart.Uri,
  3088. mainPart.GetRelationship(oddHeaderRef).TargetUri
  3089. );
  3090. // Save header1
  3091. using (TextWriter tw = new StreamWriter(package.GetPart(target).GetStream(FileMode.Create, FileAccess.Write)))
  3092. {
  3093. new XDocument
  3094. (
  3095. new XDeclaration("1.0", "UTF-8", "yes"),
  3096. odd
  3097. ).Save(tw, SaveOptions.None);
  3098. }
  3099. }
  3100. var firstHeaderRef =
  3101. (
  3102. from e in mainDoc.Descendants(w + "headerReference")
  3103. let type = e.Attribute(w + "type")
  3104. where type != null && type.Value.Equals("first", StringComparison.CurrentCultureIgnoreCase)
  3105. select e.Attribute(r + "id").Value
  3106. ).LastOrDefault();
  3107. if (firstHeaderRef != null)
  3108. {
  3109. XElement first = headers.first.Xml;
  3110. Uri target = PackUriHelper.ResolvePartUri
  3111. (
  3112. mainPart.Uri,
  3113. mainPart.GetRelationship(firstHeaderRef).TargetUri
  3114. );
  3115. // Save header3
  3116. using (TextWriter tw = new StreamWriter(package.GetPart(target).GetStream(FileMode.Create, FileAccess.Write)))
  3117. {
  3118. new XDocument
  3119. (
  3120. new XDeclaration("1.0", "UTF-8", "yes"),
  3121. first
  3122. ).Save(tw, SaveOptions.None);
  3123. }
  3124. }
  3125. var oddFooterRef =
  3126. (
  3127. from e in mainDoc.Descendants(w + "footerReference")
  3128. let type = e.Attribute(w + "type")
  3129. where type != null && type.Value.Equals("default", StringComparison.CurrentCultureIgnoreCase)
  3130. select e.Attribute(r + "id").Value
  3131. ).LastOrDefault();
  3132. if (oddFooterRef != null)
  3133. {
  3134. XElement odd = footers.odd.Xml;
  3135. Uri target = PackUriHelper.ResolvePartUri
  3136. (
  3137. mainPart.Uri,
  3138. mainPart.GetRelationship(oddFooterRef).TargetUri
  3139. );
  3140. // Save header1
  3141. using (TextWriter tw = new StreamWriter(package.GetPart(target).GetStream(FileMode.Create, FileAccess.Write)))
  3142. {
  3143. new XDocument
  3144. (
  3145. new XDeclaration("1.0", "UTF-8", "yes"),
  3146. odd
  3147. ).Save(tw, SaveOptions.None);
  3148. }
  3149. }
  3150. var evenFooterRef =
  3151. (
  3152. from e in mainDoc.Descendants(w + "footerReference")
  3153. let type = e.Attribute(w + "type")
  3154. where type != null && type.Value.Equals("even", StringComparison.CurrentCultureIgnoreCase)
  3155. select e.Attribute(r + "id").Value
  3156. ).LastOrDefault();
  3157. if (evenFooterRef != null)
  3158. {
  3159. XElement even = footers.even.Xml;
  3160. Uri target = PackUriHelper.ResolvePartUri
  3161. (
  3162. mainPart.Uri,
  3163. mainPart.GetRelationship(evenFooterRef).TargetUri
  3164. );
  3165. // Save header2
  3166. using (TextWriter tw = new StreamWriter(package.GetPart(target).GetStream(FileMode.Create, FileAccess.Write)))
  3167. {
  3168. new XDocument
  3169. (
  3170. new XDeclaration("1.0", "UTF-8", "yes"),
  3171. even
  3172. ).Save(tw, SaveOptions.None);
  3173. }
  3174. }
  3175. var firstFooterRef =
  3176. (
  3177. from e in mainDoc.Descendants(w + "footerReference")
  3178. let type = e.Attribute(w + "type")
  3179. where type != null && type.Value.Equals("first", StringComparison.CurrentCultureIgnoreCase)
  3180. select e.Attribute(r + "id").Value
  3181. ).LastOrDefault();
  3182. if (firstFooterRef != null)
  3183. {
  3184. XElement first = footers.first.Xml;
  3185. Uri target = PackUriHelper.ResolvePartUri
  3186. (
  3187. mainPart.Uri,
  3188. mainPart.GetRelationship(firstFooterRef).TargetUri
  3189. );
  3190. // Save header3
  3191. using (TextWriter tw = new StreamWriter(package.GetPart(target).GetStream(FileMode.Create, FileAccess.Write)))
  3192. {
  3193. new XDocument
  3194. (
  3195. new XDeclaration("1.0", "UTF-8", "yes"),
  3196. first
  3197. ).Save(tw, SaveOptions.None);
  3198. }
  3199. }
  3200. // Save the settings document.
  3201. using (TextWriter tw = new StreamWriter(settingsPart.GetStream(FileMode.Create, FileAccess.Write)))
  3202. settings.Save(tw, SaveOptions.None);
  3203. if (endnotesPart != null)
  3204. {
  3205. using (TextWriter tw = new StreamWriter(endnotesPart.GetStream(FileMode.Create, FileAccess.Write)))
  3206. endnotes.Save(tw, SaveOptions.None);
  3207. }
  3208. if (footnotesPart != null)
  3209. {
  3210. using (TextWriter tw = new StreamWriter(footnotesPart.GetStream(FileMode.Create, FileAccess.Write)))
  3211. footnotes.Save(tw, SaveOptions.None);
  3212. }
  3213. if (stylesPart != null)
  3214. {
  3215. using (TextWriter tw = new StreamWriter(stylesPart.GetStream(FileMode.Create, FileAccess.Write)))
  3216. styles.Save(tw, SaveOptions.None);
  3217. }
  3218. if (stylesWithEffectsPart != null)
  3219. {
  3220. using (TextWriter tw = new StreamWriter(stylesWithEffectsPart.GetStream(FileMode.Create, FileAccess.Write)))
  3221. stylesWithEffects.Save(tw, SaveOptions.None);
  3222. }
  3223. if (numberingPart != null)
  3224. {
  3225. using (TextWriter tw = new StreamWriter(numberingPart.GetStream(FileMode.Create, FileAccess.Write)))
  3226. numbering.Save(tw, SaveOptions.None);
  3227. }
  3228. if (fontTablePart != null)
  3229. {
  3230. using (TextWriter tw = new StreamWriter(fontTablePart.GetStream(FileMode.Create, FileAccess.Write)))
  3231. fontTable.Save(tw, SaveOptions.None);
  3232. }
  3233. }
  3234. // Close the document so that it can be saved.
  3235. package.Flush();
  3236. #region Save this document back to a file or stream, that was specified by the user at save time.
  3237. if (filename != null)
  3238. {
  3239. using (FileStream fs = new FileStream(filename, FileMode.Create))
  3240. {
  3241. fs.Write(memoryStream.ToArray(), 0, (int)memoryStream.Length);
  3242. }
  3243. }
  3244. else
  3245. {
  3246. if (stream.CanSeek) // 2013-05-25: Check if stream can be seeked to support System.Web.HttpResponseStream
  3247. {
  3248. // Set the length of this stream to 0
  3249. stream.SetLength(0);
  3250. // Write to the beginning of the stream
  3251. stream.Position = 0;
  3252. }
  3253. memoryStream.WriteTo(stream);
  3254. memoryStream.Flush();
  3255. }
  3256. #endregion
  3257. }
  3258. /// <summary>
  3259. /// Save this document to a file.
  3260. /// </summary>
  3261. /// <param name="filename">The filename to save this document as.</param>
  3262. /// <example>
  3263. /// Load a document from one file and save it to another.
  3264. /// <code>
  3265. /// // Load a document using its fully qualified filename.
  3266. /// DocX document = DocX.Load(@"C:\Example\Test1.docx");
  3267. ///
  3268. /// // Insert a new Paragraph
  3269. /// document.InsertParagraph("Hello world!", false);
  3270. ///
  3271. /// // Save the document to a new location.
  3272. /// document.SaveAs(@"C:\Example\Test2.docx");
  3273. /// </code>
  3274. /// </example>
  3275. /// <example>
  3276. /// Load a document from a Stream and save it to a file.
  3277. /// <code>
  3278. /// DocX document;
  3279. /// using (FileStream fs1 = new FileStream(@"C:\Example\Test1.docx", FileMode.Open))
  3280. /// {
  3281. /// // Load a document using a stream.
  3282. /// document = DocX.Load(fs1);
  3283. ///
  3284. /// // Insert a new Paragraph
  3285. /// document.InsertParagraph("Hello world again!", false);
  3286. /// }
  3287. ///
  3288. /// // Save the document to a new location.
  3289. /// document.SaveAs(@"C:\Example\Test2.docx");
  3290. /// </code>
  3291. /// </example>
  3292. /// <seealso cref="DocX.Save()"/>
  3293. /// <seealso cref="DocX.Load(System.IO.Stream)"/>
  3294. /// <seealso cref="DocX.Load(string)"/>
  3295. public void SaveAs(string filename)
  3296. {
  3297. this.filename = filename;
  3298. this.stream = null;
  3299. Save();
  3300. }
  3301. /// <summary>
  3302. /// Save this document to a Stream.
  3303. /// </summary>
  3304. /// <param name="stream">The Stream to save this document to.</param>
  3305. /// <example>
  3306. /// Load a document from a file and save it to a Stream.
  3307. /// <code>
  3308. /// // Place holder for a document.
  3309. /// DocX document;
  3310. ///
  3311. /// using (FileStream fs1 = new FileStream(@"C:\Example\Test1.docx", FileMode.Open))
  3312. /// {
  3313. /// // Load a document using a stream.
  3314. /// document = DocX.Load(fs1);
  3315. ///
  3316. /// // Insert a new Paragraph
  3317. /// document.InsertParagraph("Hello world again!", false);
  3318. /// }
  3319. ///
  3320. /// using (FileStream fs2 = new FileStream(@"C:\Example\Test2.docx", FileMode.Create))
  3321. /// {
  3322. /// // Save the document to a different stream.
  3323. /// document.SaveAs(fs2);
  3324. /// }
  3325. ///
  3326. /// // Release this document from memory.
  3327. /// document.Dispose();
  3328. /// </code>
  3329. /// </example>
  3330. /// <example>
  3331. /// Load a document from one Stream and save it to another.
  3332. /// <code>
  3333. /// DocX document;
  3334. /// using (FileStream fs1 = new FileStream(@"C:\Example\Test1.docx", FileMode.Open))
  3335. /// {
  3336. /// // Load a document using a stream.
  3337. /// document = DocX.Load(fs1);
  3338. ///
  3339. /// // Insert a new Paragraph
  3340. /// document.InsertParagraph("Hello world again!", false);
  3341. /// }
  3342. ///
  3343. /// using (FileStream fs2 = new FileStream(@"C:\Example\Test2.docx", FileMode.Create))
  3344. /// {
  3345. /// // Save the document to a different stream.
  3346. /// document.SaveAs(fs2);
  3347. /// }
  3348. /// </code>
  3349. /// </example>
  3350. /// <seealso cref="DocX.Save()"/>
  3351. /// <seealso cref="DocX.Load(System.IO.Stream)"/>
  3352. /// <seealso cref="DocX.Load(string)"/>
  3353. public void SaveAs(Stream stream)
  3354. {
  3355. this.filename = null;
  3356. this.stream = stream;
  3357. Save();
  3358. }
  3359. /// <summary>
  3360. /// Add a core property to this document. If a core property already exists with the same name it will be replaced. Core property names are case insensitive.
  3361. /// </summary>
  3362. ///<param name="propertyName">The property name.</param>
  3363. ///<param name="propertyValue">The property value.</param>
  3364. ///<example>
  3365. /// Add a core properties of each type to a document.
  3366. /// <code>
  3367. /// // Load Example.docx
  3368. /// using (DocX document = DocX.Load(@"C:\Example\Test.docx"))
  3369. /// {
  3370. /// // If this document does not contain a core property called 'forename', create one.
  3371. /// if (!document.CoreProperties.ContainsKey("forename"))
  3372. /// {
  3373. /// // Create a new core property called 'forename' and set its value.
  3374. /// document.AddCoreProperty("forename", "Cathal");
  3375. /// }
  3376. ///
  3377. /// // Get this documents core property called 'forename'.
  3378. /// string forenameValue = document.CoreProperties["forename"];
  3379. ///
  3380. /// // Print all of the information about this core property to Console.
  3381. /// Console.WriteLine(string.Format("Name: '{0}', Value: '{1}'\nPress any key...", "forename", forenameValue));
  3382. ///
  3383. /// // Save all changes made to this document.
  3384. /// document.Save();
  3385. /// } // Release this document from memory.
  3386. ///
  3387. /// // Wait for the user to press a key before exiting.
  3388. /// Console.ReadKey();
  3389. /// </code>
  3390. /// </example>
  3391. /// <seealso cref="CoreProperties"/>
  3392. /// <seealso cref="CustomProperty"/>
  3393. /// <seealso cref="CustomProperties"/>
  3394. public void AddCoreProperty(string propertyName, string propertyValue)
  3395. {
  3396. string propertyNamespacePrefix = propertyName.Contains(":") ? propertyName.Split(new[] { ':' })[0] : "cp";
  3397. string propertyLocalName = propertyName.Contains(":") ? propertyName.Split(new[] { ':' })[1] : propertyName;
  3398. // If this document does not contain a coreFilePropertyPart create one.)
  3399. if (!package.PartExists(new Uri("/docProps/core.xml", UriKind.Relative)))
  3400. throw new Exception("Core properties part doesn't exist.");
  3401. XDocument corePropDoc;
  3402. PackagePart corePropPart = package.GetPart(new Uri("/docProps/core.xml", UriKind.Relative));
  3403. using (TextReader tr = new StreamReader(corePropPart.GetStream(FileMode.Open, FileAccess.Read)))
  3404. {
  3405. corePropDoc = XDocument.Load(tr);
  3406. }
  3407. XElement corePropElement =
  3408. (from propElement in corePropDoc.Root.Elements()
  3409. where (propElement.Name.LocalName.Equals(propertyLocalName))
  3410. select propElement).SingleOrDefault();
  3411. if (corePropElement != null)
  3412. {
  3413. corePropElement.SetValue(propertyValue);
  3414. }
  3415. else
  3416. {
  3417. var propertyNamespace = corePropDoc.Root.GetNamespaceOfPrefix(propertyNamespacePrefix);
  3418. corePropDoc.Root.Add(new XElement(XName.Get(propertyLocalName, propertyNamespace.NamespaceName), propertyValue));
  3419. }
  3420. using (TextWriter tw = new StreamWriter(corePropPart.GetStream(FileMode.Create, FileAccess.Write)))
  3421. {
  3422. corePropDoc.Save(tw);
  3423. }
  3424. UpdateCorePropertyValue(this, propertyLocalName, propertyValue);
  3425. }
  3426. internal static void UpdateCorePropertyValue(DocX document, string corePropertyName, string corePropertyValue)
  3427. {
  3428. string matchPattern = string.Format(@"(DOCPROPERTY)?{0}\\\*MERGEFORMAT", corePropertyName).ToLower();
  3429. foreach (XElement e in document.mainDoc.Descendants(XName.Get("fldSimple", w.NamespaceName)))
  3430. {
  3431. string attr_value = e.Attribute(XName.Get("instr", w.NamespaceName)).Value.Replace(" ", string.Empty).Trim().ToLower();
  3432. if (Regex.IsMatch(attr_value, matchPattern))
  3433. {
  3434. XElement firstRun = e.Element(w + "r");
  3435. XElement firstText = firstRun.Element(w + "t");
  3436. XElement rPr = firstText.Element(w + "rPr");
  3437. // Delete everything and insert updated text value
  3438. e.RemoveNodes();
  3439. XElement t = new XElement(w + "t", rPr, corePropertyValue);
  3440. Novacode.Text.PreserveSpace(t);
  3441. e.Add(new XElement(firstRun.Name, firstRun.Attributes(), firstRun.Element(XName.Get("rPr", w.NamespaceName)), t));
  3442. }
  3443. }
  3444. #region Headers
  3445. IEnumerable<PackagePart> headerParts = from headerPart in document.package.GetParts()
  3446. where (Regex.IsMatch(headerPart.Uri.ToString(), @"/word/header\d?.xml"))
  3447. select headerPart;
  3448. foreach (PackagePart pp in headerParts)
  3449. {
  3450. XDocument header = XDocument.Load(new StreamReader(pp.GetStream()));
  3451. foreach (XElement e in header.Descendants(XName.Get("fldSimple", w.NamespaceName)))
  3452. {
  3453. string attr_value = e.Attribute(XName.Get("instr", w.NamespaceName)).Value.Replace(" ", string.Empty).Trim().ToLower();
  3454. if (Regex.IsMatch(attr_value, matchPattern))
  3455. {
  3456. XElement firstRun = e.Element(w + "r");
  3457. // Delete everything and insert updated text value
  3458. e.RemoveNodes();
  3459. XElement t = new XElement(w + "t", corePropertyValue);
  3460. Novacode.Text.PreserveSpace(t);
  3461. e.Add(new XElement(firstRun.Name, firstRun.Attributes(), firstRun.Element(XName.Get("rPr", w.NamespaceName)), t));
  3462. }
  3463. }
  3464. using (TextWriter tw = new StreamWriter(pp.GetStream(FileMode.Create, FileAccess.Write)))
  3465. header.Save(tw);
  3466. }
  3467. #endregion
  3468. #region Footers
  3469. IEnumerable<PackagePart> footerParts = from footerPart in document.package.GetParts()
  3470. where (Regex.IsMatch(footerPart.Uri.ToString(), @"/word/footer\d?.xml"))
  3471. select footerPart;
  3472. foreach (PackagePart pp in footerParts)
  3473. {
  3474. XDocument footer = XDocument.Load(new StreamReader(pp.GetStream()));
  3475. foreach (XElement e in footer.Descendants(XName.Get("fldSimple", w.NamespaceName)))
  3476. {
  3477. string attr_value = e.Attribute(XName.Get("instr", w.NamespaceName)).Value.Replace(" ", string.Empty).Trim().ToLower();
  3478. if (Regex.IsMatch(attr_value, matchPattern))
  3479. {
  3480. XElement firstRun = e.Element(w + "r");
  3481. // Delete everything and insert updated text value
  3482. e.RemoveNodes();
  3483. XElement t = new XElement(w + "t", corePropertyValue);
  3484. Novacode.Text.PreserveSpace(t);
  3485. e.Add(new XElement(firstRun.Name, firstRun.Attributes(), firstRun.Element(XName.Get("rPr", w.NamespaceName)), t));
  3486. }
  3487. }
  3488. using (TextWriter tw = new StreamWriter(pp.GetStream(FileMode.Create, FileAccess.Write)))
  3489. footer.Save(tw);
  3490. }
  3491. #endregion
  3492. PopulateDocument(document, document.package);
  3493. }
  3494. /// <summary>
  3495. /// 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.
  3496. /// </summary>
  3497. /// <param name="cp">The CustomProperty to add to this document.</param>
  3498. /// <example>
  3499. /// Add a custom properties of each type to a document.
  3500. /// <code>
  3501. /// // Load Example.docx
  3502. /// using (DocX document = DocX.Load(@"C:\Example\Test.docx"))
  3503. /// {
  3504. /// // A CustomProperty called forename which stores a string.
  3505. /// CustomProperty forename;
  3506. ///
  3507. /// // If this document does not contain a custom property called 'forename', create one.
  3508. /// if (!document.CustomProperties.ContainsKey("forename"))
  3509. /// {
  3510. /// // Create a new custom property called 'forename' and set its value.
  3511. /// document.AddCustomProperty(new CustomProperty("forename", "Cathal"));
  3512. /// }
  3513. ///
  3514. /// // Get this documents custom property called 'forename'.
  3515. /// forename = document.CustomProperties["forename"];
  3516. ///
  3517. /// // Print all of the information about this CustomProperty to Console.
  3518. /// Console.WriteLine(string.Format("Name: '{0}', Value: '{1}'\nPress any key...", forename.Name, forename.Value));
  3519. ///
  3520. /// // Save all changes made to this document.
  3521. /// document.Save();
  3522. /// } // Release this document from memory.
  3523. ///
  3524. /// // Wait for the user to press a key before exiting.
  3525. /// Console.ReadKey();
  3526. /// </code>
  3527. /// </example>
  3528. /// <seealso cref="CustomProperty"/>
  3529. /// <seealso cref="CustomProperties"/>
  3530. public void AddCustomProperty(CustomProperty cp)
  3531. {
  3532. // If this document does not contain a customFilePropertyPart create one.
  3533. if (!package.PartExists(new Uri("/docProps/custom.xml", UriKind.Relative)))
  3534. HelperFunctions.CreateCustomPropertiesPart(this);
  3535. XDocument customPropDoc;
  3536. PackagePart customPropPart = package.GetPart(new Uri("/docProps/custom.xml", UriKind.Relative));
  3537. using (TextReader tr = new StreamReader(customPropPart.GetStream(FileMode.Open, FileAccess.Read)))
  3538. customPropDoc = XDocument.Load(tr, LoadOptions.PreserveWhitespace);
  3539. // Each custom property has a PID, get the highest PID in this document.
  3540. IEnumerable<int> pids =
  3541. (
  3542. from d in customPropDoc.Descendants()
  3543. where d.Name.LocalName == "property"
  3544. select int.Parse(d.Attribute(XName.Get("pid")).Value)
  3545. );
  3546. int pid = 1;
  3547. if (pids.Count() > 0)
  3548. pid = pids.Max();
  3549. // Check if a custom property already exists with this name
  3550. // 2013-05-25: IgnoreCase while searching for custom property as it would produce a currupted docx.
  3551. var customProperty =
  3552. (
  3553. from d in customPropDoc.Descendants()
  3554. where (d.Name.LocalName == "property") && (d.Attribute(XName.Get("name")).Value.Equals(cp.Name, StringComparison.InvariantCultureIgnoreCase))
  3555. select d
  3556. ).SingleOrDefault();
  3557. // If a custom property with this name already exists remove it.
  3558. if (customProperty != null)
  3559. customProperty.Remove();
  3560. XElement propertiesElement = customPropDoc.Element(XName.Get("Properties", customPropertiesSchema.NamespaceName));
  3561. propertiesElement.Add
  3562. (
  3563. new XElement
  3564. (
  3565. XName.Get("property", customPropertiesSchema.NamespaceName),
  3566. new XAttribute("fmtid", "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"),
  3567. new XAttribute("pid", pid + 1),
  3568. new XAttribute("name", cp.Name),
  3569. new XElement(customVTypesSchema + cp.Type, cp.Value ?? "")
  3570. )
  3571. );
  3572. // Save the custom properties
  3573. using (TextWriter tw = new StreamWriter(customPropPart.GetStream(FileMode.Create, FileAccess.Write)))
  3574. customPropDoc.Save(tw, SaveOptions.None);
  3575. // Refresh all fields in this document which display this custom property.
  3576. UpdateCustomPropertyValue(this, cp.Name, (cp.Value ?? "").ToString());
  3577. }
  3578. /// <summary>
  3579. /// Update the custom properties inside the document
  3580. /// </summary>
  3581. /// <param name="document">The DocX document</param>
  3582. /// <param name="customPropertyName">The property used inside the document</param>
  3583. /// <param name="customPropertyValue">The new value for the property</param>
  3584. /// <remarks>Different version of Word create different Document XML.</remarks>
  3585. internal static void UpdateCustomPropertyValue(DocX document, string customPropertyName, string customPropertyValue)
  3586. {
  3587. // A list of documents, which will contain, The Main Document and if they exist: header1, header2, header3, footer1, footer2, footer3.
  3588. List<XElement> documents = new List<XElement> { document.mainDoc.Root };
  3589. // Check if each header exists and add if if so.
  3590. #region Headers
  3591. Headers headers = document.Headers;
  3592. if (headers.first != null)
  3593. documents.Add(headers.first.Xml);
  3594. if (headers.odd != null)
  3595. documents.Add(headers.odd.Xml);
  3596. if (headers.even != null)
  3597. documents.Add(headers.even.Xml);
  3598. #endregion
  3599. // Check if each footer exists and add if if so.
  3600. #region Footers
  3601. Footers footers = document.Footers;
  3602. if (footers.first != null)
  3603. documents.Add(footers.first.Xml);
  3604. if (footers.odd != null)
  3605. documents.Add(footers.odd.Xml);
  3606. if (footers.even != null)
  3607. documents.Add(footers.even.Xml);
  3608. #endregion
  3609. // Process each document in the list.
  3610. foreach (XElement doc in documents)
  3611. {
  3612. #region Word 2010+
  3613. foreach (XElement e in doc.Descendants(XName.Get("instrText", w.NamespaceName)))
  3614. {
  3615. string attr_value = e.Value.Replace(" ", string.Empty).Trim();
  3616. string match_value = string.Format(@"DOCPROPERTY {0} \* MERGEFORMAT", customPropertyName).Replace(" ", string.Empty);
  3617. if (attr_value.Equals(match_value, StringComparison.CurrentCultureIgnoreCase))
  3618. {
  3619. XNode node = e.Parent.NextNode;
  3620. bool found = false;
  3621. while (true)
  3622. {
  3623. if (node.NodeType == XmlNodeType.Element)
  3624. {
  3625. var ele = node as XElement;
  3626. var match = ele.Descendants(XName.Get("t", w.NamespaceName));
  3627. if (match.Count() > 0)
  3628. {
  3629. if (!found)
  3630. {
  3631. match.First().Value = customPropertyValue;
  3632. found = true;
  3633. }
  3634. else
  3635. {
  3636. ele.RemoveNodes();
  3637. }
  3638. }
  3639. else
  3640. {
  3641. match = ele.Descendants(XName.Get("fldChar", w.NamespaceName));
  3642. if (match.Count() > 0)
  3643. {
  3644. var endMatch = match.First().Attribute(XName.Get("fldCharType", w.NamespaceName));
  3645. if (endMatch != null && endMatch.Value == "end")
  3646. {
  3647. break;
  3648. }
  3649. }
  3650. }
  3651. }
  3652. node = node.NextNode;
  3653. }
  3654. }
  3655. }
  3656. #endregion
  3657. #region < Word 2010
  3658. foreach (XElement e in doc.Descendants(XName.Get("fldSimple", w.NamespaceName)))
  3659. {
  3660. string attr_value = e.Attribute(XName.Get("instr", w.NamespaceName)).Value.Replace(" ", string.Empty).Trim();
  3661. string match_value = string.Format(@"DOCPROPERTY {0} \* MERGEFORMAT", customPropertyName).Replace(" ", string.Empty);
  3662. if (attr_value.Equals(match_value, StringComparison.CurrentCultureIgnoreCase))
  3663. {
  3664. XElement firstRun = e.Element(w + "r");
  3665. XElement firstText = firstRun.Element(w + "t");
  3666. XElement rPr = firstText.Element(w + "rPr");
  3667. // Delete everything and insert updated text value
  3668. e.RemoveNodes();
  3669. XElement t = new XElement(w + "t", rPr, customPropertyValue);
  3670. Novacode.Text.PreserveSpace(t);
  3671. e.Add(new XElement(firstRun.Name, firstRun.Attributes(), firstRun.Element(XName.Get("rPr", w.NamespaceName)), t));
  3672. }
  3673. }
  3674. #endregion
  3675. }
  3676. }
  3677. public override Paragraph InsertParagraph()
  3678. {
  3679. Paragraph p = base.InsertParagraph();
  3680. p.PackagePart = mainPart;
  3681. return p;
  3682. }
  3683. public override Paragraph InsertParagraph(int index, string text, bool trackChanges)
  3684. {
  3685. Paragraph p = base.InsertParagraph(index, text, trackChanges);
  3686. p.PackagePart = mainPart;
  3687. return p;
  3688. }
  3689. public override Paragraph InsertParagraph(Paragraph p)
  3690. {
  3691. p.PackagePart = mainPart;
  3692. return base.InsertParagraph(p);
  3693. }
  3694. public override Paragraph InsertParagraph(int index, Paragraph p)
  3695. {
  3696. p.PackagePart = mainPart;
  3697. return base.InsertParagraph(index, p);
  3698. }
  3699. public override Paragraph InsertParagraph(int index, string text, bool trackChanges, Formatting formatting)
  3700. {
  3701. Paragraph p = base.InsertParagraph(index, text, trackChanges, formatting);
  3702. p.PackagePart = mainPart;
  3703. return p;
  3704. }
  3705. public override Paragraph InsertParagraph(string text)
  3706. {
  3707. Paragraph p = base.InsertParagraph(text);
  3708. p.PackagePart = mainPart;
  3709. return p;
  3710. }
  3711. public override Paragraph InsertParagraph(string text, bool trackChanges)
  3712. {
  3713. Paragraph p = base.InsertParagraph(text, trackChanges);
  3714. p.PackagePart = mainPart;
  3715. return p;
  3716. }
  3717. public override Paragraph InsertParagraph(string text, bool trackChanges, Formatting formatting)
  3718. {
  3719. Paragraph p = base.InsertParagraph(text, trackChanges, formatting);
  3720. p.PackagePart = mainPart;
  3721. return p;
  3722. }
  3723. public Paragraph[] InsertParagraphs(string text)
  3724. {
  3725. String[] textArray = text.Split('\n');
  3726. List<Paragraph> paragraphs = new List<Paragraph>();
  3727. foreach (var textForParagraph in textArray)
  3728. {
  3729. Paragraph p = base.InsertParagraph(text);
  3730. p.PackagePart = mainPart;
  3731. paragraphs.Add(p);
  3732. }
  3733. return paragraphs.ToArray();
  3734. }
  3735. public override ReadOnlyCollection<Paragraph> Paragraphs
  3736. {
  3737. get
  3738. {
  3739. ReadOnlyCollection<Paragraph> l = base.Paragraphs;
  3740. foreach (var paragraph in l)
  3741. {
  3742. paragraph.PackagePart = mainPart;
  3743. }
  3744. return l;
  3745. }
  3746. }
  3747. public override List<List> Lists
  3748. {
  3749. get
  3750. {
  3751. List<List> l = base.Lists;
  3752. l.ForEach(x => x.Items.ForEach(i => i.PackagePart = mainPart));
  3753. return l;
  3754. }
  3755. }
  3756. public override List<Table> Tables
  3757. {
  3758. get
  3759. {
  3760. List<Table> l = base.Tables;
  3761. l.ForEach(x => x.mainPart = mainPart);
  3762. return l;
  3763. }
  3764. }
  3765. /// <summary>
  3766. /// Create an equation and insert it in the new paragraph
  3767. /// </summary>
  3768. public override Paragraph InsertEquation(String equation)
  3769. {
  3770. Paragraph p = base.InsertEquation(equation);
  3771. p.PackagePart = mainPart;
  3772. return p;
  3773. }
  3774. /// <summary>
  3775. /// Insert a chart in document
  3776. /// </summary>
  3777. public void InsertChart(Chart chart)
  3778. {
  3779. // Create a new chart part uri.
  3780. String chartPartUriPath = String.Empty;
  3781. Int32 chartIndex = 1;
  3782. do
  3783. {
  3784. chartPartUriPath = String.Format
  3785. (
  3786. "/word/charts/chart{0}.xml",
  3787. chartIndex
  3788. );
  3789. chartIndex++;
  3790. } while (package.PartExists(new Uri(chartPartUriPath, UriKind.Relative)));
  3791. // Create chart part.
  3792. PackagePart chartPackagePart = package.CreatePart(new Uri(chartPartUriPath, UriKind.Relative), "application/vnd.openxmlformats-officedocument.drawingml.chart+xml", CompressionOption.Normal);
  3793. // Create a new chart relationship
  3794. String relID = GetNextFreeRelationshipID();
  3795. PackageRelationship rel = mainPart.CreateRelationship(chartPackagePart.Uri, TargetMode.Internal, "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart", relID);
  3796. // Save a chart info the chartPackagePart
  3797. using (TextWriter tw = new StreamWriter(chartPackagePart.GetStream(FileMode.Create, FileAccess.Write)))
  3798. chart.Xml.Save(tw);
  3799. // Insert a new chart into a paragraph.
  3800. Paragraph p = InsertParagraph();
  3801. XElement chartElement = new XElement(
  3802. XName.Get("r", DocX.w.NamespaceName),
  3803. new XElement(
  3804. XName.Get("drawing", DocX.w.NamespaceName),
  3805. new XElement(
  3806. XName.Get("inline", DocX.wp.NamespaceName),
  3807. new XElement(XName.Get("extent", DocX.wp.NamespaceName), new XAttribute("cx", "5486400"), new XAttribute("cy", "3200400")),
  3808. new XElement(XName.Get("effectExtent", DocX.wp.NamespaceName), new XAttribute("l", "0"), new XAttribute("t", "0"), new XAttribute("r", "19050"), new XAttribute("b", "19050")),
  3809. new XElement(XName.Get("docPr", DocX.wp.NamespaceName), new XAttribute("id", "1"), new XAttribute("name", "chart")),
  3810. new XElement(
  3811. XName.Get("graphic", DocX.a.NamespaceName),
  3812. new XElement(
  3813. XName.Get("graphicData", DocX.a.NamespaceName),
  3814. new XAttribute("uri", DocX.c.NamespaceName),
  3815. new XElement(
  3816. XName.Get("chart", DocX.c.NamespaceName),
  3817. new XAttribute(XName.Get("id", DocX.r.NamespaceName), relID)
  3818. )
  3819. )
  3820. )
  3821. )
  3822. ));
  3823. p.Xml.Add(chartElement);
  3824. }
  3825. /// <summary>
  3826. /// Inserts a default TOC into the current document.
  3827. /// Title: Table of contents
  3828. /// Swithces will be: TOC \h \o '1-3' \u \z
  3829. /// </summary>
  3830. /// <returns>The inserted TableOfContents</returns>
  3831. public TableOfContents InsertDefaultTableOfContents()
  3832. {
  3833. return InsertTableOfContents("Table of contents", TableOfContentsSwitches.O | TableOfContentsSwitches.H | TableOfContentsSwitches.Z | TableOfContentsSwitches.U);
  3834. }
  3835. /// <summary>
  3836. /// Inserts a TOC into the current document.
  3837. /// </summary>
  3838. /// <param name="title">The title of the TOC</param>
  3839. /// <param name="switches">Switches to be applied, see: http://officeopenxml.com/WPtableOfContents.php </param>
  3840. /// <param name="headerStyle">Lets you set the style name of the TOC header</param>
  3841. /// <param name="maxIncludeLevel">Lets you specify how many header levels should be included - default is 1-3</param>
  3842. /// <param name="rightTabPos">Lets you override the right tab position - this is not common</param>
  3843. /// <returns>The inserted TableOfContents</returns>
  3844. public TableOfContents InsertTableOfContents(string title, TableOfContentsSwitches switches, string headerStyle = null, int maxIncludeLevel = 3, int? rightTabPos = null)
  3845. {
  3846. var toc = TableOfContents.CreateTableOfContents(this, title, switches, headerStyle, maxIncludeLevel, rightTabPos);
  3847. Xml.Add(toc.Xml);
  3848. return toc;
  3849. }
  3850. /// <summary>
  3851. /// Inserts at TOC into the current document before the provided <paramref name="reference"/>
  3852. /// </summary>
  3853. /// <param name="reference">The paragraph to use as reference</param>
  3854. /// <param name="title">The title of the TOC</param>
  3855. /// <param name="switches">Switches to be applied, see: http://officeopenxml.com/WPtableOfContents.php </param>
  3856. /// <param name="headerStyle">Lets you set the style name of the TOC header</param>
  3857. /// <param name="maxIncludeLevel">Lets you specify how many header levels should be included - default is 1-3</param>
  3858. /// <param name="rightTabPos">Lets you override the right tab position - this is not common</param>
  3859. /// <returns>The inserted TableOfContents</returns>
  3860. public TableOfContents InsertTableOfContents(Paragraph reference, string title, TableOfContentsSwitches switches, string headerStyle = null, int maxIncludeLevel = 3, int? rightTabPos = null)
  3861. {
  3862. var toc = TableOfContents.CreateTableOfContents(this, title, switches, headerStyle, maxIncludeLevel, rightTabPos);
  3863. reference.Xml.AddBeforeSelf(toc.Xml);
  3864. return toc;
  3865. }
  3866. #region IDisposable Members
  3867. /// <summary>
  3868. /// Releases all resources used by this document.
  3869. /// </summary>
  3870. /// <example>
  3871. /// If you take advantage of the using keyword, Dispose() is automatically called for you.
  3872. /// <code>
  3873. /// // Load document.
  3874. /// using (DocX document = DocX.Load(@"C:\Example\Test.docx"))
  3875. /// {
  3876. /// // The document is only in memory while in this scope.
  3877. ///
  3878. /// }// Dispose() is automatically called at this point.
  3879. /// </code>
  3880. /// </example>
  3881. /// <example>
  3882. /// This example is equilivant to the one above example.
  3883. /// <code>
  3884. /// // Load document.
  3885. /// DocX document = DocX.Load(@"C:\Example\Test.docx");
  3886. ///
  3887. /// // Do something with the document here.
  3888. ///
  3889. /// // Dispose of the document.
  3890. /// document.Dispose();
  3891. /// </code>
  3892. /// </example>
  3893. public void Dispose()
  3894. {
  3895. package.Close();
  3896. }
  3897. #endregion
  3898. }
  3899. }