DocumentBuilder.cs 212 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047
  1. // Copyright (c) Microsoft. All rights reserved.
  2. // Licensed under the MIT license. See LICENSE file in the project root for full license information.
  3. #define TestForUnsupportedDocuments
  4. #define MergeStylesWithSameNames
  5. using System;
  6. using System.Collections.Generic;
  7. using System.IO;
  8. using System.Linq;
  9. using System.Xml.Linq;
  10. using DocumentFormat.OpenXml.Packaging;
  11. namespace OpenXmlPowerTools
  12. {
  13. public partial class WmlDocument : OpenXmlPowerToolsDocument
  14. {
  15. public IEnumerable<WmlDocument> SplitOnSections()
  16. {
  17. return DocumentBuilder.SplitOnSections(this);
  18. }
  19. }
  20. public class Source
  21. {
  22. public WmlDocument WmlDocument { get; set; }
  23. public int Start { get; set; }
  24. public int Count { get; set; }
  25. public bool KeepSections { get; set; }
  26. public bool DiscardHeadersAndFootersInKeptSections { get; set; }
  27. public string InsertId { get; set; }
  28. public Source(string fileName)
  29. {
  30. WmlDocument = new WmlDocument(fileName);
  31. Start = 0;
  32. Count = Int32.MaxValue;
  33. KeepSections = false;
  34. InsertId = null;
  35. }
  36. public Source(WmlDocument source)
  37. {
  38. WmlDocument = source;
  39. Start = 0;
  40. Count = Int32.MaxValue;
  41. KeepSections = false;
  42. InsertId = null;
  43. }
  44. public Source(string fileName, bool keepSections)
  45. {
  46. WmlDocument = new WmlDocument(fileName);
  47. Start = 0;
  48. Count = Int32.MaxValue;
  49. KeepSections = keepSections;
  50. InsertId = null;
  51. }
  52. public Source(WmlDocument source, bool keepSections)
  53. {
  54. WmlDocument = source;
  55. Start = 0;
  56. Count = Int32.MaxValue;
  57. KeepSections = keepSections;
  58. InsertId = null;
  59. }
  60. public Source(string fileName, string insertId)
  61. {
  62. WmlDocument = new WmlDocument(fileName);
  63. Start = 0;
  64. Count = Int32.MaxValue;
  65. KeepSections = false;
  66. InsertId = insertId;
  67. }
  68. public Source(WmlDocument source, string insertId)
  69. {
  70. WmlDocument = source;
  71. Start = 0;
  72. Count = Int32.MaxValue;
  73. KeepSections = false;
  74. InsertId = insertId;
  75. }
  76. public Source(string fileName, int start, bool keepSections)
  77. {
  78. WmlDocument = new WmlDocument(fileName);
  79. Start = start;
  80. Count = Int32.MaxValue;
  81. KeepSections = keepSections;
  82. InsertId = null;
  83. }
  84. public Source(WmlDocument source, int start, bool keepSections)
  85. {
  86. WmlDocument = source;
  87. Start = start;
  88. Count = Int32.MaxValue;
  89. KeepSections = keepSections;
  90. InsertId = null;
  91. }
  92. public Source(string fileName, int start, string insertId)
  93. {
  94. WmlDocument = new WmlDocument(fileName);
  95. Start = start;
  96. Count = Int32.MaxValue;
  97. KeepSections = false;
  98. InsertId = insertId;
  99. }
  100. public Source(WmlDocument source, int start, string insertId)
  101. {
  102. WmlDocument = source;
  103. Start = start;
  104. Count = Int32.MaxValue;
  105. KeepSections = false;
  106. InsertId = insertId;
  107. }
  108. public Source(string fileName, int start, int count, bool keepSections)
  109. {
  110. WmlDocument = new WmlDocument(fileName);
  111. Start = start;
  112. Count = count;
  113. KeepSections = keepSections;
  114. InsertId = null;
  115. }
  116. public Source(WmlDocument source, int start, int count, bool keepSections)
  117. {
  118. WmlDocument = source;
  119. Start = start;
  120. Count = count;
  121. KeepSections = keepSections;
  122. InsertId = null;
  123. }
  124. public Source(string fileName, int start, int count, string insertId)
  125. {
  126. WmlDocument = new WmlDocument(fileName);
  127. Start = start;
  128. Count = count;
  129. KeepSections = false;
  130. InsertId = insertId;
  131. }
  132. public Source(WmlDocument source, int start, int count, string insertId)
  133. {
  134. WmlDocument = source;
  135. Start = start;
  136. Count = count;
  137. KeepSections = false;
  138. InsertId = insertId;
  139. }
  140. }
  141. public class DocumentBuilderSettings
  142. {
  143. public HashSet<string> CustomXmlGuidList = null;
  144. public bool NormalizeStyleIds = false;
  145. }
  146. public static class DocumentBuilder
  147. {
  148. public static void BuildDocument(List<Source> sources, string fileName)
  149. {
  150. using (OpenXmlMemoryStreamDocument streamDoc = OpenXmlMemoryStreamDocument.CreateWordprocessingDocument())
  151. {
  152. using (WordprocessingDocument output = streamDoc.GetWordprocessingDocument())
  153. {
  154. BuildDocument(sources, output, new DocumentBuilderSettings());
  155. output.Close();
  156. }
  157. streamDoc.GetModifiedDocument().SaveAs(fileName);
  158. }
  159. }
  160. public static void BuildDocument(List<Source> sources, string fileName, DocumentBuilderSettings settings)
  161. {
  162. using (OpenXmlMemoryStreamDocument streamDoc = OpenXmlMemoryStreamDocument.CreateWordprocessingDocument())
  163. {
  164. using (WordprocessingDocument output = streamDoc.GetWordprocessingDocument())
  165. {
  166. BuildDocument(sources, output, settings);
  167. output.Close();
  168. }
  169. streamDoc.GetModifiedDocument().SaveAs(fileName);
  170. }
  171. }
  172. public static WmlDocument BuildDocument(List<Source> sources)
  173. {
  174. using (OpenXmlMemoryStreamDocument streamDoc = OpenXmlMemoryStreamDocument.CreateWordprocessingDocument())
  175. {
  176. using (WordprocessingDocument output = streamDoc.GetWordprocessingDocument())
  177. {
  178. BuildDocument(sources, output, new DocumentBuilderSettings());
  179. output.Close();
  180. }
  181. return streamDoc.GetModifiedWmlDocument();
  182. }
  183. }
  184. public static WmlDocument BuildDocument(List<Source> sources, DocumentBuilderSettings settings)
  185. {
  186. using (OpenXmlMemoryStreamDocument streamDoc = OpenXmlMemoryStreamDocument.CreateWordprocessingDocument())
  187. {
  188. using (WordprocessingDocument output = streamDoc.GetWordprocessingDocument())
  189. {
  190. BuildDocument(sources, output, settings);
  191. output.Close();
  192. }
  193. return streamDoc.GetModifiedWmlDocument();
  194. }
  195. }
  196. private struct TempSource
  197. {
  198. public int Start;
  199. public int Count;
  200. };
  201. private class Atbi
  202. {
  203. public XElement BlockLevelContent;
  204. public int Index;
  205. }
  206. private class Atbid
  207. {
  208. public XElement BlockLevelContent;
  209. public int Index;
  210. public int Div;
  211. }
  212. private const string Yes = "yes";
  213. private const string Utf8 = "UTF-8";
  214. private const string OnePointZero = "1.0";
  215. public static IEnumerable<WmlDocument> SplitOnSections(WmlDocument doc)
  216. {
  217. List<TempSource> tempSourceList;
  218. using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
  219. using (WordprocessingDocument document = streamDoc.GetWordprocessingDocument())
  220. {
  221. XDocument mainDocument = document.MainDocumentPart.GetXDocument();
  222. var divs = mainDocument
  223. .Root
  224. .Element(W.body)
  225. .Elements()
  226. .Select((p, i) => new Atbi
  227. {
  228. BlockLevelContent = p,
  229. Index = i,
  230. })
  231. .Rollup(new Atbid
  232. {
  233. BlockLevelContent = (XElement)null,
  234. Index = -1,
  235. Div = 0,
  236. },
  237. (b, p) =>
  238. {
  239. XElement elementBefore = b.BlockLevelContent
  240. .SiblingsBeforeSelfReverseDocumentOrder()
  241. .FirstOrDefault();
  242. if (elementBefore != null && elementBefore.Descendants(W.sectPr).Any())
  243. return new Atbid
  244. {
  245. BlockLevelContent = b.BlockLevelContent,
  246. Index = b.Index,
  247. Div = p.Div + 1,
  248. };
  249. return new Atbid
  250. {
  251. BlockLevelContent = b.BlockLevelContent,
  252. Index = b.Index,
  253. Div = p.Div,
  254. };
  255. });
  256. var groups = divs
  257. .GroupAdjacent(b => b.Div);
  258. tempSourceList = groups
  259. .Select(g => new TempSource
  260. {
  261. Start = g.First().Index,
  262. Count = g.Count(),
  263. })
  264. .ToList();
  265. foreach (var ts in tempSourceList)
  266. {
  267. List<Source> sources = new List<Source>()
  268. {
  269. new Source(doc, ts.Start, ts.Count, true)
  270. };
  271. WmlDocument newDoc = DocumentBuilder.BuildDocument(sources);
  272. newDoc = AdjustSectionBreak(newDoc);
  273. yield return newDoc;
  274. }
  275. }
  276. }
  277. private static WmlDocument AdjustSectionBreak(WmlDocument doc)
  278. {
  279. using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(doc))
  280. {
  281. using (WordprocessingDocument document = streamDoc.GetWordprocessingDocument())
  282. {
  283. XDocument mainXDoc = document.MainDocumentPart.GetXDocument();
  284. XElement lastElement = mainXDoc.Root
  285. .Element(W.body)
  286. .Elements()
  287. .LastOrDefault();
  288. if (lastElement != null)
  289. {
  290. if (lastElement.Name != W.sectPr &&
  291. lastElement.Descendants(W.sectPr).Any())
  292. {
  293. mainXDoc.Root.Element(W.body).Add(lastElement.Descendants(W.sectPr).First());
  294. lastElement.Descendants(W.sectPr).Remove();
  295. if (!lastElement.Elements()
  296. .Where(e => e.Name != W.pPr)
  297. .Any())
  298. lastElement.Remove();
  299. document.MainDocumentPart.PutXDocument();
  300. }
  301. }
  302. }
  303. return streamDoc.GetModifiedWmlDocument();
  304. }
  305. }
  306. private static void BuildDocument(List<Source> sources, WordprocessingDocument output, DocumentBuilderSettings settings)
  307. {
  308. WmlDocument wmlGlossaryDocument = CoalesceGlossaryDocumentParts(sources, settings);
  309. if (RelationshipMarkup == null)
  310. InitRelationshipMarkup();
  311. // This list is used to eliminate duplicate images
  312. List<ImageData> images = new List<ImageData>();
  313. XDocument mainPart = output.MainDocumentPart.GetXDocument();
  314. mainPart.Declaration.Standalone = Yes;
  315. mainPart.Declaration.Encoding = Utf8;
  316. mainPart.Root.ReplaceWith(
  317. new XElement(W.document, NamespaceAttributes,
  318. new XElement(W.body)));
  319. if (sources.Count > 0)
  320. {
  321. // the following function makes sure that for a given style name, the same style ID is used for all documents.
  322. if (settings != null && settings.NormalizeStyleIds)
  323. sources = NormalizeStyleNamesAndIds(sources);
  324. using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(sources[0].WmlDocument))
  325. using (WordprocessingDocument doc = streamDoc.GetWordprocessingDocument())
  326. {
  327. CopyStartingParts(doc, output, images);
  328. CopySpecifiedCustomXmlParts(doc, output, settings);
  329. }
  330. int sourceNum2 = 0;
  331. foreach (Source source in sources)
  332. {
  333. if (source.InsertId != null)
  334. {
  335. while (true)
  336. {
  337. #if false
  338. modify AppendDocument so that it can take a part.
  339. for each in main document part, header parts, footer parts
  340. are there any PtOpenXml.Insert elements in any of them?
  341. if so, then open and process all.
  342. #endif
  343. bool foundInMainDocPart = false;
  344. XDocument mainXDoc = output.MainDocumentPart.GetXDocument();
  345. if (mainXDoc.Descendants(PtOpenXml.Insert).Any(d => (string)d.Attribute(PtOpenXml.Id) == source.InsertId))
  346. foundInMainDocPart = true;
  347. if (foundInMainDocPart)
  348. {
  349. using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(source.WmlDocument))
  350. using (WordprocessingDocument doc = streamDoc.GetWordprocessingDocument())
  351. {
  352. #if TestForUnsupportedDocuments
  353. // throws exceptions if a document contains unsupported content
  354. TestForUnsupportedDocument(doc, sources.IndexOf(source));
  355. #endif
  356. if (foundInMainDocPart)
  357. {
  358. if (source.KeepSections && source.DiscardHeadersAndFootersInKeptSections)
  359. RemoveHeadersAndFootersFromSections(doc);
  360. else if (source.KeepSections)
  361. ProcessSectionsForLinkToPreviousHeadersAndFooters(doc);
  362. List<XElement> contents = doc.MainDocumentPart.GetXDocument()
  363. .Root
  364. .Element(W.body)
  365. .Elements()
  366. .Skip(source.Start)
  367. .Take(source.Count)
  368. .ToList();
  369. try
  370. {
  371. AppendDocument(doc, output, contents, source.KeepSections, source.InsertId, images);
  372. }
  373. catch (DocumentBuilderInternalException dbie)
  374. {
  375. if (dbie.Message.Contains("{0}"))
  376. throw new DocumentBuilderException(string.Format(dbie.Message, sourceNum2));
  377. else
  378. throw dbie;
  379. }
  380. }
  381. }
  382. }
  383. else
  384. break;
  385. }
  386. }
  387. else
  388. {
  389. using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(source.WmlDocument))
  390. using (WordprocessingDocument doc = streamDoc.GetWordprocessingDocument())
  391. {
  392. #if TestForUnsupportedDocuments
  393. // throws exceptions if a document contains unsupported content
  394. TestForUnsupportedDocument(doc, sources.IndexOf(source));
  395. #endif
  396. if (source.KeepSections && source.DiscardHeadersAndFootersInKeptSections)
  397. RemoveHeadersAndFootersFromSections(doc);
  398. else if (source.KeepSections)
  399. ProcessSectionsForLinkToPreviousHeadersAndFooters(doc);
  400. var body = doc.MainDocumentPart.GetXDocument()
  401. .Root
  402. .Element(W.body);
  403. if (body == null)
  404. throw new DocumentBuilderException(
  405. String.Format("Source {0} is unsupported document - contains no body element in the correct namespace", sourceNum2));
  406. List<XElement> contents = body
  407. .Elements()
  408. .Skip(source.Start)
  409. .Take(source.Count)
  410. .ToList();
  411. try
  412. {
  413. AppendDocument(doc, output, contents, source.KeepSections, null, images);
  414. }
  415. catch (DocumentBuilderInternalException dbie)
  416. {
  417. if (dbie.Message.Contains("{0}"))
  418. throw new DocumentBuilderException(string.Format(dbie.Message, sourceNum2));
  419. else
  420. throw dbie;
  421. }
  422. }
  423. }
  424. ++sourceNum2;
  425. }
  426. if (!sources.Any(s => s.KeepSections))
  427. {
  428. using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(sources[0].WmlDocument))
  429. using (WordprocessingDocument doc = streamDoc.GetWordprocessingDocument())
  430. {
  431. var body = doc.MainDocumentPart.GetXDocument().Root.Element(W.body);
  432. if (body != null && body.Elements().Any())
  433. {
  434. var sectPr = doc.MainDocumentPart.GetXDocument().Root.Elements(W.body)
  435. .Elements().LastOrDefault();
  436. if (sectPr != null && sectPr.Name == W.sectPr)
  437. {
  438. AddSectionAndDependencies(doc, output, sectPr, images);
  439. output.MainDocumentPart.GetXDocument().Root.Element(W.body).Add(sectPr);
  440. }
  441. }
  442. }
  443. }
  444. else
  445. {
  446. FixUpSectionProperties(output);
  447. // Any sectPr elements that do not have headers and footers should take their headers and footers from the *next* section,
  448. // i.e. from the running section.
  449. var mxd = output.MainDocumentPart.GetXDocument();
  450. var sections = mxd.Descendants(W.sectPr).Reverse().ToList();
  451. CachedHeaderFooter[] cachedHeaderFooter = new[]
  452. {
  453. new CachedHeaderFooter() { Ref = W.headerReference, Type = "first" },
  454. new CachedHeaderFooter() { Ref = W.headerReference, Type = "even" },
  455. new CachedHeaderFooter() { Ref = W.headerReference, Type = "default" },
  456. new CachedHeaderFooter() { Ref = W.footerReference, Type = "first" },
  457. new CachedHeaderFooter() { Ref = W.footerReference, Type = "even" },
  458. new CachedHeaderFooter() { Ref = W.footerReference, Type = "default" },
  459. };
  460. bool firstSection = true;
  461. foreach (var sect in sections)
  462. {
  463. if (firstSection)
  464. {
  465. foreach (var hf in cachedHeaderFooter)
  466. {
  467. var referenceElement = sect.Elements(hf.Ref).FirstOrDefault(z => (string)z.Attribute(W.type) == hf.Type);
  468. if (referenceElement != null)
  469. hf.CachedPartRid = (string)referenceElement.Attribute(R.id);
  470. }
  471. firstSection = false;
  472. continue;
  473. }
  474. else
  475. {
  476. CopyOrCacheHeaderOrFooter(output, cachedHeaderFooter, sect, W.headerReference, "first");
  477. CopyOrCacheHeaderOrFooter(output, cachedHeaderFooter, sect, W.headerReference, "even");
  478. CopyOrCacheHeaderOrFooter(output, cachedHeaderFooter, sect, W.headerReference, "default");
  479. CopyOrCacheHeaderOrFooter(output, cachedHeaderFooter, sect, W.footerReference, "first");
  480. CopyOrCacheHeaderOrFooter(output, cachedHeaderFooter, sect, W.footerReference, "even");
  481. CopyOrCacheHeaderOrFooter(output, cachedHeaderFooter, sect, W.footerReference, "default");
  482. }
  483. }
  484. }
  485. // Now can process PtOpenXml:Insert elements in headers / footers
  486. int sourceNum = 0;
  487. foreach (Source source in sources)
  488. {
  489. if (source.InsertId != null)
  490. {
  491. while (true)
  492. {
  493. #if false
  494. this uses an overload of AppendDocument that takes a part.
  495. for each in main document part, header parts, footer parts
  496. are there any PtOpenXml.Insert elements in any of them?
  497. if so, then open and process all.
  498. #endif
  499. bool foundInHeadersFooters = false;
  500. if (output.MainDocumentPart.HeaderParts.Any(hp =>
  501. {
  502. var hpXDoc = hp.GetXDocument();
  503. return hpXDoc.Descendants(PtOpenXml.Insert).Any(d => (string)d.Attribute(PtOpenXml.Id) == source.InsertId);
  504. }))
  505. foundInHeadersFooters = true;
  506. if (output.MainDocumentPart.FooterParts.Any(fp =>
  507. {
  508. var hpXDoc = fp.GetXDocument();
  509. return hpXDoc.Descendants(PtOpenXml.Insert).Any(d => (string)d.Attribute(PtOpenXml.Id) == source.InsertId);
  510. }))
  511. foundInHeadersFooters = true;
  512. if (foundInHeadersFooters)
  513. {
  514. using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(source.WmlDocument))
  515. using (WordprocessingDocument doc = streamDoc.GetWordprocessingDocument())
  516. {
  517. #if TestForUnsupportedDocuments
  518. // throws exceptions if a document contains unsupported content
  519. TestForUnsupportedDocument(doc, sources.IndexOf(source));
  520. #endif
  521. var partList = output.MainDocumentPart.HeaderParts.Cast<OpenXmlPart>().Concat(output.MainDocumentPart.FooterParts.Cast<OpenXmlPart>()).ToList();
  522. foreach (var part in partList)
  523. {
  524. var partXDoc = part.GetXDocument();
  525. if (!partXDoc.Descendants(PtOpenXml.Insert).Any(d => (string)d.Attribute(PtOpenXml.Id) == source.InsertId))
  526. continue;
  527. List<XElement> contents = doc.MainDocumentPart.GetXDocument()
  528. .Root
  529. .Element(W.body)
  530. .Elements()
  531. .Skip(source.Start)
  532. .Take(source.Count)
  533. .ToList();
  534. try
  535. {
  536. AppendDocument(doc, output, part, contents, source.KeepSections, source.InsertId, images);
  537. }
  538. catch (DocumentBuilderInternalException dbie)
  539. {
  540. if (dbie.Message.Contains("{0}"))
  541. throw new DocumentBuilderException(string.Format(dbie.Message, sourceNum));
  542. else
  543. throw dbie;
  544. }
  545. }
  546. }
  547. }
  548. else
  549. break;
  550. }
  551. }
  552. ++sourceNum;
  553. }
  554. if (sources.Any(s => s.KeepSections) && !output.MainDocumentPart.GetXDocument().Root.Descendants(W.sectPr).Any())
  555. {
  556. using (OpenXmlMemoryStreamDocument streamDoc = new OpenXmlMemoryStreamDocument(sources[0].WmlDocument))
  557. using (WordprocessingDocument doc = streamDoc.GetWordprocessingDocument())
  558. {
  559. var sectPr = doc.MainDocumentPart.GetXDocument().Root.Element(W.body)
  560. .Elements().LastOrDefault();
  561. if (sectPr != null && sectPr.Name == W.sectPr)
  562. {
  563. AddSectionAndDependencies(doc, output, sectPr, images);
  564. output.MainDocumentPart.GetXDocument().Root.Element(W.body).Add(sectPr);
  565. }
  566. }
  567. }
  568. AdjustDocPrIds(output);
  569. }
  570. if (wmlGlossaryDocument != null)
  571. WriteGlossaryDocumentPart(wmlGlossaryDocument, output, images);
  572. foreach (var part in output.GetAllParts())
  573. if (part.Annotation<XDocument>() != null)
  574. part.PutXDocument();
  575. }
  576. // there are two scenarios that need to be handled
  577. // - if I find a style name that maps to a style ID different from one already mapped
  578. // - if a style name maps to a style ID that is already used for a different style
  579. // - then need to correct things
  580. // - make a complete list of all things that need to be changed, for every correction
  581. // - do the corrections all at one
  582. // - mark the document as changed, and change it in the sources.
  583. private static List<Source> NormalizeStyleNamesAndIds(List<Source> sources)
  584. {
  585. Dictionary<string, string> styleNameMap = new Dictionary<string, string>();
  586. HashSet<string> styleIds = new HashSet<string>();
  587. List<Source> newSources = new List<Source>();
  588. foreach (var src in sources)
  589. {
  590. var newSrc = AddAndRectify(src, styleNameMap, styleIds);
  591. newSources.Add(newSrc);
  592. }
  593. return newSources;
  594. }
  595. private static Source AddAndRectify(Source src, Dictionary<string, string> styleNameMap, HashSet<string> styleIds)
  596. {
  597. bool modified = false;
  598. using (MemoryStream ms = new MemoryStream())
  599. {
  600. ms.Write(src.WmlDocument.DocumentByteArray, 0, src.WmlDocument.DocumentByteArray.Length);
  601. using (WordprocessingDocument wDoc = WordprocessingDocument.Open(ms, true))
  602. {
  603. Dictionary<string, string> correctionList = new Dictionary<string, string>();
  604. var thisStyleNameMap = GetStyleNameMap(wDoc);
  605. foreach (var pair in thisStyleNameMap)
  606. {
  607. var styleName = pair.Key;
  608. var styleId = pair.Value;
  609. // if the styleNameMap does not contain an entry for this name
  610. if (!styleNameMap.ContainsKey(styleName))
  611. {
  612. // if the id is already used
  613. if (styleIds.Contains(styleId))
  614. {
  615. // this style uses a styleId that is used for another style.
  616. // randomly generate new styleId
  617. while (true)
  618. {
  619. var newStyleId = GenStyleIdFromStyleName(styleName);
  620. if (! styleIds.Contains(newStyleId))
  621. {
  622. correctionList.Add(styleId, newStyleId);
  623. styleNameMap.Add(styleName, newStyleId);
  624. styleIds.Add(newStyleId);
  625. break;
  626. }
  627. }
  628. }
  629. // otherwise we just add to the styleNameMap
  630. else
  631. {
  632. styleNameMap.Add(styleName, styleId);
  633. styleIds.Add(styleId);
  634. }
  635. }
  636. // but if the styleNameMap does contain an entry for this name
  637. else
  638. {
  639. // if the id is the same as the existing ID, then nothing to do
  640. if (styleNameMap[styleName] == styleId)
  641. continue;
  642. correctionList.Add(styleId, styleNameMap[styleName]);
  643. }
  644. }
  645. if (correctionList.Any())
  646. {
  647. modified = true;
  648. AdjustStyleIdsForDocument(wDoc, correctionList);
  649. }
  650. }
  651. if (modified)
  652. {
  653. var newWmlDocument = new WmlDocument(src.WmlDocument.FileName, ms.ToArray());
  654. var newSrc = new Source(newWmlDocument, src.Start, src.Count, src.KeepSections);
  655. newSrc.DiscardHeadersAndFootersInKeptSections = src.DiscardHeadersAndFootersInKeptSections;
  656. newSrc.InsertId = src.InsertId;
  657. return newSrc;
  658. }
  659. }
  660. return src;
  661. }
  662. #if false
  663. application/vnd.ms-word.styles.textEffects+xml styles/style/@styleId
  664. application/vnd.ms-word.styles.textEffects+xml styles/style/basedOn/@val
  665. application/vnd.ms-word.styles.textEffects+xml styles/style/link/@val
  666. application/vnd.ms-word.styles.textEffects+xml styles/style/next/@val
  667. application/vnd.ms-word.stylesWithEffects+xml styles/style/@styleId
  668. application/vnd.ms-word.stylesWithEffects+xml styles/style/basedOn/@val
  669. application/vnd.ms-word.stylesWithEffects+xml styles/style/link/@val
  670. application/vnd.ms-word.stylesWithEffects+xml styles/style/next/@val
  671. application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml pPr/pStyle/@val
  672. application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml rPr/rStyle/@val
  673. application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml tblPr/tblStyle/@val
  674. application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml pPr/pStyle/@val
  675. application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml rPr/rStyle/@val
  676. application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml tblPr/tblStyle/@val
  677. application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml pPr/pStyle/@val
  678. application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml rPr/rStyle/@val
  679. application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml tblPr/tblStyle/@val
  680. application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml pPr/pStyle/@val
  681. application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml rPr/rStyle/@val
  682. application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml tblPr/tblStyle/@val
  683. application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml pPr/pStyle/@val
  684. application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml rPr/rStyle/@val
  685. application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml tblPr/tblStyle/@val
  686. application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml pPr/pStyle/@val
  687. application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml rPr/rStyle/@val
  688. application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml tblPr/tblStyle/@val
  689. application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml abstractNum/lvl/pStyle/@val
  690. application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml abstractNum/numStyleLink/@val
  691. application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml abstractNum/styleLink/@val
  692. application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml settings/clickAndTypeStyle/@val
  693. Name, not ID
  694. ===================================
  695. application/vnd.ms-word.styles.textEffects+xml styles/style/name/@val
  696. application/vnd.openxmlformats-officedocument.wordprocessingml.stylesWithEffects+xml styles/style/name/@val
  697. application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml styles/style/name/@val
  698. application/vnd.ms-word.stylesWithEffects+xml styles/style/name/@val
  699. application/vnd.openxmlformats-officedocument.wordprocessingml.stylesWithEffects+xml latentStyles/lsdException/@name
  700. application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml latentStyles/lsdException/@name
  701. application/vnd.ms-word.stylesWithEffects+xml latentStyles/lsdException/@name
  702. application/vnd.ms-word.styles.textEffects+xml latentStyles/lsdException/@name
  703. #endif
  704. private static void AdjustStyleIdsForDocument(WordprocessingDocument wDoc, Dictionary<string, string> correctionList)
  705. {
  706. // update styles part
  707. UpdateStyleIdsForStylePart(wDoc.MainDocumentPart.StyleDefinitionsPart, correctionList);
  708. if (wDoc.MainDocumentPart.StylesWithEffectsPart != null)
  709. UpdateStyleIdsForStylePart(wDoc.MainDocumentPart.StylesWithEffectsPart, correctionList);
  710. // update content parts
  711. UpdateStyleIdsForContentPart(wDoc.MainDocumentPart, correctionList);
  712. foreach (var part in wDoc.MainDocumentPart.HeaderParts)
  713. UpdateStyleIdsForContentPart(part, correctionList);
  714. foreach (var part in wDoc.MainDocumentPart.FooterParts)
  715. UpdateStyleIdsForContentPart(part, correctionList);
  716. if (wDoc.MainDocumentPart.FootnotesPart != null)
  717. UpdateStyleIdsForContentPart(wDoc.MainDocumentPart.FootnotesPart, correctionList);
  718. if (wDoc.MainDocumentPart.EndnotesPart != null)
  719. UpdateStyleIdsForContentPart(wDoc.MainDocumentPart.EndnotesPart, correctionList);
  720. if (wDoc.MainDocumentPart.WordprocessingCommentsPart != null)
  721. UpdateStyleIdsForContentPart(wDoc.MainDocumentPart.WordprocessingCommentsPart, correctionList);
  722. if (wDoc.MainDocumentPart.WordprocessingCommentsExPart != null)
  723. UpdateStyleIdsForContentPart(wDoc.MainDocumentPart.WordprocessingCommentsExPart, correctionList);
  724. // update numbering part
  725. UpdateStyleIdsForNumberingPart(wDoc.MainDocumentPart.NumberingDefinitionsPart, correctionList);
  726. }
  727. private static void UpdateStyleIdsForNumberingPart(OpenXmlPart part, Dictionary<string, string> correctionList)
  728. {
  729. #if false
  730. application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml abstractNum/lvl/pStyle/@val
  731. application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml abstractNum/numStyleLink/@val
  732. application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml abstractNum/styleLink/@val
  733. #endif
  734. var numXDoc = part.GetXDocument();
  735. var numAttributeChangeList = correctionList
  736. .Select(cor =>
  737. new
  738. {
  739. NewId = cor.Value,
  740. PStyleAttributesToChange = numXDoc
  741. .Descendants(W.pStyle)
  742. .Attributes(W.val)
  743. .Where(a => a.Value == cor.Key)
  744. .ToList(),
  745. NumStyleLinkAttributesToChange = numXDoc
  746. .Descendants(W.numStyleLink)
  747. .Attributes(W.val)
  748. .Where(a => a.Value == cor.Key)
  749. .ToList(),
  750. StyleLinkAttributesToChange = numXDoc
  751. .Descendants(W.styleLink)
  752. .Attributes(W.val)
  753. .Where(a => a.Value == cor.Key)
  754. .ToList(),
  755. }
  756. )
  757. .ToList();
  758. foreach (var item in numAttributeChangeList)
  759. {
  760. foreach (var att in item.PStyleAttributesToChange)
  761. att.Value = item.NewId;
  762. foreach (var att in item.NumStyleLinkAttributesToChange)
  763. att.Value = item.NewId;
  764. foreach (var att in item.StyleLinkAttributesToChange)
  765. att.Value = item.NewId;
  766. }
  767. part.PutXDocument();
  768. }
  769. private static void UpdateStyleIdsForStylePart(OpenXmlPart part, Dictionary<string, string> correctionList)
  770. {
  771. #if false
  772. application/vnd.ms-word.styles.textEffects+xml styles/style/@styleId
  773. application/vnd.ms-word.styles.textEffects+xml styles/style/basedOn/@val
  774. application/vnd.ms-word.styles.textEffects+xml styles/style/link/@val
  775. application/vnd.ms-word.styles.textEffects+xml styles/style/next/@val
  776. #endif
  777. var styleXDoc = part.GetXDocument();
  778. var styleAttributeChangeList = correctionList
  779. .Select(cor =>
  780. new
  781. {
  782. NewId = cor.Value,
  783. StyleIdAttributesToChange = styleXDoc
  784. .Root
  785. .Elements(W.style)
  786. .Attributes(W.styleId)
  787. .Where(a => a.Value == cor.Key)
  788. .ToList(),
  789. BasedOnAttributesToChange = styleXDoc
  790. .Root
  791. .Elements(W.style)
  792. .Elements(W.basedOn)
  793. .Attributes(W.val)
  794. .Where(a => a.Value == cor.Key)
  795. .ToList(),
  796. NextAttributesToChange = styleXDoc
  797. .Root
  798. .Elements(W.style)
  799. .Elements(W.next)
  800. .Attributes(W.val)
  801. .Where(a => a.Value == cor.Key)
  802. .ToList(),
  803. LinkAttributesToChange = styleXDoc
  804. .Root
  805. .Elements(W.style)
  806. .Elements(W.link)
  807. .Attributes(W.val)
  808. .Where(a => a.Value == cor.Key)
  809. .ToList(),
  810. }
  811. )
  812. .ToList();
  813. foreach (var item in styleAttributeChangeList)
  814. {
  815. foreach (var att in item.StyleIdAttributesToChange)
  816. att.Value = item.NewId;
  817. foreach (var att in item.BasedOnAttributesToChange)
  818. att.Value = item.NewId;
  819. foreach (var att in item.NextAttributesToChange)
  820. att.Value = item.NewId;
  821. foreach (var att in item.LinkAttributesToChange)
  822. att.Value = item.NewId;
  823. }
  824. part.PutXDocument();
  825. }
  826. private static void UpdateStyleIdsForContentPart(OpenXmlPart part, Dictionary<string, string> correctionList)
  827. {
  828. #if false
  829. application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml pPr/pStyle/@val
  830. application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml rPr/rStyle/@val
  831. application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml tblPr/tblStyle/@val
  832. #endif
  833. var xDoc = part.GetXDocument();
  834. var mainAttributeChangeList = correctionList
  835. .Select(cor =>
  836. new
  837. {
  838. NewId = cor.Value,
  839. PStyleAttributesToChange = xDoc
  840. .Descendants(W.pStyle)
  841. .Attributes(W.val)
  842. .Where(a => a.Value == cor.Key)
  843. .ToList(),
  844. RStyleAttributesToChange = xDoc
  845. .Descendants(W.rStyle)
  846. .Attributes(W.val)
  847. .Where(a => a.Value == cor.Key)
  848. .ToList(),
  849. TblStyleAttributesToChange = xDoc
  850. .Descendants(W.tblStyle)
  851. .Attributes(W.val)
  852. .Where(a => a.Value == cor.Key)
  853. .ToList(),
  854. }
  855. )
  856. .ToList();
  857. foreach (var item in mainAttributeChangeList)
  858. {
  859. foreach (var att in item.PStyleAttributesToChange)
  860. att.Value = item.NewId;
  861. foreach (var att in item.RStyleAttributesToChange)
  862. att.Value = item.NewId;
  863. foreach (var att in item.TblStyleAttributesToChange)
  864. att.Value = item.NewId;
  865. }
  866. part.PutXDocument();
  867. }
  868. private static string GenStyleIdFromStyleName(string styleName)
  869. {
  870. var newStyleId = styleName
  871. .Replace("_", "")
  872. .Replace("#", "")
  873. .Replace(".", "") + ((new Random()).Next(990) + 9).ToString();
  874. return newStyleId;
  875. }
  876. private static Dictionary<string, string> GetStyleNameMap(WordprocessingDocument wDoc)
  877. {
  878. var sxDoc = wDoc.MainDocumentPart.StyleDefinitionsPart.GetXDocument();
  879. var thisDocumentDictionary = sxDoc
  880. .Root
  881. .Elements(W.style)
  882. .ToDictionary(
  883. z => (string)z.Elements(W.name).Attributes(W.val).FirstOrDefault(),
  884. z => (string)z.Attribute(W.styleId));
  885. return thisDocumentDictionary;
  886. }
  887. #if false
  888. At various locations in Open-Xml-PowerTools, you will find examples of Open XML markup that is associated with code associated with
  889. querying or generating that markup. This is an example of the GlossaryDocumentPart.
  890. <w:glossaryDocument xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:cx="http://schemas.microsoft.com/office/drawing/2014/chartex" xmlns:cx1="http://schemas.microsoft.com/office/drawing/2015/9/8/chartex" xmlns:cx2="http://schemas.microsoft.com/office/drawing/2015/10/21/chartex" xmlns:cx3="http://schemas.microsoft.com/office/drawing/2016/5/9/chartex" xmlns:cx4="http://schemas.microsoft.com/office/drawing/2016/5/10/chartex" xmlns:cx5="http://schemas.microsoft.com/office/drawing/2016/5/11/chartex" xmlns:cx6="http://schemas.microsoft.com/office/drawing/2016/5/12/chartex" xmlns:cx7="http://schemas.microsoft.com/office/drawing/2016/5/13/chartex" xmlns:cx8="http://schemas.microsoft.com/office/drawing/2016/5/14/chartex" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:aink="http://schemas.microsoft.com/office/drawing/2016/ink" xmlns:am3d="http://schemas.microsoft.com/office/drawing/2017/model3d" 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:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" 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:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" xmlns:w16cid="http://schemas.microsoft.com/office/word/2016/wordml/cid" xmlns:w16se="http://schemas.microsoft.com/office/word/2015/wordml/symex" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" mc:Ignorable="w14 w15 w16se w16cid wp14">
  891. <w:docParts>
  892. <w:docPart>
  893. <w:docPartPr>
  894. <w:name w:val="CDE7B64C7BB446AE905B622B0A882EB6" />
  895. <w:category>
  896. <w:name w:val="General" />
  897. <w:gallery w:val="placeholder" />
  898. </w:category>
  899. <w:types>
  900. <w:type w:val="bbPlcHdr" />
  901. </w:types>
  902. <w:behaviors>
  903. <w:behavior w:val="content" />
  904. </w:behaviors>
  905. <w:guid w:val="{13882A71-B5B7-4421-ACBB-9B61C61B3034}" />
  906. </w:docPartPr>
  907. <w:docPartBody>
  908. <w:p w:rsidR="00004EEA" w:rsidRDefault="00AD57F5" w:rsidP="00AD57F5">
  909. #endif
  910. private static void WriteGlossaryDocumentPart(WmlDocument wmlGlossaryDocument, WordprocessingDocument output, List<ImageData> images)
  911. {
  912. using (MemoryStream ms = new MemoryStream())
  913. {
  914. ms.Write(wmlGlossaryDocument.DocumentByteArray, 0, wmlGlossaryDocument.DocumentByteArray.Length);
  915. using (WordprocessingDocument wDoc = WordprocessingDocument.Open(ms, true))
  916. {
  917. var fromXDoc = wDoc.MainDocumentPart.GetXDocument();
  918. var outputGlossaryDocumentPart = output.MainDocumentPart.AddNewPart<GlossaryDocumentPart>();
  919. var newXDoc = new XDocument(
  920. new XDeclaration(OnePointZero, Utf8, Yes),
  921. new XElement(W.glossaryDocument,
  922. NamespaceAttributes,
  923. new XElement(W.docParts,
  924. fromXDoc.Descendants(W.docPart))));
  925. outputGlossaryDocumentPart.PutXDocument(newXDoc);
  926. CopyGlossaryDocumentPartsToGD(wDoc, output, fromXDoc.Root.Descendants(W.docPart), images);
  927. CopyRelatedPartsForContentParts(wDoc.MainDocumentPart, outputGlossaryDocumentPart, new[] { fromXDoc.Root }, images);
  928. }
  929. }
  930. }
  931. private static WmlDocument CoalesceGlossaryDocumentParts(IEnumerable<Source> sources, DocumentBuilderSettings settings)
  932. {
  933. List<Source> allGlossaryDocuments = sources
  934. .Select(s => DocumentBuilder.ExtractGlossaryDocument(s.WmlDocument))
  935. .Where(s => s != null)
  936. .Select(s => new Source(s))
  937. .ToList();
  938. if (!allGlossaryDocuments.Any())
  939. return null;
  940. WmlDocument coalescedRaw = DocumentBuilder.BuildDocument(allGlossaryDocuments);
  941. // now need to do some fix up
  942. using (MemoryStream ms = new MemoryStream())
  943. {
  944. ms.Write(coalescedRaw.DocumentByteArray, 0, coalescedRaw.DocumentByteArray.Length);
  945. using (WordprocessingDocument wDoc = WordprocessingDocument.Open(ms, true))
  946. {
  947. var mainXDoc = wDoc.MainDocumentPart.GetXDocument();
  948. var newBody = new XElement(W.body,
  949. new XElement(W.docParts,
  950. mainXDoc.Root.Element(W.body).Elements(W.docParts).Elements(W.docPart)));
  951. mainXDoc.Root.Element(W.body).ReplaceWith(newBody);
  952. wDoc.MainDocumentPart.PutXDocument();
  953. }
  954. WmlDocument coalescedGlossaryDocument = new WmlDocument("Coalesced.docx", ms.ToArray());
  955. return coalescedGlossaryDocument;
  956. }
  957. }
  958. private static void InitRelationshipMarkup()
  959. {
  960. RelationshipMarkup = new Dictionary<XName, XName[]>()
  961. {
  962. //{ button, new [] { image }},
  963. { A.blip, new [] { R.embed, R.link }},
  964. { A.hlinkClick, new [] { R.id }},
  965. { A.relIds, new [] { R.cs, R.dm, R.lo, R.qs }},
  966. //{ a14:imgLayer, new [] { R.embed }},
  967. //{ ax:ocx, new [] { R.id }},
  968. { C.chart, new [] { R.id }},
  969. { C.externalData, new [] { R.id }},
  970. { C.userShapes, new [] { R.id }},
  971. { DGM.relIds, new [] { R.cs, R.dm, R.lo, R.qs }},
  972. { O.OLEObject, new [] { R.id }},
  973. { VML.fill, new [] { R.id }},
  974. { VML.imagedata, new [] { R.href, R.id, R.pict }},
  975. { VML.stroke, new [] { R.id }},
  976. { W.altChunk, new [] { R.id }},
  977. { W.attachedTemplate, new [] { R.id }},
  978. { W.control, new [] { R.id }},
  979. { W.dataSource, new [] { R.id }},
  980. { W.embedBold, new [] { R.id }},
  981. { W.embedBoldItalic, new [] { R.id }},
  982. { W.embedItalic, new [] { R.id }},
  983. { W.embedRegular, new [] { R.id }},
  984. { W.footerReference, new [] { R.id }},
  985. { W.headerReference, new [] { R.id }},
  986. { W.headerSource, new [] { R.id }},
  987. { W.hyperlink, new [] { R.id }},
  988. { W.printerSettings, new [] { R.id }},
  989. { W.recipientData, new [] { R.id }}, // Mail merge, not required
  990. { W.saveThroughXslt, new [] { R.id }},
  991. { W.sourceFileName, new [] { R.id }}, // Framesets, not required
  992. { W.src, new [] { R.id }}, // Mail merge, not required
  993. { W.subDoc, new [] { R.id }}, // Sub documents, not required
  994. //{ w14:contentPart, new [] { R.id }},
  995. { WNE.toolbarData, new [] { R.id }},
  996. };
  997. }
  998. private static void CopySpecifiedCustomXmlParts(WordprocessingDocument sourceDocument, WordprocessingDocument output, DocumentBuilderSettings settings)
  999. {
  1000. if (settings.CustomXmlGuidList == null || !settings.CustomXmlGuidList.Any())
  1001. return;
  1002. foreach (CustomXmlPart customXmlPart in sourceDocument.MainDocumentPart.CustomXmlParts)
  1003. {
  1004. OpenXmlPart propertyPart = customXmlPart
  1005. .Parts
  1006. .Select(p => p.OpenXmlPart)
  1007. .Where(p => p.ContentType == "application/vnd.openxmlformats-officedocument.customXmlProperties+xml")
  1008. .FirstOrDefault();
  1009. if (propertyPart != null)
  1010. {
  1011. XDocument propertyPartDoc = propertyPart.GetXDocument();
  1012. #if false
  1013. At various locations in Open-Xml-PowerTools, you will find examples of Open XML markup that is associated with code associated with
  1014. querying or generating that markup. This is an example of the Custom XML Properties part.
  1015. <ds:datastoreItem ds:itemID="{1337A0C2-E6EE-4612-ACA5-E0E5A513381D}" xmlns:ds="http://schemas.openxmlformats.org/officeDocument/2006/customXml">
  1016. <ds:schemaRefs />
  1017. </ds:datastoreItem>
  1018. #endif
  1019. var itemID = (string)propertyPartDoc.Root.Attribute(DS.itemID);
  1020. if (itemID != null)
  1021. {
  1022. itemID = itemID.Trim('{', '}');
  1023. if (settings.CustomXmlGuidList.Contains(itemID))
  1024. {
  1025. CustomXmlPart newPart = output.MainDocumentPart.AddCustomXmlPart(customXmlPart.ContentType);
  1026. newPart.GetXDocument().Add(customXmlPart.GetXDocument().Root);
  1027. foreach (OpenXmlPart propPart in customXmlPart.Parts.Select(p => p.OpenXmlPart))
  1028. {
  1029. CustomXmlPropertiesPart newPropPart = newPart.AddNewPart<CustomXmlPropertiesPart>();
  1030. newPropPart.GetXDocument().Add(propPart.GetXDocument().Root);
  1031. }
  1032. }
  1033. }
  1034. }
  1035. }
  1036. }
  1037. private static void RemoveHeadersAndFootersFromSections(WordprocessingDocument doc)
  1038. {
  1039. var mdXDoc = doc.MainDocumentPart.GetXDocument();
  1040. var sections = mdXDoc.Descendants(W.sectPr).ToList();
  1041. foreach (var sect in sections)
  1042. {
  1043. sect.Elements(W.headerReference).Remove();
  1044. sect.Elements(W.footerReference).Remove();
  1045. }
  1046. doc.MainDocumentPart.PutXDocument();
  1047. }
  1048. private class CachedHeaderFooter
  1049. {
  1050. public XName Ref;
  1051. public string Type;
  1052. public string CachedPartRid;
  1053. };
  1054. private static void ProcessSectionsForLinkToPreviousHeadersAndFooters(WordprocessingDocument doc)
  1055. {
  1056. CachedHeaderFooter[] cachedHeaderFooter = new[]
  1057. {
  1058. new CachedHeaderFooter() { Ref = W.headerReference, Type = "first" },
  1059. new CachedHeaderFooter() { Ref = W.headerReference, Type = "even" },
  1060. new CachedHeaderFooter() { Ref = W.headerReference, Type = "default" },
  1061. new CachedHeaderFooter() { Ref = W.footerReference, Type = "first" },
  1062. new CachedHeaderFooter() { Ref = W.footerReference, Type = "even" },
  1063. new CachedHeaderFooter() { Ref = W.footerReference, Type = "default" },
  1064. };
  1065. var mdXDoc = doc.MainDocumentPart.GetXDocument();
  1066. var sections = mdXDoc.Descendants(W.sectPr).ToList();
  1067. var firstSection = true;
  1068. foreach (var sect in sections)
  1069. {
  1070. if (firstSection)
  1071. {
  1072. var headerFirst = FindReference(sect, W.headerReference, "first");
  1073. var headerDefault = FindReference(sect, W.headerReference, "default");
  1074. var headerEven = FindReference(sect, W.headerReference, "even");
  1075. var footerFirst = FindReference(sect, W.footerReference, "first");
  1076. var footerDefault = FindReference(sect, W.footerReference, "default");
  1077. var footerEven = FindReference(sect, W.footerReference, "even");
  1078. if (headerEven == null)
  1079. {
  1080. if (headerDefault != null)
  1081. AddReferenceToExistingHeaderOrFooter(doc.MainDocumentPart, sect, (string)headerDefault.Attribute(R.id), W.headerReference, "even");
  1082. else
  1083. InitEmptyHeaderOrFooter(doc.MainDocumentPart, sect, W.headerReference, "even");
  1084. }
  1085. if (headerFirst == null)
  1086. {
  1087. if (headerDefault != null)
  1088. AddReferenceToExistingHeaderOrFooter(doc.MainDocumentPart, sect, (string)headerDefault.Attribute(R.id), W.headerReference, "first");
  1089. else
  1090. InitEmptyHeaderOrFooter(doc.MainDocumentPart, sect, W.headerReference, "first");
  1091. }
  1092. if (footerEven == null)
  1093. {
  1094. if (footerDefault != null)
  1095. AddReferenceToExistingHeaderOrFooter(doc.MainDocumentPart, sect, (string)footerDefault.Attribute(R.id), W.footerReference, "even");
  1096. else
  1097. InitEmptyHeaderOrFooter(doc.MainDocumentPart, sect, W.footerReference, "even");
  1098. }
  1099. if (footerFirst == null)
  1100. {
  1101. if (footerDefault != null)
  1102. AddReferenceToExistingHeaderOrFooter(doc.MainDocumentPart, sect, (string)footerDefault.Attribute(R.id), W.footerReference, "first");
  1103. else
  1104. InitEmptyHeaderOrFooter(doc.MainDocumentPart, sect, W.footerReference, "first");
  1105. }
  1106. foreach (var hf in cachedHeaderFooter)
  1107. {
  1108. if (sect.Elements(hf.Ref).FirstOrDefault(z => (string)z.Attribute(W.type) == hf.Type) == null)
  1109. InitEmptyHeaderOrFooter(doc.MainDocumentPart, sect, hf.Ref, hf.Type);
  1110. var reference = sect.Elements(hf.Ref).FirstOrDefault(z => (string)z.Attribute(W.type) == hf.Type);
  1111. if (reference == null)
  1112. throw new OpenXmlPowerToolsException("Internal error");
  1113. hf.CachedPartRid = (string)reference.Attribute(R.id);
  1114. }
  1115. firstSection = false;
  1116. continue;
  1117. }
  1118. else
  1119. {
  1120. CopyOrCacheHeaderOrFooter(doc, cachedHeaderFooter, sect, W.headerReference, "first");
  1121. CopyOrCacheHeaderOrFooter(doc, cachedHeaderFooter, sect, W.headerReference, "even");
  1122. CopyOrCacheHeaderOrFooter(doc, cachedHeaderFooter, sect, W.headerReference, "default");
  1123. CopyOrCacheHeaderOrFooter(doc, cachedHeaderFooter, sect, W.footerReference, "first");
  1124. CopyOrCacheHeaderOrFooter(doc, cachedHeaderFooter, sect, W.footerReference, "even");
  1125. CopyOrCacheHeaderOrFooter(doc, cachedHeaderFooter, sect, W.footerReference, "default");
  1126. }
  1127. }
  1128. doc.MainDocumentPart.PutXDocument();
  1129. }
  1130. private static void CopyOrCacheHeaderOrFooter(WordprocessingDocument doc, CachedHeaderFooter[] cachedHeaderFooter, XElement sect, XName referenceXName, string type)
  1131. {
  1132. var referenceElement = FindReference(sect, referenceXName, type);
  1133. if (referenceElement == null)
  1134. {
  1135. var cachedPartRid = cachedHeaderFooter.FirstOrDefault(z => z.Ref == referenceXName && z.Type == type).CachedPartRid;
  1136. AddReferenceToExistingHeaderOrFooter(doc.MainDocumentPart, sect, cachedPartRid, referenceXName, type);
  1137. }
  1138. else
  1139. {
  1140. var cachedPart = cachedHeaderFooter.FirstOrDefault(z => z.Ref == referenceXName && z.Type == type);
  1141. cachedPart.CachedPartRid = (string)referenceElement.Attribute(R.id);
  1142. }
  1143. }
  1144. private static XElement FindReference(XElement sect, XName reference, string type)
  1145. {
  1146. return sect.Elements(reference).FirstOrDefault(z =>
  1147. {
  1148. return (string)z.Attribute(W.type) == type;
  1149. });
  1150. }
  1151. private static void AddReferenceToExistingHeaderOrFooter(MainDocumentPart mainDocPart, XElement sect, string rId, XName reference, string toType)
  1152. {
  1153. if (reference == W.headerReference)
  1154. {
  1155. var referenceToAdd = new XElement(W.headerReference,
  1156. new XAttribute(W.type, toType),
  1157. new XAttribute(R.id, rId));
  1158. sect.AddFirst(referenceToAdd);
  1159. }
  1160. else
  1161. {
  1162. var referenceToAdd = new XElement(W.footerReference,
  1163. new XAttribute(W.type, toType),
  1164. new XAttribute(R.id, rId));
  1165. sect.AddFirst(referenceToAdd);
  1166. }
  1167. }
  1168. private static void InitEmptyHeaderOrFooter(MainDocumentPart mainDocPart, XElement sect, XName referenceXName, string toType)
  1169. {
  1170. XDocument xDoc = null;
  1171. if (referenceXName == W.headerReference)
  1172. {
  1173. xDoc = XDocument.Parse(
  1174. @"<?xml version='1.0' encoding='utf-8' standalone='yes'?>
  1175. <w:hdr xmlns:wpc='http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas'
  1176. xmlns:mc='http://schemas.openxmlformats.org/markup-compatibility/2006'
  1177. xmlns:o='urn:schemas-microsoft-com:office:office'
  1178. xmlns:r='http://schemas.openxmlformats.org/officeDocument/2006/relationships'
  1179. xmlns:m='http://schemas.openxmlformats.org/officeDocument/2006/math'
  1180. xmlns:v='urn:schemas-microsoft-com:vml'
  1181. xmlns:wp14='http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing'
  1182. xmlns:wp='http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing'
  1183. xmlns:w10='urn:schemas-microsoft-com:office:word'
  1184. xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'
  1185. xmlns:w14='http://schemas.microsoft.com/office/word/2010/wordml'
  1186. xmlns:w15='http://schemas.microsoft.com/office/word/2012/wordml'
  1187. xmlns:wpg='http://schemas.microsoft.com/office/word/2010/wordprocessingGroup'
  1188. xmlns:wpi='http://schemas.microsoft.com/office/word/2010/wordprocessingInk'
  1189. xmlns:wne='http://schemas.microsoft.com/office/word/2006/wordml'
  1190. xmlns:wps='http://schemas.microsoft.com/office/word/2010/wordprocessingShape'
  1191. mc:Ignorable='w14 w15 wp14'>
  1192. <w:p>
  1193. <w:pPr>
  1194. <w:pStyle w:val='Header' />
  1195. </w:pPr>
  1196. <w:r>
  1197. <w:t></w:t>
  1198. </w:r>
  1199. </w:p>
  1200. </w:hdr>");
  1201. var newHeaderPart = mainDocPart.AddNewPart<HeaderPart>();
  1202. newHeaderPart.PutXDocument(xDoc);
  1203. var referenceToAdd = new XElement(W.headerReference,
  1204. new XAttribute(W.type, toType),
  1205. new XAttribute(R.id, mainDocPart.GetIdOfPart(newHeaderPart)));
  1206. sect.AddFirst(referenceToAdd);
  1207. }
  1208. else
  1209. {
  1210. xDoc = XDocument.Parse(@"<?xml version='1.0' encoding='utf-8' standalone='yes'?>
  1211. <w:ftr xmlns:wpc='http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas'
  1212. xmlns:mc='http://schemas.openxmlformats.org/markup-compatibility/2006'
  1213. xmlns:o='urn:schemas-microsoft-com:office:office'
  1214. xmlns:r='http://schemas.openxmlformats.org/officeDocument/2006/relationships'
  1215. xmlns:m='http://schemas.openxmlformats.org/officeDocument/2006/math'
  1216. xmlns:v='urn:schemas-microsoft-com:vml'
  1217. xmlns:wp14='http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing'
  1218. xmlns:wp='http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing'
  1219. xmlns:w10='urn:schemas-microsoft-com:office:word'
  1220. xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'
  1221. xmlns:w14='http://schemas.microsoft.com/office/word/2010/wordml'
  1222. xmlns:w15='http://schemas.microsoft.com/office/word/2012/wordml'
  1223. xmlns:wpg='http://schemas.microsoft.com/office/word/2010/wordprocessingGroup'
  1224. xmlns:wpi='http://schemas.microsoft.com/office/word/2010/wordprocessingInk'
  1225. xmlns:wne='http://schemas.microsoft.com/office/word/2006/wordml'
  1226. xmlns:wps='http://schemas.microsoft.com/office/word/2010/wordprocessingShape'
  1227. mc:Ignorable='w14 w15 wp14'>
  1228. <w:p>
  1229. <w:pPr>
  1230. <w:pStyle w:val='Footer' />
  1231. </w:pPr>
  1232. <w:r>
  1233. <w:t></w:t>
  1234. </w:r>
  1235. </w:p>
  1236. </w:ftr>");
  1237. var newFooterPart = mainDocPart.AddNewPart<FooterPart>();
  1238. newFooterPart.PutXDocument(xDoc);
  1239. var referenceToAdd = new XElement(W.footerReference,
  1240. new XAttribute(W.type, toType),
  1241. new XAttribute(R.id, mainDocPart.GetIdOfPart(newFooterPart)));
  1242. sect.AddFirst(referenceToAdd);
  1243. }
  1244. }
  1245. private static void TestPartForUnsupportedContent(OpenXmlPart part, int sourceNumber)
  1246. {
  1247. XNamespace[] obsoleteNamespaces = new[]
  1248. {
  1249. XNamespace.Get("http://schemas.microsoft.com/office/word/2007/5/30/wordml"),
  1250. XNamespace.Get("http://schemas.microsoft.com/office/word/2008/9/16/wordprocessingDrawing"),
  1251. XNamespace.Get("http://schemas.microsoft.com/office/word/2009/2/wordml"),
  1252. };
  1253. XDocument xDoc = part.GetXDocument();
  1254. XElement invalidElement = xDoc.Descendants()
  1255. .FirstOrDefault(d =>
  1256. {
  1257. bool b = d.Name == W.subDoc ||
  1258. d.Name == W.control ||
  1259. d.Name == W.altChunk ||
  1260. d.Name.LocalName == "contentPart" ||
  1261. obsoleteNamespaces.Contains(d.Name.Namespace);
  1262. bool b2 = b ||
  1263. d.Attributes().Any(a => obsoleteNamespaces.Contains(a.Name.Namespace));
  1264. return b2;
  1265. });
  1266. if (invalidElement != null)
  1267. {
  1268. if (invalidElement.Name == W.subDoc)
  1269. throw new DocumentBuilderException(String.Format("Source {0} is unsupported document - contains sub document",
  1270. sourceNumber));
  1271. if (invalidElement.Name == W.control)
  1272. throw new DocumentBuilderException(String.Format("Source {0} is unsupported document - contains ActiveX controls",
  1273. sourceNumber));
  1274. if (invalidElement.Name == W.altChunk)
  1275. throw new DocumentBuilderException(String.Format("Source {0} is unsupported document - contains altChunk",
  1276. sourceNumber));
  1277. if (invalidElement.Name.LocalName == "contentPart")
  1278. throw new DocumentBuilderException(String.Format("Source {0} is unsupported document - contains contentPart content",
  1279. sourceNumber));
  1280. if (obsoleteNamespaces.Contains(invalidElement.Name.Namespace) ||
  1281. invalidElement.Attributes().Any(a => obsoleteNamespaces.Contains(a.Name.Namespace)))
  1282. throw new DocumentBuilderException(String.Format("Source {0} is unsupported document - contains obsolete namespace",
  1283. sourceNumber));
  1284. }
  1285. }
  1286. //What does not work:
  1287. //- sub docs
  1288. //- bidi text appears to work but has not been tested
  1289. //- languages other than en-us appear to work but have not been tested
  1290. //- documents with activex controls
  1291. //- mail merge source documents (look for dataSource in settings)
  1292. //- documents with ink
  1293. //- documents with frame sets and frames
  1294. private static void TestForUnsupportedDocument(WordprocessingDocument doc, int sourceNumber)
  1295. {
  1296. if (doc.MainDocumentPart.GetXDocument().Root == null)
  1297. throw new DocumentBuilderException(string.Format("Source {0} is an invalid document - MainDocumentPart contains no content.", sourceNumber));
  1298. if ((string)doc.MainDocumentPart.GetXDocument().Root.Name.NamespaceName == "http://purl.oclc.org/ooxml/wordprocessingml/main")
  1299. throw new DocumentBuilderException(string.Format("Source {0} is saved in strict mode, not supported", sourceNumber));
  1300. // note: if ever want to support section changes, need to address the code that rationalizes headers and footers, propagating to sections that inherit headers/footers from prev section
  1301. foreach (var d in doc.MainDocumentPart.GetXDocument().Descendants())
  1302. {
  1303. if (d.Name == W.sectPrChange)
  1304. throw new DocumentBuilderException(string.Format("Source {0} contains section changes (w:sectPrChange), not supported", sourceNumber));
  1305. // note: if ever want to support Open-Xml-PowerTools attributes, need to make sure that all attributes are propagated in all cases
  1306. //if (d.Name.Namespace == PtOpenXml.ptOpenXml ||
  1307. // d.Name.Namespace == PtOpenXml.pt)
  1308. // throw new DocumentBuilderException(string.Format("Source {0} contains Open-Xml-PowerTools markup, not supported", sourceNumber));
  1309. //if (d.Attributes().Any(a => a.Name.Namespace == PtOpenXml.ptOpenXml || a.Name.Namespace == PtOpenXml.pt))
  1310. // throw new DocumentBuilderException(string.Format("Source {0} contains Open-Xml-PowerTools markup, not supported", sourceNumber));
  1311. }
  1312. TestPartForUnsupportedContent(doc.MainDocumentPart, sourceNumber);
  1313. foreach (var hdr in doc.MainDocumentPart.HeaderParts)
  1314. TestPartForUnsupportedContent(hdr, sourceNumber);
  1315. foreach (var ftr in doc.MainDocumentPart.FooterParts)
  1316. TestPartForUnsupportedContent(ftr, sourceNumber);
  1317. if (doc.MainDocumentPart.FootnotesPart != null)
  1318. TestPartForUnsupportedContent(doc.MainDocumentPart.FootnotesPart, sourceNumber);
  1319. if (doc.MainDocumentPart.EndnotesPart != null)
  1320. TestPartForUnsupportedContent(doc.MainDocumentPart.EndnotesPart, sourceNumber);
  1321. if (doc.MainDocumentPart.DocumentSettingsPart != null &&
  1322. doc.MainDocumentPart.DocumentSettingsPart.GetXDocument().Descendants().Any(d => d.Name == W.src ||
  1323. d.Name == W.recipientData || d.Name == W.mailMerge))
  1324. throw new DocumentBuilderException(String.Format("Source {0} is unsupported document - contains Mail Merge content",
  1325. sourceNumber));
  1326. if (doc.MainDocumentPart.WebSettingsPart != null &&
  1327. doc.MainDocumentPart.WebSettingsPart.GetXDocument().Descendants().Any(d => d.Name == W.frameset))
  1328. throw new DocumentBuilderException(String.Format("Source {0} is unsupported document - contains a frameset", sourceNumber));
  1329. var numberingElements = doc.MainDocumentPart
  1330. .GetXDocument()
  1331. .Descendants(W.numPr)
  1332. .Where(n =>
  1333. {
  1334. bool zeroId = (int?)n.Attribute(W.id) == 0;
  1335. bool hasChildInsId = n.Elements(W.ins).Any();
  1336. if (zeroId || hasChildInsId)
  1337. return false;
  1338. return true;
  1339. })
  1340. .ToList();
  1341. if (numberingElements.Any() &&
  1342. doc.MainDocumentPart.NumberingDefinitionsPart == null)
  1343. throw new DocumentBuilderException(String.Format(
  1344. "Source {0} is invalid document - contains numbering markup but no numbering part", sourceNumber));
  1345. }
  1346. private static void FixUpSectionProperties(WordprocessingDocument newDocument)
  1347. {
  1348. XDocument mainDocumentXDoc = newDocument.MainDocumentPart.GetXDocument();
  1349. mainDocumentXDoc.Declaration.Standalone = Yes;
  1350. mainDocumentXDoc.Declaration.Encoding = Utf8;
  1351. XElement body = mainDocumentXDoc.Root.Element(W.body);
  1352. var sectionPropertiesToMove = body
  1353. .Elements()
  1354. .Take(body.Elements().Count() - 1)
  1355. .Where(e => e.Name == W.sectPr)
  1356. .ToList();
  1357. foreach (var s in sectionPropertiesToMove)
  1358. {
  1359. var p = s.SiblingsBeforeSelfReverseDocumentOrder().First();
  1360. if (p.Element(W.pPr) == null)
  1361. p.AddFirst(new XElement(W.pPr));
  1362. p.Element(W.pPr).Add(s);
  1363. }
  1364. foreach (var s in sectionPropertiesToMove)
  1365. s.Remove();
  1366. }
  1367. private static void AddSectionAndDependencies(WordprocessingDocument sourceDocument, WordprocessingDocument newDocument,
  1368. XElement sectionMarkup, List<ImageData> images)
  1369. {
  1370. var headerReferences = sectionMarkup.Elements(W.headerReference);
  1371. foreach (var headerReference in headerReferences)
  1372. {
  1373. string oldRid = headerReference.Attribute(R.id).Value;
  1374. HeaderPart oldHeaderPart = null;
  1375. try
  1376. {
  1377. oldHeaderPart = (HeaderPart)sourceDocument.MainDocumentPart.GetPartById(oldRid);
  1378. }
  1379. catch (ArgumentOutOfRangeException)
  1380. {
  1381. var message = string.Format("ArgumentOutOfRangeException, attempting to get header rId={0}", oldRid);
  1382. throw new OpenXmlPowerToolsException(message);
  1383. }
  1384. XDocument oldHeaderXDoc = oldHeaderPart.GetXDocument();
  1385. if (oldHeaderXDoc != null && oldHeaderXDoc.Root != null)
  1386. CopyNumbering(sourceDocument, newDocument, new[] { oldHeaderXDoc.Root }, images);
  1387. HeaderPart newHeaderPart = newDocument.MainDocumentPart.AddNewPart<HeaderPart>();
  1388. XDocument newHeaderXDoc = newHeaderPart.GetXDocument();
  1389. newHeaderXDoc.Declaration.Standalone = Yes;
  1390. newHeaderXDoc.Declaration.Encoding = Utf8;
  1391. newHeaderXDoc.Add(oldHeaderXDoc.Root);
  1392. headerReference.Attribute(R.id).Value = newDocument.MainDocumentPart.GetIdOfPart(newHeaderPart);
  1393. AddRelationships(oldHeaderPart, newHeaderPart, new[] { newHeaderXDoc.Root });
  1394. CopyRelatedPartsForContentParts(oldHeaderPart, newHeaderPart, new[] { newHeaderXDoc.Root }, images);
  1395. }
  1396. var footerReferences = sectionMarkup.Elements(W.footerReference);
  1397. foreach (var footerReference in footerReferences)
  1398. {
  1399. string oldRid = footerReference.Attribute(R.id).Value;
  1400. var oldFooterPart2 = sourceDocument.MainDocumentPart.GetPartById(oldRid);
  1401. if (!(oldFooterPart2 is FooterPart))
  1402. throw new DocumentBuilderException("Invalid document - invalid footer part.");
  1403. FooterPart oldFooterPart = (FooterPart)oldFooterPart2;
  1404. XDocument oldFooterXDoc = oldFooterPart.GetXDocument();
  1405. if (oldFooterXDoc != null && oldFooterXDoc.Root != null)
  1406. CopyNumbering(sourceDocument, newDocument, new[] { oldFooterXDoc.Root }, images);
  1407. FooterPart newFooterPart = newDocument.MainDocumentPart.AddNewPart<FooterPart>();
  1408. XDocument newFooterXDoc = newFooterPart.GetXDocument();
  1409. newFooterXDoc.Declaration.Standalone = Yes;
  1410. newFooterXDoc.Declaration.Encoding = Utf8;
  1411. newFooterXDoc.Add(oldFooterXDoc.Root);
  1412. footerReference.Attribute(R.id).Value = newDocument.MainDocumentPart.GetIdOfPart(newFooterPart);
  1413. AddRelationships(oldFooterPart, newFooterPart, new[] { newFooterXDoc.Root });
  1414. CopyRelatedPartsForContentParts(oldFooterPart, newFooterPart, new[] { newFooterXDoc.Root }, images);
  1415. }
  1416. }
  1417. private static void MergeStyles(WordprocessingDocument sourceDocument, WordprocessingDocument newDocument, XDocument fromStyles, XDocument toStyles, IEnumerable<XElement> newContent)
  1418. {
  1419. #if MergeStylesWithSameNames
  1420. var newIds = new Dictionary<string, string>();
  1421. #endif
  1422. if (fromStyles.Root == null)
  1423. return;
  1424. foreach (XElement style in fromStyles.Root.Elements(W.style))
  1425. {
  1426. var fromId = (string)style.Attribute(W.styleId);
  1427. var fromName = (string)style.Elements(W.name).Attributes(W.val).FirstOrDefault();
  1428. var toStyle = toStyles
  1429. .Root
  1430. .Elements(W.style)
  1431. .FirstOrDefault(st => (string)st.Elements(W.name).Attributes(W.val).FirstOrDefault() == fromName);
  1432. if (toStyle == null)
  1433. {
  1434. #if MergeStylesWithSameNames
  1435. var linkElement = style.Element(W.link);
  1436. string linkedId;
  1437. if (linkElement != null && newIds.TryGetValue(linkElement.Attribute(W.val).Value, out linkedId))
  1438. {
  1439. var linkedStyle = toStyles.Root.Elements(W.style)
  1440. .First(o => o.Attribute(W.styleId).Value == linkedId);
  1441. if (linkedStyle.Element(W.link) != null)
  1442. newIds.Add(fromId, linkedStyle.Element(W.link).Attribute(W.val).Value);
  1443. continue;
  1444. }
  1445. //string name = (string)style.Elements(W.name).Attributes(W.val).FirstOrDefault();
  1446. //var namedStyle = toStyles
  1447. // .Root
  1448. // .Elements(W.style)
  1449. // .Where(st => st.Element(W.name) != null)
  1450. // .FirstOrDefault(o => (string)o.Element(W.name).Attribute(W.val) == name);
  1451. //if (namedStyle != null)
  1452. //{
  1453. // if (! newIds.ContainsKey(fromId))
  1454. // newIds.Add(fromId, namedStyle.Attribute(W.styleId).Value);
  1455. // continue;
  1456. //}
  1457. #endif
  1458. int number = 1;
  1459. int abstractNumber = 0;
  1460. XDocument oldNumbering = null;
  1461. XDocument newNumbering = null;
  1462. foreach (XElement numReference in style.Descendants(W.numPr))
  1463. {
  1464. XElement idElement = numReference.Descendants(W.numId).FirstOrDefault();
  1465. if (idElement != null)
  1466. {
  1467. if (oldNumbering == null)
  1468. {
  1469. if (sourceDocument.MainDocumentPart.NumberingDefinitionsPart != null)
  1470. oldNumbering = sourceDocument.MainDocumentPart.NumberingDefinitionsPart.GetXDocument();
  1471. else
  1472. {
  1473. oldNumbering = new XDocument();
  1474. oldNumbering.Declaration = new XDeclaration(OnePointZero, Utf8, Yes);
  1475. oldNumbering.Add(new XElement(W.numbering, NamespaceAttributes));
  1476. }
  1477. }
  1478. if (newNumbering == null)
  1479. {
  1480. if (newDocument.MainDocumentPart.NumberingDefinitionsPart != null)
  1481. {
  1482. newNumbering = newDocument.MainDocumentPart.NumberingDefinitionsPart.GetXDocument();
  1483. newNumbering.Declaration.Standalone = Yes;
  1484. newNumbering.Declaration.Encoding = Utf8;
  1485. var numIds = newNumbering
  1486. .Root
  1487. .Elements(W.num)
  1488. .Select(f => (int)f.Attribute(W.numId));
  1489. if (numIds.Any())
  1490. number = numIds.Max() + 1;
  1491. numIds = newNumbering
  1492. .Root
  1493. .Elements(W.abstractNum)
  1494. .Select(f => (int)f.Attribute(W.abstractNumId));
  1495. if (numIds.Any())
  1496. abstractNumber = numIds.Max() + 1;
  1497. }
  1498. else
  1499. {
  1500. newDocument.MainDocumentPart.AddNewPart<NumberingDefinitionsPart>();
  1501. newNumbering = newDocument.MainDocumentPart.NumberingDefinitionsPart.GetXDocument();
  1502. newNumbering.Declaration.Standalone = Yes;
  1503. newNumbering.Declaration.Encoding = Utf8;
  1504. newNumbering.Add(new XElement(W.numbering, NamespaceAttributes));
  1505. }
  1506. }
  1507. string numId = idElement.Attribute(W.val).Value;
  1508. if (numId != "0")
  1509. {
  1510. XElement element = oldNumbering
  1511. .Descendants()
  1512. .Elements(W.num)
  1513. .Where(p => ((string)p.Attribute(W.numId)) == numId)
  1514. .FirstOrDefault();
  1515. // Copy abstract numbering element, if necessary (use matching NSID)
  1516. string abstractNumId = string.Empty;
  1517. if (element != null)
  1518. {
  1519. abstractNumId = element
  1520. .Elements(W.abstractNumId)
  1521. .First()
  1522. .Attribute(W.val)
  1523. .Value;
  1524. XElement abstractElement = oldNumbering
  1525. .Descendants()
  1526. .Elements(W.abstractNum)
  1527. .Where(p => ((string)p.Attribute(W.abstractNumId)) == abstractNumId)
  1528. .FirstOrDefault();
  1529. string abstractNSID = string.Empty;
  1530. if (abstractElement != null)
  1531. {
  1532. XElement nsidElement = abstractElement
  1533. .Element(W.nsid);
  1534. abstractNSID = null;
  1535. if (nsidElement != null)
  1536. abstractNSID = (string)nsidElement
  1537. .Attribute(W.val);
  1538. XElement newAbstractElement = newNumbering
  1539. .Descendants()
  1540. .Elements(W.abstractNum)
  1541. .Where(e => e.Annotation<FromPreviousSourceSemaphore>() == null)
  1542. .Where(p =>
  1543. {
  1544. var thisNsidElement = p.Element(W.nsid);
  1545. if (thisNsidElement == null)
  1546. return false;
  1547. return (string)thisNsidElement.Attribute(W.val) == abstractNSID;
  1548. })
  1549. .FirstOrDefault();
  1550. if (newAbstractElement == null)
  1551. {
  1552. newAbstractElement = new XElement(abstractElement);
  1553. newAbstractElement.Attribute(W.abstractNumId).Value = abstractNumber.ToString();
  1554. abstractNumber++;
  1555. if (newNumbering.Root.Elements(W.abstractNum).Any())
  1556. newNumbering.Root.Elements(W.abstractNum).Last().AddAfterSelf(newAbstractElement);
  1557. else
  1558. newNumbering.Root.Add(newAbstractElement);
  1559. foreach (XElement pictId in newAbstractElement.Descendants(W.lvlPicBulletId))
  1560. {
  1561. string bulletId = (string)pictId.Attribute(W.val);
  1562. XElement numPicBullet = oldNumbering
  1563. .Descendants(W.numPicBullet)
  1564. .FirstOrDefault(d => (string)d.Attribute(W.numPicBulletId) == bulletId);
  1565. int maxNumPicBulletId = new int[] { -1 }.Concat(
  1566. newNumbering.Descendants(W.numPicBullet)
  1567. .Attributes(W.numPicBulletId)
  1568. .Select(a => (int)a))
  1569. .Max() + 1;
  1570. XElement newNumPicBullet = new XElement(numPicBullet);
  1571. newNumPicBullet.Attribute(W.numPicBulletId).Value = maxNumPicBulletId.ToString();
  1572. pictId.Attribute(W.val).Value = maxNumPicBulletId.ToString();
  1573. newNumbering.Root.AddFirst(newNumPicBullet);
  1574. }
  1575. }
  1576. string newAbstractId = newAbstractElement.Attribute(W.abstractNumId).Value;
  1577. // Copy numbering element, if necessary (use matching element with no overrides)
  1578. XElement newElement = null;
  1579. if (!element.Elements(W.lvlOverride).Any())
  1580. newElement = newNumbering
  1581. .Descendants()
  1582. .Elements(W.num)
  1583. .Where(p => !p.Elements(W.lvlOverride).Any() &&
  1584. ((string)p.Elements(W.abstractNumId).First().Attribute(W.val)) == newAbstractId)
  1585. .FirstOrDefault();
  1586. if (newElement == null)
  1587. {
  1588. newElement = new XElement(element);
  1589. newElement
  1590. .Elements(W.abstractNumId)
  1591. .First()
  1592. .Attribute(W.val).Value = newAbstractId;
  1593. newElement.Attribute(W.numId).Value = number.ToString();
  1594. number++;
  1595. newNumbering.Root.Add(newElement);
  1596. }
  1597. idElement.Attribute(W.val).Value = newElement.Attribute(W.numId).Value;
  1598. }
  1599. }
  1600. }
  1601. }
  1602. }
  1603. var newStyle = new XElement(style);
  1604. // get rid of anything not in the w: namespace
  1605. newStyle.Descendants().Where(d => d.Name.NamespaceName != W.w).Remove();
  1606. newStyle.Descendants().Attributes().Where(d => d.Name.NamespaceName != W.w).Remove();
  1607. toStyles.Root.Add(newStyle);
  1608. }
  1609. else
  1610. {
  1611. var toId = (string)toStyle.Attribute(W.styleId);
  1612. if (fromId != toId)
  1613. {
  1614. if (! newIds.ContainsKey(fromId))
  1615. newIds.Add(fromId, toId);
  1616. }
  1617. }
  1618. }
  1619. #if MergeStylesWithSameNames
  1620. if (newIds.Count > 0)
  1621. {
  1622. foreach (var style in toStyles
  1623. .Root
  1624. .Elements(W.style))
  1625. {
  1626. ConvertToNewId(style.Element(W.basedOn), newIds);
  1627. ConvertToNewId(style.Element(W.next), newIds);
  1628. }
  1629. foreach (var item in newContent.DescendantsAndSelf()
  1630. .Where(d => d.Name == W.pStyle ||
  1631. d.Name == W.rStyle ||
  1632. d.Name == W.tblStyle))
  1633. {
  1634. ConvertToNewId(item, newIds);
  1635. }
  1636. if (newDocument.MainDocumentPart.NumberingDefinitionsPart != null)
  1637. {
  1638. var newNumbering = newDocument.MainDocumentPart.NumberingDefinitionsPart.GetXDocument();
  1639. ConvertNumberingPartToNewIds(newNumbering, newIds);
  1640. }
  1641. // Convert source document, since numberings will be copied over after styles.
  1642. if (sourceDocument.MainDocumentPart.NumberingDefinitionsPart != null)
  1643. {
  1644. var sourceNumbering = sourceDocument.MainDocumentPart.NumberingDefinitionsPart.GetXDocument();
  1645. ConvertNumberingPartToNewIds(sourceNumbering, newIds);
  1646. }
  1647. }
  1648. #endif
  1649. }
  1650. private static void MergeLatentStyles(XDocument fromStyles, XDocument toStyles)
  1651. {
  1652. var fromLatentStyles = fromStyles.Descendants(W.latentStyles).FirstOrDefault();
  1653. if (fromLatentStyles == null)
  1654. return;
  1655. var toLatentStyles = toStyles.Descendants(W.latentStyles).FirstOrDefault();
  1656. if (toLatentStyles == null)
  1657. {
  1658. var newLatentStylesElement = new XElement(W.latentStyles,
  1659. fromLatentStyles.Attributes());
  1660. var globalDefaults = toStyles
  1661. .Descendants(W.docDefaults)
  1662. .FirstOrDefault();
  1663. if (globalDefaults == null)
  1664. {
  1665. var firstStyle = toStyles
  1666. .Root
  1667. .Elements(W.style)
  1668. .FirstOrDefault();
  1669. if (firstStyle == null)
  1670. toStyles.Root.Add(newLatentStylesElement);
  1671. else
  1672. firstStyle.AddBeforeSelf(newLatentStylesElement);
  1673. }
  1674. else
  1675. globalDefaults.AddAfterSelf(newLatentStylesElement);
  1676. }
  1677. toLatentStyles = toStyles.Descendants(W.latentStyles).FirstOrDefault();
  1678. if (toLatentStyles == null)
  1679. throw new OpenXmlPowerToolsException("Internal error");
  1680. var toStylesHash = new HashSet<string>();
  1681. foreach (var lse in toLatentStyles.Elements(W.lsdException))
  1682. toStylesHash.Add((string)lse.Attribute(W.name));
  1683. foreach (var fls in fromLatentStyles.Elements(W.lsdException))
  1684. {
  1685. var name = (string)fls.Attribute(W.name);
  1686. if (toStylesHash.Contains(name))
  1687. continue;
  1688. toLatentStyles.Add(fls);
  1689. toStylesHash.Add(name);
  1690. }
  1691. var count = toLatentStyles
  1692. .Elements(W.lsdException)
  1693. .Count();
  1694. toLatentStyles.SetAttributeValue(W.count, count);
  1695. }
  1696. private static void MergeDocDefaultStyles(XDocument xDocument, XDocument newXDoc)
  1697. {
  1698. var docDefaultStyles = xDocument.Descendants(W.docDefaults);
  1699. foreach (var docDefaultStyle in docDefaultStyles)
  1700. {
  1701. newXDoc.Root.Add(docDefaultStyle);
  1702. }
  1703. }
  1704. #if MergeStylesWithSameNames
  1705. private static void ConvertToNewId(XElement element, Dictionary<string, string> newIds)
  1706. {
  1707. if (element == null)
  1708. return;
  1709. var valueAttribute = element.Attribute(W.val);
  1710. string newId;
  1711. if (newIds.TryGetValue(valueAttribute.Value, out newId))
  1712. {
  1713. valueAttribute.Value = newId;
  1714. }
  1715. }
  1716. private static void ConvertNumberingPartToNewIds(XDocument newNumbering, Dictionary<string, string> newIds)
  1717. {
  1718. foreach (var abstractNum in newNumbering
  1719. .Root
  1720. .Elements(W.abstractNum))
  1721. {
  1722. ConvertToNewId(abstractNum.Element(W.styleLink), newIds);
  1723. ConvertToNewId(abstractNum.Element(W.numStyleLink), newIds);
  1724. }
  1725. foreach (var item in newNumbering
  1726. .Descendants()
  1727. .Where(d => d.Name == W.pStyle ||
  1728. d.Name == W.rStyle ||
  1729. d.Name == W.tblStyle))
  1730. {
  1731. ConvertToNewId(item, newIds);
  1732. }
  1733. }
  1734. #endif
  1735. private static void MergeFontTables(XDocument fromFontTable, XDocument toFontTable)
  1736. {
  1737. foreach (XElement font in fromFontTable.Root.Elements(W.font))
  1738. {
  1739. string name = font.Attribute(W.name).Value;
  1740. if (toFontTable
  1741. .Root
  1742. .Elements(W.font)
  1743. .Where(o => o.Attribute(W.name).Value == name)
  1744. .Count() == 0)
  1745. toFontTable.Root.Add(new XElement(font));
  1746. }
  1747. }
  1748. private static void CopyStylesAndFonts(WordprocessingDocument sourceDocument, WordprocessingDocument newDocument,
  1749. IEnumerable<XElement> newContent)
  1750. {
  1751. // Copy all styles to the new document
  1752. if (sourceDocument.MainDocumentPart.StyleDefinitionsPart != null)
  1753. {
  1754. XDocument oldStyles = sourceDocument.MainDocumentPart.StyleDefinitionsPart.GetXDocument();
  1755. if (newDocument.MainDocumentPart.StyleDefinitionsPart == null)
  1756. {
  1757. newDocument.MainDocumentPart.AddNewPart<StyleDefinitionsPart>();
  1758. XDocument newStyles = newDocument.MainDocumentPart.StyleDefinitionsPart.GetXDocument();
  1759. newStyles.Declaration.Standalone = Yes;
  1760. newStyles.Declaration.Encoding = Utf8;
  1761. newStyles.Add(oldStyles.Root);
  1762. }
  1763. else
  1764. {
  1765. XDocument newStyles = newDocument.MainDocumentPart.StyleDefinitionsPart.GetXDocument();
  1766. MergeStyles(sourceDocument, newDocument, oldStyles, newStyles, newContent);
  1767. MergeLatentStyles(oldStyles, newStyles);
  1768. }
  1769. }
  1770. // Copy all styles with effects to the new document
  1771. if (sourceDocument.MainDocumentPart.StylesWithEffectsPart != null)
  1772. {
  1773. XDocument oldStyles = sourceDocument.MainDocumentPart.StylesWithEffectsPart.GetXDocument();
  1774. if (newDocument.MainDocumentPart.StylesWithEffectsPart == null)
  1775. {
  1776. newDocument.MainDocumentPart.AddNewPart<StylesWithEffectsPart>();
  1777. XDocument newStyles = newDocument.MainDocumentPart.StylesWithEffectsPart.GetXDocument();
  1778. newStyles.Declaration.Standalone = Yes;
  1779. newStyles.Declaration.Encoding = Utf8;
  1780. newStyles.Add(oldStyles.Root);
  1781. }
  1782. else
  1783. {
  1784. XDocument newStyles = newDocument.MainDocumentPart.StylesWithEffectsPart.GetXDocument();
  1785. MergeStyles(sourceDocument, newDocument, oldStyles, newStyles, newContent);
  1786. MergeLatentStyles(oldStyles, newStyles);
  1787. }
  1788. }
  1789. // Copy fontTable to the new document
  1790. if (sourceDocument.MainDocumentPart.FontTablePart != null)
  1791. {
  1792. XDocument oldFontTable = sourceDocument.MainDocumentPart.FontTablePart.GetXDocument();
  1793. if (newDocument.MainDocumentPart.FontTablePart == null)
  1794. {
  1795. newDocument.MainDocumentPart.AddNewPart<FontTablePart>();
  1796. XDocument newFontTable = newDocument.MainDocumentPart.FontTablePart.GetXDocument();
  1797. newFontTable.Declaration.Standalone = Yes;
  1798. newFontTable.Declaration.Encoding = Utf8;
  1799. newFontTable.Add(oldFontTable.Root);
  1800. }
  1801. else
  1802. {
  1803. XDocument newFontTable = newDocument.MainDocumentPart.FontTablePart.GetXDocument();
  1804. MergeFontTables(oldFontTable, newFontTable);
  1805. }
  1806. }
  1807. }
  1808. private static void CopyComments(WordprocessingDocument sourceDocument, WordprocessingDocument newDocument,
  1809. IEnumerable<XElement> newContent, List<ImageData> images)
  1810. {
  1811. Dictionary<int, int> commentIdMap = new Dictionary<int, int>();
  1812. int number = 0;
  1813. XDocument oldComments = null;
  1814. XDocument newComments = null;
  1815. foreach (XElement comment in newContent.DescendantsAndSelf(W.commentReference))
  1816. {
  1817. if (oldComments == null)
  1818. oldComments = sourceDocument.MainDocumentPart.WordprocessingCommentsPart.GetXDocument();
  1819. if (newComments == null)
  1820. {
  1821. if (newDocument.MainDocumentPart.WordprocessingCommentsPart != null)
  1822. {
  1823. newComments = newDocument.MainDocumentPart.WordprocessingCommentsPart.GetXDocument();
  1824. newComments.Declaration.Standalone = Yes;
  1825. newComments.Declaration.Encoding = Utf8;
  1826. var ids = newComments.Root.Elements(W.comment).Select(f => (int)f.Attribute(W.id));
  1827. if (ids.Any())
  1828. number = ids.Max() + 1;
  1829. }
  1830. else
  1831. {
  1832. newDocument.MainDocumentPart.AddNewPart<WordprocessingCommentsPart>();
  1833. newComments = newDocument.MainDocumentPart.WordprocessingCommentsPart.GetXDocument();
  1834. newComments.Declaration.Standalone = Yes;
  1835. newComments.Declaration.Encoding = Utf8;
  1836. newComments.Add(new XElement(W.comments, NamespaceAttributes));
  1837. }
  1838. }
  1839. int id;
  1840. if (!int.TryParse((string)comment.Attribute(W.id), out id))
  1841. throw new DocumentBuilderException("Invalid document - invalid comment id");
  1842. XElement element = oldComments
  1843. .Descendants()
  1844. .Elements(W.comment)
  1845. .Where(p => {
  1846. int thisId;
  1847. if (! int.TryParse((string)p.Attribute(W.id), out thisId))
  1848. throw new DocumentBuilderException("Invalid document - invalid comment id");
  1849. return thisId == id;
  1850. })
  1851. .FirstOrDefault();
  1852. if (element == null)
  1853. throw new DocumentBuilderException("Invalid document - comment reference without associated comment in comments part");
  1854. XElement newElement = new XElement(element);
  1855. newElement.Attribute(W.id).Value = number.ToString();
  1856. newComments.Root.Add(newElement);
  1857. if (! commentIdMap.ContainsKey(id))
  1858. commentIdMap.Add(id, number);
  1859. number++;
  1860. }
  1861. foreach (var item in newContent.DescendantsAndSelf()
  1862. .Where(d => d.Name == W.commentReference ||
  1863. d.Name == W.commentRangeStart ||
  1864. d.Name == W.commentRangeEnd)
  1865. .ToList())
  1866. {
  1867. if (commentIdMap.ContainsKey((int)item.Attribute(W.id)))
  1868. item.Attribute(W.id).Value = commentIdMap[(int)item.Attribute(W.id)].ToString();
  1869. }
  1870. if (sourceDocument.MainDocumentPart.WordprocessingCommentsPart != null &&
  1871. newDocument.MainDocumentPart.WordprocessingCommentsPart != null)
  1872. {
  1873. AddRelationships(sourceDocument.MainDocumentPart.WordprocessingCommentsPart,
  1874. newDocument.MainDocumentPart.WordprocessingCommentsPart,
  1875. new[] { newDocument.MainDocumentPart.WordprocessingCommentsPart.GetXDocument().Root });
  1876. CopyRelatedPartsForContentParts(sourceDocument.MainDocumentPart.WordprocessingCommentsPart,
  1877. newDocument.MainDocumentPart.WordprocessingCommentsPart,
  1878. new[] { newDocument.MainDocumentPart.WordprocessingCommentsPart.GetXDocument().Root },
  1879. images);
  1880. }
  1881. }
  1882. private static void AdjustUniqueIds(WordprocessingDocument sourceDocument,
  1883. WordprocessingDocument newDocument, IEnumerable<XElement> newContent)
  1884. {
  1885. // adjust bookmark unique ids
  1886. int maxId = 0;
  1887. if (newDocument.MainDocumentPart.GetXDocument().Descendants(W.bookmarkStart).Any())
  1888. maxId = newDocument.MainDocumentPart.GetXDocument().Descendants(W.bookmarkStart)
  1889. .Select(d => (int)d.Attribute(W.id)).Max();
  1890. Dictionary<int, int> bookmarkIdMap = new Dictionary<int, int>();
  1891. foreach (var item in newContent.DescendantsAndSelf().Where(bm => bm.Name == W.bookmarkStart ||
  1892. bm.Name == W.bookmarkEnd))
  1893. {
  1894. int id;
  1895. if (!int.TryParse((string)item.Attribute(W.id), out id))
  1896. throw new DocumentBuilderException("Invalid document - invalid value for bookmark ID");
  1897. if (!bookmarkIdMap.ContainsKey(id))
  1898. bookmarkIdMap.Add(id, ++maxId);
  1899. }
  1900. foreach (var bookmarkElement in newContent.DescendantsAndSelf().Where(e => e.Name == W.bookmarkStart ||
  1901. e.Name == W.bookmarkEnd))
  1902. bookmarkElement.Attribute(W.id).Value = bookmarkIdMap[(int)bookmarkElement.Attribute(W.id)].ToString();
  1903. // adjust shape unique ids
  1904. // This doesn't work because OLEObjects refer to shapes by ID.
  1905. // Punting on this, because sooner or later, this will be a non-issue.
  1906. //foreach (var item in newContent.DescendantsAndSelf(VML.shape))
  1907. //{
  1908. // Guid g = Guid.NewGuid();
  1909. // string s = "R" + g.ToString().Replace("-", "");
  1910. // item.Attribute(NoNamespace.id).Value = s;
  1911. //}
  1912. }
  1913. private static void AdjustDocPrIds(WordprocessingDocument newDocument)
  1914. {
  1915. int docPrId = 0;
  1916. foreach (var item in newDocument.MainDocumentPart.GetXDocument().Descendants(WP.docPr))
  1917. item.Attribute(NoNamespace.id).Value = (++docPrId).ToString();
  1918. foreach (var header in newDocument.MainDocumentPart.HeaderParts)
  1919. foreach (var item in header.GetXDocument().Descendants(WP.docPr))
  1920. item.Attribute(NoNamespace.id).Value = (++docPrId).ToString();
  1921. foreach (var footer in newDocument.MainDocumentPart.FooterParts)
  1922. foreach (var item in footer.GetXDocument().Descendants(WP.docPr))
  1923. item.Attribute(NoNamespace.id).Value = (++docPrId).ToString();
  1924. if (newDocument.MainDocumentPart.FootnotesPart != null)
  1925. foreach (var item in newDocument.MainDocumentPart.FootnotesPart.GetXDocument().Descendants(WP.docPr))
  1926. item.Attribute(NoNamespace.id).Value = (++docPrId).ToString();
  1927. if (newDocument.MainDocumentPart.EndnotesPart != null)
  1928. foreach (var item in newDocument.MainDocumentPart.EndnotesPart.GetXDocument().Descendants(WP.docPr))
  1929. item.Attribute(NoNamespace.id).Value = (++docPrId).ToString();
  1930. }
  1931. // This probably doesn't need to be done, except that the Open XML SDK will not validate
  1932. // documents that contain the o:gfxdata attribute.
  1933. private static void RemoveGfxdata(IEnumerable<XElement> newContent)
  1934. {
  1935. newContent.DescendantsAndSelf().Attributes(O.gfxdata).Remove();
  1936. }
  1937. private static object InsertTransform(XNode node, List<XElement> newContent)
  1938. {
  1939. XElement element = node as XElement;
  1940. if (element != null)
  1941. {
  1942. if (element.Annotation<ReplaceSemaphore>() != null)
  1943. return newContent;
  1944. return new XElement(element.Name,
  1945. element.Attributes(),
  1946. element.Nodes().Select(n => InsertTransform(n, newContent)));
  1947. }
  1948. return node;
  1949. }
  1950. private class ReplaceSemaphore { }
  1951. // Rules for sections
  1952. // - if KeepSections for all documents in the source collection are false, then it takes the section
  1953. // from the first document.
  1954. // - if you specify true for any document, and if the last section is part of the specified content,
  1955. // then that section is copied. If any paragraph in the content has a section, then that section
  1956. // is copied.
  1957. // - if you specify true for any document, and there are no sections for any paragraphs, then no
  1958. // sections are copied.
  1959. private static void AppendDocument(WordprocessingDocument sourceDocument, WordprocessingDocument newDocument,
  1960. List<XElement> newContent, bool keepSection, string insertId, List<ImageData> images)
  1961. {
  1962. FixRanges(sourceDocument.MainDocumentPart.GetXDocument(), newContent);
  1963. AddRelationships(sourceDocument.MainDocumentPart, newDocument.MainDocumentPart, newContent);
  1964. CopyRelatedPartsForContentParts(sourceDocument.MainDocumentPart, newDocument.MainDocumentPart,
  1965. newContent, images);
  1966. // Append contents
  1967. XDocument newMainXDoc = newDocument.MainDocumentPart.GetXDocument();
  1968. newMainXDoc.Declaration.Standalone = Yes;
  1969. newMainXDoc.Declaration.Encoding = Utf8;
  1970. if (keepSection == false)
  1971. {
  1972. List<XElement> adjustedContents = newContent.Where(e => e.Name != W.sectPr).ToList();
  1973. adjustedContents.DescendantsAndSelf(W.sectPr).Remove();
  1974. newContent = adjustedContents;
  1975. }
  1976. var listOfSectionProps = newContent.DescendantsAndSelf(W.sectPr).ToList();
  1977. foreach (var sectPr in listOfSectionProps)
  1978. AddSectionAndDependencies(sourceDocument, newDocument, sectPr, images);
  1979. CopyStylesAndFonts(sourceDocument, newDocument, newContent);
  1980. CopyNumbering(sourceDocument, newDocument, newContent, images);
  1981. CopyComments(sourceDocument, newDocument, newContent, images);
  1982. CopyFootnotes(sourceDocument, newDocument, newContent, images);
  1983. CopyEndnotes(sourceDocument, newDocument, newContent, images);
  1984. AdjustUniqueIds(sourceDocument, newDocument, newContent);
  1985. RemoveGfxdata(newContent);
  1986. CopyCustomXmlPartsForDataBoundContentControls(sourceDocument, newDocument, newContent);
  1987. CopyWebExtensions(sourceDocument, newDocument);
  1988. if (insertId != null)
  1989. {
  1990. XElement insertElementToReplace = newMainXDoc
  1991. .Descendants(PtOpenXml.Insert)
  1992. .FirstOrDefault(i => (string)i.Attribute(PtOpenXml.Id) == insertId);
  1993. if (insertElementToReplace != null)
  1994. insertElementToReplace.AddAnnotation(new ReplaceSemaphore());
  1995. newMainXDoc.Element(W.document).ReplaceWith((XElement)InsertTransform(newMainXDoc.Root, newContent));
  1996. }
  1997. else
  1998. newMainXDoc.Root.Element(W.body).Add(newContent);
  1999. if (newMainXDoc.Descendants().Any(d =>
  2000. {
  2001. if (d.Name.Namespace == PtOpenXml.pt || d.Name.Namespace == PtOpenXml.ptOpenXml)
  2002. return true;
  2003. if (d.Attributes().Any(att => att.Name.Namespace == PtOpenXml.pt || att.Name.Namespace == PtOpenXml.ptOpenXml))
  2004. return true;
  2005. return false;
  2006. }))
  2007. {
  2008. var root = newMainXDoc.Root;
  2009. if (!root.Attributes().Any(na => na.Value == PtOpenXml.pt.NamespaceName))
  2010. {
  2011. root.Add(new XAttribute(XNamespace.Xmlns + "pt", PtOpenXml.pt.NamespaceName));
  2012. AddToIgnorable(root, "pt");
  2013. }
  2014. if (!root.Attributes().Any(na => na.Value == PtOpenXml.ptOpenXml.NamespaceName))
  2015. {
  2016. root.Add(new XAttribute(XNamespace.Xmlns + "pt14", PtOpenXml.ptOpenXml.NamespaceName));
  2017. AddToIgnorable(root, "pt14");
  2018. }
  2019. }
  2020. }
  2021. private static void CopyWebExtensions(WordprocessingDocument sourceDocument, WordprocessingDocument newDocument)
  2022. {
  2023. if (sourceDocument.WebExTaskpanesPart != null && newDocument.WebExTaskpanesPart == null)
  2024. {
  2025. newDocument.AddWebExTaskpanesPart();
  2026. newDocument.WebExTaskpanesPart.GetXDocument().Add(sourceDocument.WebExTaskpanesPart.GetXDocument().Root);
  2027. foreach (var sourceWebExtensionPart in sourceDocument.WebExTaskpanesPart.WebExtensionParts)
  2028. {
  2029. var newWebExtensionpart = newDocument.WebExTaskpanesPart.AddNewPart<WebExtensionPart>(
  2030. sourceDocument.WebExTaskpanesPart.GetIdOfPart(sourceWebExtensionPart));
  2031. newWebExtensionpart.GetXDocument().Add(sourceWebExtensionPart.GetXDocument().Root);
  2032. }
  2033. }
  2034. }
  2035. private static void AddToIgnorable(XElement root, string v)
  2036. {
  2037. var ignorable = root.Attribute(MC.Ignorable);
  2038. if (ignorable != null)
  2039. {
  2040. var val = (string)ignorable;
  2041. val = val + " " + v;
  2042. ignorable.Remove();
  2043. root.SetAttributeValue(MC.Ignorable, val);
  2044. }
  2045. }
  2046. /// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2047. /// New method to support new functionality
  2048. private static void AppendDocument(WordprocessingDocument sourceDocument, WordprocessingDocument newDocument, OpenXmlPart part,
  2049. List<XElement> newContent, bool keepSection, string insertId, List<ImageData> images)
  2050. {
  2051. // Append contents
  2052. XDocument partXDoc = part.GetXDocument();
  2053. partXDoc.Declaration.Standalone = Yes;
  2054. partXDoc.Declaration.Encoding = Utf8;
  2055. FixRanges(part.GetXDocument(), newContent);
  2056. AddRelationships(sourceDocument.MainDocumentPart, part, newContent);
  2057. CopyRelatedPartsForContentParts(sourceDocument.MainDocumentPart, part,
  2058. newContent, images);
  2059. // never keep sections for content to be inserted into a header/footer
  2060. List<XElement> adjustedContents = newContent.Where(e => e.Name != W.sectPr).ToList();
  2061. adjustedContents.DescendantsAndSelf(W.sectPr).Remove();
  2062. newContent = adjustedContents;
  2063. CopyNumbering(sourceDocument, newDocument, newContent, images);
  2064. CopyComments(sourceDocument, newDocument, newContent, images);
  2065. AdjustUniqueIds(sourceDocument, newDocument, newContent);
  2066. RemoveGfxdata(newContent);
  2067. if (insertId == null)
  2068. throw new OpenXmlPowerToolsException("Internal error");
  2069. XElement insertElementToReplace = partXDoc
  2070. .Descendants(PtOpenXml.Insert)
  2071. .FirstOrDefault(i => (string)i.Attribute(PtOpenXml.Id) == insertId);
  2072. if (insertElementToReplace != null)
  2073. insertElementToReplace.AddAnnotation(new ReplaceSemaphore());
  2074. partXDoc.Elements().First().ReplaceWith((XElement)InsertTransform(partXDoc.Root, newContent));
  2075. }
  2076. /// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  2077. public static WmlDocument ExtractGlossaryDocument(WmlDocument wmlGlossaryDocument)
  2078. {
  2079. if (RelationshipMarkup == null)
  2080. InitRelationshipMarkup();
  2081. using (MemoryStream ms = new MemoryStream())
  2082. {
  2083. ms.Write(wmlGlossaryDocument.DocumentByteArray, 0, wmlGlossaryDocument.DocumentByteArray.Length);
  2084. using (WordprocessingDocument wDoc = WordprocessingDocument.Open(ms, false))
  2085. {
  2086. if (wDoc.MainDocumentPart.GlossaryDocumentPart == null)
  2087. return null;
  2088. var fromXd = wDoc.MainDocumentPart.GlossaryDocumentPart.GetXDocument();
  2089. if (fromXd.Root == null)
  2090. return null;
  2091. using (MemoryStream outMs = new MemoryStream())
  2092. {
  2093. using (WordprocessingDocument outWDoc = WordprocessingDocument.Create(outMs, DocumentFormat.OpenXml.WordprocessingDocumentType.Document))
  2094. {
  2095. List<ImageData> images = new List<ImageData>();
  2096. MainDocumentPart mdp = outWDoc.AddMainDocumentPart();
  2097. var mdpXd = mdp.GetXDocument();
  2098. XElement root = new XElement(W.document);
  2099. if (mdpXd.Root == null)
  2100. mdpXd.Add(root);
  2101. else
  2102. mdpXd.Root.ReplaceWith(root);
  2103. root.Add(new XElement(W.body,
  2104. fromXd.Root.Elements(W.docParts)));
  2105. mdp.PutXDocument();
  2106. var newContent = fromXd.Root.Elements(W.docParts);
  2107. CopyGlossaryDocumentPartsFromGD(wDoc, outWDoc, newContent, images);
  2108. CopyRelatedPartsForContentParts(wDoc.MainDocumentPart.GlossaryDocumentPart, mdp, newContent, images);
  2109. }
  2110. return new WmlDocument("Glossary.docx", outMs.ToArray());
  2111. }
  2112. }
  2113. }
  2114. }
  2115. private static void CopyGlossaryDocumentPartsFromGD(WordprocessingDocument sourceDocument, WordprocessingDocument newDocument,
  2116. IEnumerable<XElement> newContent, List<ImageData> images)
  2117. {
  2118. // Copy all styles to the new document
  2119. if (sourceDocument.MainDocumentPart.GlossaryDocumentPart.StyleDefinitionsPart != null)
  2120. {
  2121. XDocument oldStyles = sourceDocument.MainDocumentPart.GlossaryDocumentPart.StyleDefinitionsPart.GetXDocument();
  2122. if (newDocument.MainDocumentPart.StyleDefinitionsPart == null)
  2123. {
  2124. newDocument.MainDocumentPart.AddNewPart<StyleDefinitionsPart>();
  2125. XDocument newStyles = newDocument.MainDocumentPart.StyleDefinitionsPart.GetXDocument();
  2126. newStyles.Declaration.Standalone = Yes;
  2127. newStyles.Declaration.Encoding = Utf8;
  2128. newStyles.Add(oldStyles.Root);
  2129. newDocument.MainDocumentPart.StyleDefinitionsPart.PutXDocument();
  2130. }
  2131. else
  2132. {
  2133. XDocument newStyles = newDocument.MainDocumentPart.StyleDefinitionsPart.GetXDocument();
  2134. MergeStyles(sourceDocument, newDocument, oldStyles, newStyles, newContent);
  2135. newDocument.MainDocumentPart.StyleDefinitionsPart.PutXDocument();
  2136. }
  2137. }
  2138. // Copy fontTable to the new document
  2139. if (sourceDocument.MainDocumentPart.GlossaryDocumentPart.FontTablePart != null)
  2140. {
  2141. XDocument oldFontTable = sourceDocument.MainDocumentPart.GlossaryDocumentPart.FontTablePart.GetXDocument();
  2142. if (newDocument.MainDocumentPart.FontTablePart == null)
  2143. {
  2144. newDocument.MainDocumentPart.AddNewPart<FontTablePart>();
  2145. XDocument newFontTable = newDocument.MainDocumentPart.FontTablePart.GetXDocument();
  2146. newFontTable.Declaration.Standalone = Yes;
  2147. newFontTable.Declaration.Encoding = Utf8;
  2148. newFontTable.Add(oldFontTable.Root);
  2149. newDocument.MainDocumentPart.FontTablePart.PutXDocument();
  2150. }
  2151. else
  2152. {
  2153. XDocument newFontTable = newDocument.MainDocumentPart.FontTablePart.GetXDocument();
  2154. MergeFontTables(oldFontTable, newFontTable);
  2155. newDocument.MainDocumentPart.FontTablePart.PutXDocument();
  2156. }
  2157. }
  2158. DocumentSettingsPart oldSettingsPart = sourceDocument.MainDocumentPart.GlossaryDocumentPart.DocumentSettingsPart;
  2159. if (oldSettingsPart != null)
  2160. {
  2161. DocumentSettingsPart newSettingsPart = newDocument.MainDocumentPart.AddNewPart<DocumentSettingsPart>();
  2162. XDocument settingsXDoc = oldSettingsPart.GetXDocument();
  2163. AddRelationships(oldSettingsPart, newSettingsPart, new[] { settingsXDoc.Root });
  2164. //CopyFootnotesPart(sourceDocument, newDocument, settingsXDoc, images);
  2165. //CopyEndnotesPart(sourceDocument, newDocument, settingsXDoc, images);
  2166. XDocument newXDoc = newDocument.MainDocumentPart.DocumentSettingsPart.GetXDocument();
  2167. newXDoc.Declaration.Standalone = Yes;
  2168. newXDoc.Declaration.Encoding = Utf8;
  2169. newXDoc.Add(settingsXDoc.Root);
  2170. CopyRelatedPartsForContentParts(oldSettingsPart, newSettingsPart, new[] { newXDoc.Root }, images);
  2171. newSettingsPart.PutXDocument(newXDoc);
  2172. }
  2173. WebSettingsPart oldWebSettingsPart = sourceDocument.MainDocumentPart.GlossaryDocumentPart.WebSettingsPart;
  2174. if (oldWebSettingsPart != null)
  2175. {
  2176. WebSettingsPart newWebSettingsPart = newDocument.MainDocumentPart.AddNewPart<WebSettingsPart>();
  2177. XDocument settingsXDoc = oldWebSettingsPart.GetXDocument();
  2178. AddRelationships(oldWebSettingsPart, newWebSettingsPart, new[] { settingsXDoc.Root });
  2179. XDocument newXDoc = newDocument.MainDocumentPart.WebSettingsPart.GetXDocument();
  2180. newXDoc.Declaration.Standalone = Yes;
  2181. newXDoc.Declaration.Encoding = Utf8;
  2182. newXDoc.Add(settingsXDoc.Root);
  2183. newWebSettingsPart.PutXDocument(newXDoc);
  2184. }
  2185. NumberingDefinitionsPart oldNumberingDefinitionsPart = sourceDocument.MainDocumentPart.GlossaryDocumentPart.NumberingDefinitionsPart;
  2186. if (oldNumberingDefinitionsPart != null)
  2187. {
  2188. CopyNumberingForGlossaryDocumentPartFromGD(oldNumberingDefinitionsPart, newDocument, newContent, images);
  2189. }
  2190. }
  2191. private static void CopyGlossaryDocumentPartsToGD(WordprocessingDocument sourceDocument, WordprocessingDocument newDocument,
  2192. IEnumerable<XElement> newContent, List<ImageData> images)
  2193. {
  2194. // Copy all styles to the new document
  2195. if (sourceDocument.MainDocumentPart.StyleDefinitionsPart != null)
  2196. {
  2197. XDocument oldStyles = sourceDocument.MainDocumentPart.StyleDefinitionsPart.GetXDocument();
  2198. newDocument.MainDocumentPart.GlossaryDocumentPart.AddNewPart<StyleDefinitionsPart>();
  2199. XDocument newStyles = newDocument.MainDocumentPart.GlossaryDocumentPart.StyleDefinitionsPart.GetXDocument();
  2200. newStyles.Declaration.Standalone = Yes;
  2201. newStyles.Declaration.Encoding = Utf8;
  2202. newStyles.Add(oldStyles.Root);
  2203. newDocument.MainDocumentPart.GlossaryDocumentPart.StyleDefinitionsPart.PutXDocument();
  2204. }
  2205. // Copy fontTable to the new document
  2206. if (sourceDocument.MainDocumentPart.FontTablePart != null)
  2207. {
  2208. XDocument oldFontTable = sourceDocument.MainDocumentPart.FontTablePart.GetXDocument();
  2209. newDocument.MainDocumentPart.GlossaryDocumentPart.AddNewPart<FontTablePart>();
  2210. XDocument newFontTable = newDocument.MainDocumentPart.GlossaryDocumentPart.FontTablePart.GetXDocument();
  2211. newFontTable.Declaration.Standalone = Yes;
  2212. newFontTable.Declaration.Encoding = Utf8;
  2213. newFontTable.Add(oldFontTable.Root);
  2214. newDocument.MainDocumentPart.FontTablePart.PutXDocument();
  2215. }
  2216. DocumentSettingsPart oldSettingsPart = sourceDocument.MainDocumentPart.DocumentSettingsPart;
  2217. if (oldSettingsPart != null)
  2218. {
  2219. DocumentSettingsPart newSettingsPart = newDocument.MainDocumentPart.GlossaryDocumentPart.AddNewPart<DocumentSettingsPart>();
  2220. XDocument settingsXDoc = oldSettingsPart.GetXDocument();
  2221. AddRelationships(oldSettingsPart, newSettingsPart, new[] { settingsXDoc.Root });
  2222. //CopyFootnotesPart(sourceDocument, newDocument, settingsXDoc, images);
  2223. //CopyEndnotesPart(sourceDocument, newDocument, settingsXDoc, images);
  2224. XDocument newXDoc = newDocument.MainDocumentPart.GlossaryDocumentPart.DocumentSettingsPart.GetXDocument();
  2225. newXDoc.Declaration.Standalone = Yes;
  2226. newXDoc.Declaration.Encoding = Utf8;
  2227. newXDoc.Add(settingsXDoc.Root);
  2228. CopyRelatedPartsForContentParts(oldSettingsPart, newSettingsPart, new[] { newXDoc.Root }, images);
  2229. newSettingsPart.PutXDocument(newXDoc);
  2230. }
  2231. WebSettingsPart oldWebSettingsPart = sourceDocument.MainDocumentPart.WebSettingsPart;
  2232. if (oldWebSettingsPart != null)
  2233. {
  2234. WebSettingsPart newWebSettingsPart = newDocument.MainDocumentPart.GlossaryDocumentPart.AddNewPart<WebSettingsPart>();
  2235. XDocument settingsXDoc = oldWebSettingsPart.GetXDocument();
  2236. AddRelationships(oldWebSettingsPart, newWebSettingsPart, new[] { settingsXDoc.Root });
  2237. XDocument newXDoc = newDocument.MainDocumentPart.GlossaryDocumentPart.WebSettingsPart.GetXDocument();
  2238. newXDoc.Declaration.Standalone = Yes;
  2239. newXDoc.Declaration.Encoding = Utf8;
  2240. newXDoc.Add(settingsXDoc.Root);
  2241. newWebSettingsPart.PutXDocument(newXDoc);
  2242. }
  2243. NumberingDefinitionsPart oldNumberingDefinitionsPart = sourceDocument.MainDocumentPart.NumberingDefinitionsPart;
  2244. if (oldNumberingDefinitionsPart != null)
  2245. {
  2246. CopyNumberingForGlossaryDocumentPartToGD(oldNumberingDefinitionsPart, newDocument, newContent, images);
  2247. }
  2248. }
  2249. #if false
  2250. At various locations in Open-Xml-PowerTools, you will find examples of Open XML markup that is associated with code associated with
  2251. querying or generating that markup. This is an example of the GlossaryDocument part.
  2252. <w:glossaryDocument xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:cx="http://schemas.microsoft.com/office/drawing/2014/chartex" xmlns:cx1="http://schemas.microsoft.com/office/drawing/2015/9/8/chartex" xmlns:cx2="http://schemas.microsoft.com/office/drawing/2015/10/21/chartex" xmlns:cx3="http://schemas.microsoft.com/office/drawing/2016/5/9/chartex" xmlns:cx4="http://schemas.microsoft.com/office/drawing/2016/5/10/chartex" xmlns:cx5="http://schemas.microsoft.com/office/drawing/2016/5/11/chartex" xmlns:cx6="http://schemas.microsoft.com/office/drawing/2016/5/12/chartex" xmlns:cx7="http://schemas.microsoft.com/office/drawing/2016/5/13/chartex" xmlns:cx8="http://schemas.microsoft.com/office/drawing/2016/5/14/chartex" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:aink="http://schemas.microsoft.com/office/drawing/2016/ink" xmlns:am3d="http://schemas.microsoft.com/office/drawing/2017/model3d" 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:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" 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:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" xmlns:w16cid="http://schemas.microsoft.com/office/word/2016/wordml/cid" xmlns:w16se="http://schemas.microsoft.com/office/word/2015/wordml/symex" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" mc:Ignorable="w14 w15 w16se w16cid wp14">
  2253. <w:docParts>
  2254. <w:docPart>
  2255. <w:docPartPr>
  2256. <w:name w:val="CDE7B64C7BB446AE905B622B0A882EB6" />
  2257. <w:category>
  2258. <w:name w:val="General" />
  2259. <w:gallery w:val="placeholder" />
  2260. </w:category>
  2261. <w:types>
  2262. <w:type w:val="bbPlcHdr" />
  2263. </w:types>
  2264. <w:behaviors>
  2265. <w:behavior w:val="content" />
  2266. </w:behaviors>
  2267. <w:guid w:val="{13882A71-B5B7-4421-ACBB-9B61C61B3034}" />
  2268. </w:docPartPr>
  2269. <w:docPartBody>
  2270. <w:p w:rsidR="00004EEA" w:rsidRDefault="00AD57F5" w:rsidP="00AD57F5">
  2271. <w:pPr>
  2272. <w:pStyle w:val="CDE7B64C7BB446AE905B622B0A882EB6" />
  2273. </w:pPr>
  2274. <w:r w:rsidRPr="00FB619D">
  2275. <w:rPr>
  2276. <w:rStyle w:val="PlaceholderText" />
  2277. <w:lang w:val="da-DK" />
  2278. </w:rPr>
  2279. <w:t>Produktnavn</w:t>
  2280. </w:r>
  2281. <w:r w:rsidRPr="007379EE">
  2282. <w:rPr>
  2283. <w:rStyle w:val="PlaceholderText" />
  2284. </w:rPr>
  2285. <w:t>.</w:t>
  2286. </w:r>
  2287. </w:p>
  2288. </w:docPartBody>
  2289. </w:docPart>
  2290. </w:docParts>
  2291. </w:glossaryDocument>
  2292. #endif
  2293. private static void CopyCustomXmlPartsForDataBoundContentControls(WordprocessingDocument sourceDocument, WordprocessingDocument newDocument, IEnumerable<XElement> newContent)
  2294. {
  2295. List<string> itemList = new List<string>();
  2296. foreach (string itemId in newContent
  2297. .Descendants(W.dataBinding)
  2298. .Select(e => (string)e.Attribute(W.storeItemID)))
  2299. if (!itemList.Contains(itemId))
  2300. itemList.Add(itemId);
  2301. foreach (CustomXmlPart customXmlPart in sourceDocument.MainDocumentPart.CustomXmlParts)
  2302. {
  2303. OpenXmlPart propertyPart = customXmlPart
  2304. .Parts
  2305. .Select(p => p.OpenXmlPart)
  2306. .Where(p => p.ContentType == "application/vnd.openxmlformats-officedocument.customXmlProperties+xml")
  2307. .FirstOrDefault();
  2308. if (propertyPart != null)
  2309. {
  2310. XDocument propertyPartDoc = propertyPart.GetXDocument();
  2311. if (itemList.Contains(propertyPartDoc.Root.Attribute(DS.itemID).Value))
  2312. {
  2313. CustomXmlPart newPart = newDocument.MainDocumentPart.AddCustomXmlPart(customXmlPart.ContentType);
  2314. newPart.GetXDocument().Add(customXmlPart.GetXDocument().Root);
  2315. foreach (OpenXmlPart propPart in customXmlPart.Parts.Select(p => p.OpenXmlPart))
  2316. {
  2317. CustomXmlPropertiesPart newPropPart = newPart.AddNewPart<CustomXmlPropertiesPart>();
  2318. newPropPart.GetXDocument().Add(propPart.GetXDocument().Root);
  2319. }
  2320. }
  2321. }
  2322. }
  2323. }
  2324. private static Dictionary<XName, XName[]> RelationshipMarkup = null;
  2325. private static void UpdateContent(IEnumerable<XElement> newContent, XName elementToModify, string oldRid, string newRid)
  2326. {
  2327. foreach (var attributeName in RelationshipMarkup[elementToModify])
  2328. {
  2329. var elementsToUpdate = newContent
  2330. .Descendants(elementToModify)
  2331. .Where(e => (string)e.Attribute(attributeName) == oldRid);
  2332. foreach (var element in elementsToUpdate)
  2333. element.Attribute(attributeName).Value = newRid;
  2334. }
  2335. }
  2336. private static void AddRelationships(OpenXmlPart oldPart, OpenXmlPart newPart, IEnumerable<XElement> newContent)
  2337. {
  2338. var relevantElements = newContent.DescendantsAndSelf()
  2339. .Where(d => RelationshipMarkup.ContainsKey(d.Name) &&
  2340. d.Attributes().Any(a => RelationshipMarkup[d.Name].Contains(a.Name)));
  2341. foreach (var e in relevantElements)
  2342. {
  2343. if (e.Name == W.hyperlink)
  2344. {
  2345. string relId = (string)e.Attribute(R.id);
  2346. if (string.IsNullOrEmpty(relId))
  2347. continue;
  2348. var tempHyperlink = newPart.HyperlinkRelationships.FirstOrDefault(h => h.Id == relId);
  2349. if (tempHyperlink != null)
  2350. continue;
  2351. Guid g = Guid.NewGuid();
  2352. string newRid = $"R{g:N}";
  2353. var oldHyperlink = oldPart.HyperlinkRelationships.FirstOrDefault(h => h.Id == relId);
  2354. if (oldHyperlink == null)
  2355. continue;
  2356. //throw new DocumentBuilderInternalException("Internal Error 0002");
  2357. newPart.AddHyperlinkRelationship(oldHyperlink.Uri, oldHyperlink.IsExternal, newRid);
  2358. UpdateContent(newContent, e.Name, relId, newRid);
  2359. }
  2360. if (e.Name == W.attachedTemplate || e.Name == W.saveThroughXslt)
  2361. {
  2362. string relId = (string)e.Attribute(R.id);
  2363. if (string.IsNullOrEmpty(relId))
  2364. continue;
  2365. var tempExternalRelationship = newPart.ExternalRelationships.FirstOrDefault(h => h.Id == relId);
  2366. if (tempExternalRelationship != null)
  2367. continue;
  2368. Guid g = Guid.NewGuid();
  2369. string newRid = $"R{g:N}";
  2370. var oldRel = oldPart.ExternalRelationships.FirstOrDefault(h => h.Id == relId);
  2371. if (oldRel == null)
  2372. throw new DocumentBuilderInternalException("Source {0} is invalid document - hyperlink contains invalid references");
  2373. newPart.AddExternalRelationship(oldRel.RelationshipType, oldRel.Uri, newRid);
  2374. UpdateContent(newContent, e.Name, relId, newRid);
  2375. }
  2376. if (e.Name == A.hlinkClick || e.Name == A.hlinkHover || e.Name == A.hlinkMouseOver)
  2377. {
  2378. string relId = (string)e.Attribute(R.id);
  2379. if (string.IsNullOrEmpty(relId))
  2380. continue;
  2381. var tempHyperlink = newPart.HyperlinkRelationships.FirstOrDefault(h => h.Id == relId);
  2382. if (tempHyperlink != null)
  2383. continue;
  2384. Guid g = Guid.NewGuid();
  2385. string newRid = $"R{g:N}";
  2386. var oldHyperlink = oldPart.HyperlinkRelationships.FirstOrDefault(h => h.Id == relId);
  2387. if (oldHyperlink == null)
  2388. continue;
  2389. newPart.AddHyperlinkRelationship(oldHyperlink.Uri, oldHyperlink.IsExternal, newRid);
  2390. UpdateContent(newContent, e.Name, relId, newRid);
  2391. }
  2392. if (e.Name == VML.imagedata)
  2393. {
  2394. string relId = (string)e.Attribute(R.href);
  2395. if (string.IsNullOrEmpty(relId))
  2396. continue;
  2397. var tempExternalRelationship = newPart.ExternalRelationships.FirstOrDefault(h => h.Id == relId);
  2398. if (tempExternalRelationship != null)
  2399. continue;
  2400. Guid g = Guid.NewGuid();
  2401. string newRid = $"R{g:N}";
  2402. var oldRel = oldPart.ExternalRelationships.FirstOrDefault(h => h.Id == relId);
  2403. if (oldRel == null)
  2404. throw new DocumentBuilderInternalException("Internal Error 0006");
  2405. newPart.AddExternalRelationship(oldRel.RelationshipType, oldRel.Uri, newRid);
  2406. UpdateContent(newContent, e.Name, relId, newRid);
  2407. }
  2408. if (e.Name == A.blip)
  2409. {
  2410. // <a:blip r:embed="rId6" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" />
  2411. string relId = (string)e.Attribute(R.link);
  2412. //if (relId == null)
  2413. // relId = (string)e.Attribute(R.embed);
  2414. if (string.IsNullOrEmpty(relId))
  2415. continue;
  2416. var tempExternalRelationship = newPart.ExternalRelationships.FirstOrDefault(h => h.Id == relId);
  2417. if (tempExternalRelationship != null)
  2418. continue;
  2419. Guid g = Guid.NewGuid();
  2420. string newRid = $"R{g:N}";
  2421. var oldRel = oldPart.ExternalRelationships.FirstOrDefault(h => h.Id == relId);
  2422. if (oldRel == null)
  2423. continue;
  2424. newPart.AddExternalRelationship(oldRel.RelationshipType, oldRel.Uri, newRid);
  2425. UpdateContent(newContent, e.Name, relId, newRid);
  2426. }
  2427. }
  2428. }
  2429. private class FromPreviousSourceSemaphore { };
  2430. private static void CopyNumbering(WordprocessingDocument sourceDocument, WordprocessingDocument newDocument,
  2431. IEnumerable<XElement> newContent, List<ImageData> images)
  2432. {
  2433. Dictionary<int, int> numIdMap = new Dictionary<int, int>();
  2434. int number = 1;
  2435. int abstractNumber = 0;
  2436. XDocument oldNumbering = null;
  2437. XDocument newNumbering = null;
  2438. foreach (XElement numReference in newContent.DescendantsAndSelf(W.numPr))
  2439. {
  2440. XElement idElement = numReference.Descendants(W.numId).FirstOrDefault();
  2441. if (idElement != null)
  2442. {
  2443. if (oldNumbering == null)
  2444. oldNumbering = sourceDocument.MainDocumentPart.NumberingDefinitionsPart.GetXDocument();
  2445. if (newNumbering == null)
  2446. {
  2447. if (newDocument.MainDocumentPart.NumberingDefinitionsPart != null)
  2448. {
  2449. newNumbering = newDocument.MainDocumentPart.NumberingDefinitionsPart.GetXDocument();
  2450. var numIds = newNumbering
  2451. .Root
  2452. .Elements(W.num)
  2453. .Select(f => (int)f.Attribute(W.numId));
  2454. if (numIds.Any())
  2455. number = numIds.Max() + 1;
  2456. numIds = newNumbering
  2457. .Root
  2458. .Elements(W.abstractNum)
  2459. .Select(f => (int)f.Attribute(W.abstractNumId));
  2460. if (numIds.Any())
  2461. abstractNumber = numIds.Max() + 1;
  2462. }
  2463. else
  2464. {
  2465. newDocument.MainDocumentPart.AddNewPart<NumberingDefinitionsPart>();
  2466. newNumbering = newDocument.MainDocumentPart.NumberingDefinitionsPart.GetXDocument();
  2467. newNumbering.Declaration.Standalone = Yes;
  2468. newNumbering.Declaration.Encoding = Utf8;
  2469. newNumbering.Add(new XElement(W.numbering, NamespaceAttributes));
  2470. }
  2471. }
  2472. int numId = (int)idElement.Attribute(W.val);
  2473. if (numId != 0)
  2474. {
  2475. XElement element = oldNumbering
  2476. .Descendants(W.num)
  2477. .Where(p => ((int)p.Attribute(W.numId)) == numId)
  2478. .FirstOrDefault();
  2479. if (element == null)
  2480. continue;
  2481. // Copy abstract numbering element, if necessary (use matching NSID)
  2482. string abstractNumIdStr = (string)element
  2483. .Elements(W.abstractNumId)
  2484. .First()
  2485. .Attribute(W.val);
  2486. int abstractNumId;
  2487. if (!int.TryParse(abstractNumIdStr, out abstractNumId))
  2488. throw new DocumentBuilderException("Invalid document - invalid value for abstractNumId");
  2489. XElement abstractElement = oldNumbering
  2490. .Descendants()
  2491. .Elements(W.abstractNum)
  2492. .Where(p => ((int)p.Attribute(W.abstractNumId)) == abstractNumId)
  2493. .First();
  2494. XElement nsidElement = abstractElement
  2495. .Element(W.nsid);
  2496. string abstractNSID = null;
  2497. if (nsidElement != null)
  2498. abstractNSID = (string)nsidElement
  2499. .Attribute(W.val);
  2500. XElement newAbstractElement = newNumbering
  2501. .Descendants()
  2502. .Elements(W.abstractNum)
  2503. .Where(e => e.Annotation<FromPreviousSourceSemaphore>() == null)
  2504. .Where(p =>
  2505. {
  2506. var thisNsidElement = p.Element(W.nsid);
  2507. if (thisNsidElement == null)
  2508. return false;
  2509. return (string)thisNsidElement.Attribute(W.val) == abstractNSID;
  2510. })
  2511. .FirstOrDefault();
  2512. if (newAbstractElement == null)
  2513. {
  2514. newAbstractElement = new XElement(abstractElement);
  2515. newAbstractElement.Attribute(W.abstractNumId).Value = abstractNumber.ToString();
  2516. abstractNumber++;
  2517. if (newNumbering.Root.Elements(W.abstractNum).Any())
  2518. newNumbering.Root.Elements(W.abstractNum).Last().AddAfterSelf(newAbstractElement);
  2519. else
  2520. newNumbering.Root.Add(newAbstractElement);
  2521. foreach (XElement pictId in newAbstractElement.Descendants(W.lvlPicBulletId))
  2522. {
  2523. string bulletId = (string)pictId.Attribute(W.val);
  2524. XElement numPicBullet = oldNumbering
  2525. .Descendants(W.numPicBullet)
  2526. .FirstOrDefault(d => (string)d.Attribute(W.numPicBulletId) == bulletId);
  2527. int maxNumPicBulletId = new int[] { -1 }.Concat(
  2528. newNumbering.Descendants(W.numPicBullet)
  2529. .Attributes(W.numPicBulletId)
  2530. .Select(a => (int)a))
  2531. .Max() + 1;
  2532. XElement newNumPicBullet = new XElement(numPicBullet);
  2533. newNumPicBullet.Attribute(W.numPicBulletId).Value = maxNumPicBulletId.ToString();
  2534. pictId.Attribute(W.val).Value = maxNumPicBulletId.ToString();
  2535. newNumbering.Root.AddFirst(newNumPicBullet);
  2536. }
  2537. }
  2538. string newAbstractId = newAbstractElement.Attribute(W.abstractNumId).Value;
  2539. // Copy numbering element, if necessary (use matching element with no overrides)
  2540. XElement newElement;
  2541. if (numIdMap.ContainsKey(numId))
  2542. {
  2543. newElement = newNumbering
  2544. .Descendants()
  2545. .Elements(W.num)
  2546. .Where(e => e.Annotation<FromPreviousSourceSemaphore>() == null)
  2547. .Where(p => ((int)p.Attribute(W.numId)) == numIdMap[numId])
  2548. .First();
  2549. }
  2550. else
  2551. {
  2552. newElement = new XElement(element);
  2553. newElement
  2554. .Elements(W.abstractNumId)
  2555. .First()
  2556. .Attribute(W.val).Value = newAbstractId;
  2557. newElement.Attribute(W.numId).Value = number.ToString();
  2558. numIdMap.Add(numId, number);
  2559. number++;
  2560. newNumbering.Root.Add(newElement);
  2561. }
  2562. idElement.Attribute(W.val).Value = newElement.Attribute(W.numId).Value;
  2563. }
  2564. }
  2565. }
  2566. if (newNumbering != null)
  2567. {
  2568. foreach (var abstractNum in newNumbering.Descendants(W.abstractNum))
  2569. abstractNum.AddAnnotation(new FromPreviousSourceSemaphore());
  2570. foreach (var num in newNumbering.Descendants(W.num))
  2571. num.AddAnnotation(new FromPreviousSourceSemaphore());
  2572. }
  2573. if (newDocument.MainDocumentPart.NumberingDefinitionsPart != null &&
  2574. sourceDocument.MainDocumentPart.NumberingDefinitionsPart != null)
  2575. {
  2576. AddRelationships(sourceDocument.MainDocumentPart.NumberingDefinitionsPart,
  2577. newDocument.MainDocumentPart.NumberingDefinitionsPart,
  2578. new[] { newDocument.MainDocumentPart.NumberingDefinitionsPart.GetXDocument().Root });
  2579. CopyRelatedPartsForContentParts(sourceDocument.MainDocumentPart.NumberingDefinitionsPart,
  2580. newDocument.MainDocumentPart.NumberingDefinitionsPart,
  2581. new[] { newDocument.MainDocumentPart.NumberingDefinitionsPart.GetXDocument().Root }, images);
  2582. }
  2583. }
  2584. // Note: the following two methods were added with almost exact duplicate code to the method above, because I do not want to touch that code.
  2585. private static void CopyNumberingForGlossaryDocumentPartFromGD(NumberingDefinitionsPart sourceNumberingPart, WordprocessingDocument newDocument,
  2586. IEnumerable<XElement> newContent, List<ImageData> images)
  2587. {
  2588. Dictionary<int, int> numIdMap = new Dictionary<int, int>();
  2589. int number = 1;
  2590. int abstractNumber = 0;
  2591. XDocument oldNumbering = null;
  2592. XDocument newNumbering = null;
  2593. foreach (XElement numReference in newContent.DescendantsAndSelf(W.numPr))
  2594. {
  2595. XElement idElement = numReference.Descendants(W.numId).FirstOrDefault();
  2596. if (idElement != null)
  2597. {
  2598. if (oldNumbering == null)
  2599. oldNumbering = sourceNumberingPart.GetXDocument();
  2600. if (newNumbering == null)
  2601. {
  2602. if (newDocument.MainDocumentPart.NumberingDefinitionsPart != null)
  2603. {
  2604. newNumbering = newDocument.MainDocumentPart.NumberingDefinitionsPart.GetXDocument();
  2605. var numIds = newNumbering
  2606. .Root
  2607. .Elements(W.num)
  2608. .Select(f => (int)f.Attribute(W.numId));
  2609. if (numIds.Any())
  2610. number = numIds.Max() + 1;
  2611. numIds = newNumbering
  2612. .Root
  2613. .Elements(W.abstractNum)
  2614. .Select(f => (int)f.Attribute(W.abstractNumId));
  2615. if (numIds.Any())
  2616. abstractNumber = numIds.Max() + 1;
  2617. }
  2618. else
  2619. {
  2620. newDocument.MainDocumentPart.AddNewPart<NumberingDefinitionsPart>();
  2621. newNumbering = newDocument.MainDocumentPart.NumberingDefinitionsPart.GetXDocument();
  2622. newNumbering.Declaration.Standalone = Yes;
  2623. newNumbering.Declaration.Encoding = Utf8;
  2624. newNumbering.Add(new XElement(W.numbering, NamespaceAttributes));
  2625. }
  2626. }
  2627. int numId = (int)idElement.Attribute(W.val);
  2628. if (numId != 0)
  2629. {
  2630. XElement element = oldNumbering
  2631. .Descendants(W.num)
  2632. .Where(p => ((int)p.Attribute(W.numId)) == numId)
  2633. .FirstOrDefault();
  2634. if (element == null)
  2635. continue;
  2636. // Copy abstract numbering element, if necessary (use matching NSID)
  2637. string abstractNumIdStr = (string)element
  2638. .Elements(W.abstractNumId)
  2639. .First()
  2640. .Attribute(W.val);
  2641. int abstractNumId;
  2642. if (!int.TryParse(abstractNumIdStr, out abstractNumId))
  2643. throw new DocumentBuilderException("Invalid document - invalid value for abstractNumId");
  2644. XElement abstractElement = oldNumbering
  2645. .Descendants()
  2646. .Elements(W.abstractNum)
  2647. .Where(p => ((int)p.Attribute(W.abstractNumId)) == abstractNumId)
  2648. .First();
  2649. XElement nsidElement = abstractElement
  2650. .Element(W.nsid);
  2651. string abstractNSID = null;
  2652. if (nsidElement != null)
  2653. abstractNSID = (string)nsidElement
  2654. .Attribute(W.val);
  2655. XElement newAbstractElement = newNumbering
  2656. .Descendants()
  2657. .Elements(W.abstractNum)
  2658. .Where(e => e.Annotation<FromPreviousSourceSemaphore>() == null)
  2659. .Where(p =>
  2660. {
  2661. var thisNsidElement = p.Element(W.nsid);
  2662. if (thisNsidElement == null)
  2663. return false;
  2664. return (string)thisNsidElement.Attribute(W.val) == abstractNSID;
  2665. })
  2666. .FirstOrDefault();
  2667. if (newAbstractElement == null)
  2668. {
  2669. newAbstractElement = new XElement(abstractElement);
  2670. newAbstractElement.Attribute(W.abstractNumId).Value = abstractNumber.ToString();
  2671. abstractNumber++;
  2672. if (newNumbering.Root.Elements(W.abstractNum).Any())
  2673. newNumbering.Root.Elements(W.abstractNum).Last().AddAfterSelf(newAbstractElement);
  2674. else
  2675. newNumbering.Root.Add(newAbstractElement);
  2676. foreach (XElement pictId in newAbstractElement.Descendants(W.lvlPicBulletId))
  2677. {
  2678. string bulletId = (string)pictId.Attribute(W.val);
  2679. XElement numPicBullet = oldNumbering
  2680. .Descendants(W.numPicBullet)
  2681. .FirstOrDefault(d => (string)d.Attribute(W.numPicBulletId) == bulletId);
  2682. int maxNumPicBulletId = new int[] { -1 }.Concat(
  2683. newNumbering.Descendants(W.numPicBullet)
  2684. .Attributes(W.numPicBulletId)
  2685. .Select(a => (int)a))
  2686. .Max() + 1;
  2687. XElement newNumPicBullet = new XElement(numPicBullet);
  2688. newNumPicBullet.Attribute(W.numPicBulletId).Value = maxNumPicBulletId.ToString();
  2689. pictId.Attribute(W.val).Value = maxNumPicBulletId.ToString();
  2690. newNumbering.Root.AddFirst(newNumPicBullet);
  2691. }
  2692. }
  2693. string newAbstractId = newAbstractElement.Attribute(W.abstractNumId).Value;
  2694. // Copy numbering element, if necessary (use matching element with no overrides)
  2695. XElement newElement;
  2696. if (numIdMap.ContainsKey(numId))
  2697. {
  2698. newElement = newNumbering
  2699. .Descendants()
  2700. .Elements(W.num)
  2701. .Where(e => e.Annotation<FromPreviousSourceSemaphore>() == null)
  2702. .Where(p => ((int)p.Attribute(W.numId)) == numIdMap[numId])
  2703. .First();
  2704. }
  2705. else
  2706. {
  2707. newElement = new XElement(element);
  2708. newElement
  2709. .Elements(W.abstractNumId)
  2710. .First()
  2711. .Attribute(W.val).Value = newAbstractId;
  2712. newElement.Attribute(W.numId).Value = number.ToString();
  2713. numIdMap.Add(numId, number);
  2714. number++;
  2715. newNumbering.Root.Add(newElement);
  2716. }
  2717. idElement.Attribute(W.val).Value = newElement.Attribute(W.numId).Value;
  2718. }
  2719. }
  2720. }
  2721. if (newNumbering != null)
  2722. {
  2723. foreach (var abstractNum in newNumbering.Descendants(W.abstractNum))
  2724. abstractNum.AddAnnotation(new FromPreviousSourceSemaphore());
  2725. foreach (var num in newNumbering.Descendants(W.num))
  2726. num.AddAnnotation(new FromPreviousSourceSemaphore());
  2727. }
  2728. if (newDocument.MainDocumentPart.NumberingDefinitionsPart != null &&
  2729. sourceNumberingPart != null)
  2730. {
  2731. AddRelationships(sourceNumberingPart,
  2732. newDocument.MainDocumentPart.NumberingDefinitionsPart,
  2733. new[] { newDocument.MainDocumentPart.NumberingDefinitionsPart.GetXDocument().Root });
  2734. CopyRelatedPartsForContentParts(sourceNumberingPart,
  2735. newDocument.MainDocumentPart.NumberingDefinitionsPart,
  2736. new[] { newDocument.MainDocumentPart.NumberingDefinitionsPart.GetXDocument().Root }, images);
  2737. }
  2738. if (newDocument.MainDocumentPart.NumberingDefinitionsPart != null)
  2739. newDocument.MainDocumentPart.NumberingDefinitionsPart.PutXDocument();
  2740. }
  2741. private static void CopyNumberingForGlossaryDocumentPartToGD(NumberingDefinitionsPart sourceNumberingPart, WordprocessingDocument newDocument,
  2742. IEnumerable<XElement> newContent, List<ImageData> images)
  2743. {
  2744. Dictionary<int, int> numIdMap = new Dictionary<int, int>();
  2745. int number = 1;
  2746. int abstractNumber = 0;
  2747. XDocument oldNumbering = null;
  2748. XDocument newNumbering = null;
  2749. foreach (XElement numReference in newContent.DescendantsAndSelf(W.numPr))
  2750. {
  2751. XElement idElement = numReference.Descendants(W.numId).FirstOrDefault();
  2752. if (idElement != null)
  2753. {
  2754. if (oldNumbering == null)
  2755. oldNumbering = sourceNumberingPart.GetXDocument();
  2756. if (newNumbering == null)
  2757. {
  2758. if (newDocument.MainDocumentPart.GlossaryDocumentPart.NumberingDefinitionsPart != null)
  2759. {
  2760. newNumbering = newDocument.MainDocumentPart.GlossaryDocumentPart.NumberingDefinitionsPart.GetXDocument();
  2761. var numIds = newNumbering
  2762. .Root
  2763. .Elements(W.num)
  2764. .Select(f => (int)f.Attribute(W.numId));
  2765. if (numIds.Any())
  2766. number = numIds.Max() + 1;
  2767. numIds = newNumbering
  2768. .Root
  2769. .Elements(W.abstractNum)
  2770. .Select(f => (int)f.Attribute(W.abstractNumId));
  2771. if (numIds.Any())
  2772. abstractNumber = numIds.Max() + 1;
  2773. }
  2774. else
  2775. {
  2776. newDocument.MainDocumentPart.GlossaryDocumentPart.AddNewPart<NumberingDefinitionsPart>();
  2777. newNumbering = newDocument.MainDocumentPart.GlossaryDocumentPart.NumberingDefinitionsPart.GetXDocument();
  2778. newNumbering.Declaration.Standalone = Yes;
  2779. newNumbering.Declaration.Encoding = Utf8;
  2780. newNumbering.Add(new XElement(W.numbering, NamespaceAttributes));
  2781. }
  2782. }
  2783. int numId = (int)idElement.Attribute(W.val);
  2784. if (numId != 0)
  2785. {
  2786. XElement element = oldNumbering
  2787. .Descendants(W.num)
  2788. .Where(p => ((int)p.Attribute(W.numId)) == numId)
  2789. .FirstOrDefault();
  2790. if (element == null)
  2791. continue;
  2792. // Copy abstract numbering element, if necessary (use matching NSID)
  2793. string abstractNumIdStr = (string)element
  2794. .Elements(W.abstractNumId)
  2795. .First()
  2796. .Attribute(W.val);
  2797. int abstractNumId;
  2798. if (!int.TryParse(abstractNumIdStr, out abstractNumId))
  2799. throw new DocumentBuilderException("Invalid document - invalid value for abstractNumId");
  2800. XElement abstractElement = oldNumbering
  2801. .Descendants()
  2802. .Elements(W.abstractNum)
  2803. .Where(p => ((int)p.Attribute(W.abstractNumId)) == abstractNumId)
  2804. .First();
  2805. XElement nsidElement = abstractElement
  2806. .Element(W.nsid);
  2807. string abstractNSID = null;
  2808. if (nsidElement != null)
  2809. abstractNSID = (string)nsidElement
  2810. .Attribute(W.val);
  2811. XElement newAbstractElement = newNumbering
  2812. .Descendants()
  2813. .Elements(W.abstractNum)
  2814. .Where(e => e.Annotation<FromPreviousSourceSemaphore>() == null)
  2815. .Where(p =>
  2816. {
  2817. var thisNsidElement = p.Element(W.nsid);
  2818. if (thisNsidElement == null)
  2819. return false;
  2820. return (string)thisNsidElement.Attribute(W.val) == abstractNSID;
  2821. })
  2822. .FirstOrDefault();
  2823. if (newAbstractElement == null)
  2824. {
  2825. newAbstractElement = new XElement(abstractElement);
  2826. newAbstractElement.Attribute(W.abstractNumId).Value = abstractNumber.ToString();
  2827. abstractNumber++;
  2828. if (newNumbering.Root.Elements(W.abstractNum).Any())
  2829. newNumbering.Root.Elements(W.abstractNum).Last().AddAfterSelf(newAbstractElement);
  2830. else
  2831. newNumbering.Root.Add(newAbstractElement);
  2832. foreach (XElement pictId in newAbstractElement.Descendants(W.lvlPicBulletId))
  2833. {
  2834. string bulletId = (string)pictId.Attribute(W.val);
  2835. XElement numPicBullet = oldNumbering
  2836. .Descendants(W.numPicBullet)
  2837. .FirstOrDefault(d => (string)d.Attribute(W.numPicBulletId) == bulletId);
  2838. int maxNumPicBulletId = new int[] { -1 }.Concat(
  2839. newNumbering.Descendants(W.numPicBullet)
  2840. .Attributes(W.numPicBulletId)
  2841. .Select(a => (int)a))
  2842. .Max() + 1;
  2843. XElement newNumPicBullet = new XElement(numPicBullet);
  2844. newNumPicBullet.Attribute(W.numPicBulletId).Value = maxNumPicBulletId.ToString();
  2845. pictId.Attribute(W.val).Value = maxNumPicBulletId.ToString();
  2846. newNumbering.Root.AddFirst(newNumPicBullet);
  2847. }
  2848. }
  2849. string newAbstractId = newAbstractElement.Attribute(W.abstractNumId).Value;
  2850. // Copy numbering element, if necessary (use matching element with no overrides)
  2851. XElement newElement;
  2852. if (numIdMap.ContainsKey(numId))
  2853. {
  2854. newElement = newNumbering
  2855. .Descendants()
  2856. .Elements(W.num)
  2857. .Where(e => e.Annotation<FromPreviousSourceSemaphore>() == null)
  2858. .Where(p => ((int)p.Attribute(W.numId)) == numIdMap[numId])
  2859. .First();
  2860. }
  2861. else
  2862. {
  2863. newElement = new XElement(element);
  2864. newElement
  2865. .Elements(W.abstractNumId)
  2866. .First()
  2867. .Attribute(W.val).Value = newAbstractId;
  2868. newElement.Attribute(W.numId).Value = number.ToString();
  2869. numIdMap.Add(numId, number);
  2870. number++;
  2871. newNumbering.Root.Add(newElement);
  2872. }
  2873. idElement.Attribute(W.val).Value = newElement.Attribute(W.numId).Value;
  2874. }
  2875. }
  2876. }
  2877. if (newNumbering != null)
  2878. {
  2879. foreach (var abstractNum in newNumbering.Descendants(W.abstractNum))
  2880. abstractNum.AddAnnotation(new FromPreviousSourceSemaphore());
  2881. foreach (var num in newNumbering.Descendants(W.num))
  2882. num.AddAnnotation(new FromPreviousSourceSemaphore());
  2883. }
  2884. if (newDocument.MainDocumentPart.GlossaryDocumentPart.NumberingDefinitionsPart != null &&
  2885. sourceNumberingPart != null)
  2886. {
  2887. AddRelationships(sourceNumberingPart,
  2888. newDocument.MainDocumentPart.GlossaryDocumentPart.NumberingDefinitionsPart,
  2889. new[] { newDocument.MainDocumentPart.GlossaryDocumentPart.NumberingDefinitionsPart.GetXDocument().Root });
  2890. CopyRelatedPartsForContentParts(sourceNumberingPart,
  2891. newDocument.MainDocumentPart.GlossaryDocumentPart.NumberingDefinitionsPart,
  2892. new[] { newDocument.MainDocumentPart.GlossaryDocumentPart.NumberingDefinitionsPart.GetXDocument().Root }, images);
  2893. }
  2894. if (newDocument.MainDocumentPart.GlossaryDocumentPart.NumberingDefinitionsPart != null)
  2895. newDocument.MainDocumentPart.GlossaryDocumentPart.NumberingDefinitionsPart.PutXDocument();
  2896. }
  2897. private static void CopyRelatedImage(OpenXmlPart oldContentPart, OpenXmlPart newContentPart, XElement imageReference, XName attributeName,
  2898. List<ImageData> images)
  2899. {
  2900. string relId = (string)imageReference.Attribute(attributeName);
  2901. if (string.IsNullOrEmpty(relId))
  2902. return;
  2903. // First look to see if this relId has already been added to the new document.
  2904. // This is necessary for those parts that get processed with both old and new ids, such as the comments
  2905. // part. This is not necessary for parts such as the main document part, but this code won't malfunction
  2906. // in that case.
  2907. var tempPartIdPair5 = newContentPart.Parts.FirstOrDefault(p => p.RelationshipId == relId);
  2908. if (tempPartIdPair5 != null)
  2909. return;
  2910. ExternalRelationship tempEr5 = newContentPart.ExternalRelationships.FirstOrDefault(er => er.Id == relId);
  2911. if (tempEr5 != null)
  2912. return;
  2913. var ipp2 = oldContentPart.Parts.FirstOrDefault(ipp => ipp.RelationshipId == relId);
  2914. if (ipp2 != null)
  2915. {
  2916. var oldPart2 = ipp2.OpenXmlPart;
  2917. if (!(oldPart2 is ImagePart))
  2918. throw new DocumentBuilderException("Invalid document - target part is not ImagePart");
  2919. ImagePart oldPart = (ImagePart)ipp2.OpenXmlPart;
  2920. ImageData temp = ManageImageCopy(oldPart, newContentPart, images);
  2921. if (temp.ImagePart == null)
  2922. {
  2923. ImagePart newPart = null;
  2924. if (newContentPart is MainDocumentPart)
  2925. newPart = ((MainDocumentPart)newContentPart).AddImagePart(oldPart.ContentType);
  2926. if (newContentPart is HeaderPart)
  2927. newPart = ((HeaderPart)newContentPart).AddImagePart(oldPart.ContentType);
  2928. if (newContentPart is FooterPart)
  2929. newPart = ((FooterPart)newContentPart).AddImagePart(oldPart.ContentType);
  2930. if (newContentPart is EndnotesPart)
  2931. newPart = ((EndnotesPart)newContentPart).AddImagePart(oldPart.ContentType);
  2932. if (newContentPart is FootnotesPart)
  2933. newPart = ((FootnotesPart)newContentPart).AddImagePart(oldPart.ContentType);
  2934. if (newContentPart is ThemePart)
  2935. newPart = ((ThemePart)newContentPart).AddImagePart(oldPart.ContentType);
  2936. if (newContentPart is WordprocessingCommentsPart)
  2937. newPart = ((WordprocessingCommentsPart)newContentPart).AddImagePart(oldPart.ContentType);
  2938. if (newContentPart is DocumentSettingsPart)
  2939. newPart = ((DocumentSettingsPart)newContentPart).AddImagePart(oldPart.ContentType);
  2940. if (newContentPart is ChartPart)
  2941. newPart = ((ChartPart)newContentPart).AddImagePart(oldPart.ContentType);
  2942. if (newContentPart is NumberingDefinitionsPart)
  2943. newPart = ((NumberingDefinitionsPart)newContentPart).AddImagePart(oldPart.ContentType);
  2944. if (newContentPart is DiagramDataPart)
  2945. newPart = ((DiagramDataPart)newContentPart).AddImagePart(oldPart.ContentType);
  2946. if (newContentPart is ChartDrawingPart)
  2947. newPart = ((ChartDrawingPart)newContentPart).AddImagePart(oldPart.ContentType);
  2948. temp.ImagePart = newPart;
  2949. var id = newContentPart.GetIdOfPart(newPart);
  2950. temp.AddContentPartRelTypeResourceIdTupple(newContentPart, newPart.RelationshipType, id);
  2951. imageReference.Attribute(attributeName).Value = id;
  2952. temp.WriteImage(newPart);
  2953. }
  2954. else
  2955. {
  2956. var refRel = newContentPart.Parts.FirstOrDefault(pip =>
  2957. {
  2958. var rel = temp.ContentPartRelTypeIdList.FirstOrDefault(cpr =>
  2959. {
  2960. var found = cpr.ContentPart == newContentPart;
  2961. return found;
  2962. });
  2963. return rel != null;
  2964. });
  2965. if (refRel != null)
  2966. {
  2967. imageReference.Attribute(attributeName).Value = temp.ContentPartRelTypeIdList.First(cpr =>
  2968. {
  2969. var found = cpr.ContentPart == newContentPart;
  2970. return found;
  2971. }).RelationshipId;
  2972. return;
  2973. }
  2974. var g = new Guid();
  2975. var newId = $"R{g:N}".Substring(0, 16);
  2976. newContentPart.CreateRelationshipToPart(temp.ImagePart, newId);
  2977. imageReference.Attribute(R.id).Value = newId;
  2978. }
  2979. }
  2980. else
  2981. {
  2982. ExternalRelationship er = oldContentPart.ExternalRelationships.FirstOrDefault(er1 => er1.Id == relId);
  2983. if (er != null)
  2984. {
  2985. ExternalRelationship newEr = newContentPart.AddExternalRelationship(er.RelationshipType, er.Uri);
  2986. imageReference.Attribute(R.id).Value = newEr.Id;
  2987. }
  2988. throw new DocumentBuilderInternalException("Source {0} is unsupported document - contains reference to NULL image");
  2989. }
  2990. }
  2991. private static void CopyRelatedPartsForContentParts(OpenXmlPart oldContentPart, OpenXmlPart newContentPart,
  2992. IEnumerable<XElement> newContent, List<ImageData> images)
  2993. {
  2994. var relevantElements = newContent.DescendantsAndSelf()
  2995. .Where(d => d.Name == VML.imagedata || d.Name == VML.fill || d.Name == VML.stroke || d.Name == A.blip)
  2996. .ToList();
  2997. foreach (XElement imageReference in relevantElements)
  2998. {
  2999. CopyRelatedImage(oldContentPart, newContentPart, imageReference, R.embed, images);
  3000. CopyRelatedImage(oldContentPart, newContentPart, imageReference, R.pict, images);
  3001. CopyRelatedImage(oldContentPart, newContentPart, imageReference, R.id, images);
  3002. }
  3003. foreach (XElement diagramReference in newContent.DescendantsAndSelf().Where(d => d.Name == DGM.relIds || d.Name == A.relIds))
  3004. {
  3005. // dm attribute
  3006. string relId = diagramReference.Attribute(R.dm).Value;
  3007. var ipp = newContentPart.Parts.FirstOrDefault(p => p.RelationshipId == relId);
  3008. if (ipp != null)
  3009. {
  3010. OpenXmlPart tempPart = ipp.OpenXmlPart;
  3011. continue;
  3012. }
  3013. ExternalRelationship tempEr = newContentPart.ExternalRelationships.FirstOrDefault(er2 => er2.Id == relId);
  3014. if (tempEr != null)
  3015. continue;
  3016. OpenXmlPart oldPart = oldContentPart.GetPartById(relId);
  3017. OpenXmlPart newPart = newContentPart.AddNewPart<DiagramDataPart>();
  3018. newPart.GetXDocument().Add(oldPart.GetXDocument().Root);
  3019. diagramReference.Attribute(R.dm).Value = newContentPart.GetIdOfPart(newPart);
  3020. AddRelationships(oldPart, newPart, new[] { newPart.GetXDocument().Root });
  3021. CopyRelatedPartsForContentParts(oldPart, newPart, new[] { newPart.GetXDocument().Root }, images);
  3022. // lo attribute
  3023. relId = diagramReference.Attribute(R.lo).Value;
  3024. var ipp2 = newContentPart.Parts.FirstOrDefault(z => z.RelationshipId == relId);
  3025. if (ipp2 != null)
  3026. {
  3027. OpenXmlPart tempPart = ipp2.OpenXmlPart;
  3028. continue;
  3029. }
  3030. ExternalRelationship tempEr4 = newContentPart.ExternalRelationships.FirstOrDefault(er3 => er3.Id == relId);
  3031. if (tempEr4 != null)
  3032. continue;
  3033. oldPart = oldContentPart.GetPartById(relId);
  3034. newPart = newContentPart.AddNewPart<DiagramLayoutDefinitionPart>();
  3035. newPart.GetXDocument().Add(oldPart.GetXDocument().Root);
  3036. diagramReference.Attribute(R.lo).Value = newContentPart.GetIdOfPart(newPart);
  3037. AddRelationships(oldPart, newPart, new[] { newPart.GetXDocument().Root });
  3038. CopyRelatedPartsForContentParts(oldPart, newPart, new[] { newPart.GetXDocument().Root }, images);
  3039. // qs attribute
  3040. relId = diagramReference.Attribute(R.qs).Value;
  3041. var ipp5 = newContentPart.Parts.FirstOrDefault(z => z.RelationshipId == relId);
  3042. if (ipp5 != null)
  3043. {
  3044. OpenXmlPart tempPart = ipp5.OpenXmlPart;
  3045. continue;
  3046. }
  3047. ExternalRelationship tempEr5 = newContentPart.ExternalRelationships.FirstOrDefault(z => z.Id == relId);
  3048. if (tempEr5 != null)
  3049. continue;
  3050. oldPart = oldContentPart.GetPartById(relId);
  3051. newPart = newContentPart.AddNewPart<DiagramStylePart>();
  3052. newPart.GetXDocument().Add(oldPart.GetXDocument().Root);
  3053. diagramReference.Attribute(R.qs).Value = newContentPart.GetIdOfPart(newPart);
  3054. AddRelationships(oldPart, newPart, new[] { newPart.GetXDocument().Root });
  3055. CopyRelatedPartsForContentParts(oldPart, newPart, new[] { newPart.GetXDocument().Root }, images);
  3056. // cs attribute
  3057. relId = diagramReference.Attribute(R.cs).Value;
  3058. var ipp6 = newContentPart.Parts.FirstOrDefault(z => z.RelationshipId == relId);
  3059. if (ipp6 != null)
  3060. {
  3061. OpenXmlPart tempPart = ipp6.OpenXmlPart;
  3062. continue;
  3063. }
  3064. ExternalRelationship tempEr6 = newContentPart.ExternalRelationships.FirstOrDefault(z => z.Id == relId);
  3065. if (tempEr6 != null)
  3066. continue;
  3067. oldPart = oldContentPart.GetPartById(relId);
  3068. newPart = newContentPart.AddNewPart<DiagramColorsPart>();
  3069. newPart.GetXDocument().Add(oldPart.GetXDocument().Root);
  3070. diagramReference.Attribute(R.cs).Value = newContentPart.GetIdOfPart(newPart);
  3071. AddRelationships(oldPart, newPart, new[] { newPart.GetXDocument().Root });
  3072. CopyRelatedPartsForContentParts(oldPart, newPart, new[] { newPart.GetXDocument().Root }, images);
  3073. }
  3074. foreach (XElement oleReference in newContent.DescendantsAndSelf(O.OLEObject))
  3075. {
  3076. string relId = (string)oleReference.Attribute(R.id);
  3077. // First look to see if this relId has already been added to the new document.
  3078. // This is necessary for those parts that get processed with both old and new ids, such as the comments
  3079. // part. This is not necessary for parts such as the main document part, but this code won't malfunction
  3080. // in that case.
  3081. var ipp1 = newContentPart.Parts.FirstOrDefault(p => p.RelationshipId == relId);
  3082. if (ipp1 != null)
  3083. {
  3084. OpenXmlPart tempPart = ipp1.OpenXmlPart;
  3085. continue;
  3086. }
  3087. ExternalRelationship tempEr1 = newContentPart.ExternalRelationships.FirstOrDefault(z => z.Id == relId);
  3088. if (tempEr1 != null)
  3089. continue;
  3090. var ipp4 = oldContentPart.Parts.FirstOrDefault(z => z.RelationshipId == relId);
  3091. if (ipp4 != null)
  3092. {
  3093. OpenXmlPart oldPart = oldContentPart.GetPartById(relId);
  3094. OpenXmlPart newPart = null;
  3095. if (oldPart is EmbeddedObjectPart)
  3096. {
  3097. if (newContentPart is HeaderPart)
  3098. newPart = ((HeaderPart)newContentPart).AddEmbeddedObjectPart(oldPart.ContentType);
  3099. if (newContentPart is FooterPart)
  3100. newPart = ((FooterPart)newContentPart).AddEmbeddedObjectPart(oldPart.ContentType);
  3101. if (newContentPart is MainDocumentPart)
  3102. newPart = ((MainDocumentPart)newContentPart).AddEmbeddedObjectPart(oldPart.ContentType);
  3103. if (newContentPart is FootnotesPart)
  3104. newPart = ((FootnotesPart)newContentPart).AddEmbeddedObjectPart(oldPart.ContentType);
  3105. if (newContentPart is EndnotesPart)
  3106. newPart = ((EndnotesPart)newContentPart).AddEmbeddedObjectPart(oldPart.ContentType);
  3107. if (newContentPart is WordprocessingCommentsPart)
  3108. newPart = ((WordprocessingCommentsPart)newContentPart).AddEmbeddedObjectPart(oldPart.ContentType);
  3109. }
  3110. else if (oldPart is EmbeddedPackagePart)
  3111. {
  3112. if (newContentPart is HeaderPart)
  3113. newPart = ((HeaderPart)newContentPart).AddEmbeddedPackagePart(oldPart.ContentType);
  3114. if (newContentPart is FooterPart)
  3115. newPart = ((FooterPart)newContentPart).AddEmbeddedPackagePart(oldPart.ContentType);
  3116. if (newContentPart is MainDocumentPart)
  3117. newPart = ((MainDocumentPart)newContentPart).AddEmbeddedPackagePart(oldPart.ContentType);
  3118. if (newContentPart is FootnotesPart)
  3119. newPart = ((FootnotesPart)newContentPart).AddEmbeddedPackagePart(oldPart.ContentType);
  3120. if (newContentPart is EndnotesPart)
  3121. newPart = ((EndnotesPart)newContentPart).AddEmbeddedPackagePart(oldPart.ContentType);
  3122. if (newContentPart is WordprocessingCommentsPart)
  3123. newPart = ((WordprocessingCommentsPart)newContentPart).AddEmbeddedPackagePart(oldPart.ContentType);
  3124. if (newContentPart is ChartPart)
  3125. newPart = ((ChartPart)newContentPart).AddEmbeddedPackagePart(oldPart.ContentType);
  3126. }
  3127. using (Stream oldObject = oldPart.GetStream(FileMode.Open, FileAccess.Read))
  3128. using (Stream newObject = newPart.GetStream(FileMode.Create, FileAccess.ReadWrite))
  3129. {
  3130. int byteCount;
  3131. byte[] buffer = new byte[65536];
  3132. while ((byteCount = oldObject.Read(buffer, 0, 65536)) != 0)
  3133. newObject.Write(buffer, 0, byteCount);
  3134. }
  3135. oleReference.Attribute(R.id).Value = newContentPart.GetIdOfPart(newPart);
  3136. }
  3137. else
  3138. {
  3139. if (relId != null)
  3140. {
  3141. ExternalRelationship er = oldContentPart.GetExternalRelationship(relId);
  3142. ExternalRelationship newEr = newContentPart.AddExternalRelationship(er.RelationshipType, er.Uri);
  3143. oleReference.Attribute(R.id).Value = newEr.Id;
  3144. }
  3145. }
  3146. }
  3147. foreach (XElement chartReference in newContent.DescendantsAndSelf(C.chart))
  3148. {
  3149. string relId = (string)chartReference.Attribute(R.id);
  3150. if (string.IsNullOrEmpty(relId))
  3151. continue;
  3152. var ipp2 = newContentPart.Parts.FirstOrDefault(z => z.RelationshipId == relId);
  3153. if (ipp2 != null)
  3154. {
  3155. OpenXmlPart tempPart = ipp2.OpenXmlPart;
  3156. continue;
  3157. }
  3158. ExternalRelationship tempEr2 = newContentPart.ExternalRelationships.FirstOrDefault(z => z.Id == relId);
  3159. if (tempEr2 != null)
  3160. continue;
  3161. var ipp3 = oldContentPart.Parts.FirstOrDefault(p => p.RelationshipId == relId);
  3162. if (ipp3 == null)
  3163. continue;
  3164. ChartPart oldPart = (ChartPart)ipp3.OpenXmlPart;
  3165. XDocument oldChart = oldPart.GetXDocument();
  3166. ChartPart newPart = newContentPart.AddNewPart<ChartPart>();
  3167. XDocument newChart = newPart.GetXDocument();
  3168. newChart.Add(oldChart.Root);
  3169. chartReference.Attribute(R.id).Value = newContentPart.GetIdOfPart(newPart);
  3170. CopyChartObjects(oldPart, newPart);
  3171. CopyRelatedPartsForContentParts(oldPart, newPart, new[] { newChart.Root }, images);
  3172. }
  3173. foreach (XElement userShape in newContent.DescendantsAndSelf(C.userShapes))
  3174. {
  3175. string relId = (string)userShape.Attribute(R.id);
  3176. if (string.IsNullOrEmpty(relId))
  3177. continue;
  3178. var ipp4 = newContentPart.Parts.FirstOrDefault(p => p.RelationshipId == relId);
  3179. if (ipp4 != null)
  3180. {
  3181. OpenXmlPart tempPart = ipp4.OpenXmlPart;
  3182. continue;
  3183. }
  3184. ExternalRelationship tempEr4 = newContentPart.ExternalRelationships.FirstOrDefault(z => z.Id == relId);
  3185. if (tempEr4 != null)
  3186. continue;
  3187. var ipp5 = oldContentPart.Parts.FirstOrDefault(p => p.RelationshipId == relId);
  3188. if (ipp5 != null)
  3189. {
  3190. ChartDrawingPart oldPart = (ChartDrawingPart)ipp5.OpenXmlPart;
  3191. XDocument oldXDoc = oldPart.GetXDocument();
  3192. ChartDrawingPart newPart = newContentPart.AddNewPart<ChartDrawingPart>();
  3193. XDocument newXDoc = newPart.GetXDocument();
  3194. newXDoc.Add(oldXDoc.Root);
  3195. userShape.Attribute(R.id).Value = newContentPart.GetIdOfPart(newPart);
  3196. AddRelationships(oldPart, newPart, newContent);
  3197. CopyRelatedPartsForContentParts(oldPart, newPart, new[] { newXDoc.Root }, images);
  3198. }
  3199. }
  3200. }
  3201. private static void CopyFontTable(FontTablePart oldFontTablePart, FontTablePart newFontTablePart)
  3202. {
  3203. var relevantElements = oldFontTablePart.GetXDocument().Descendants().Where(d => d.Name == W.embedRegular ||
  3204. d.Name == W.embedBold || d.Name == W.embedItalic || d.Name == W.embedBoldItalic).ToList();
  3205. foreach (XElement fontReference in relevantElements)
  3206. {
  3207. string relId = (string)fontReference.Attribute(R.id);
  3208. if (string.IsNullOrEmpty(relId))
  3209. continue;
  3210. var ipp1 = newFontTablePart.Parts.FirstOrDefault(z => z.RelationshipId == relId);
  3211. if (ipp1 != null)
  3212. {
  3213. OpenXmlPart tempPart = ipp1.OpenXmlPart;
  3214. continue;
  3215. }
  3216. ExternalRelationship tempEr1 = newFontTablePart.ExternalRelationships.FirstOrDefault(z => z.Id == relId);
  3217. if (tempEr1 != null)
  3218. continue;
  3219. var oldPart2 = oldFontTablePart.GetPartById(relId);
  3220. if (oldPart2 == null || (!(oldPart2 is FontPart)))
  3221. throw new DocumentBuilderException("Invalid document - FontTablePart contains invalid relationship");
  3222. FontPart oldPart = (FontPart)oldPart2;
  3223. FontPart newPart = newFontTablePart.AddFontPart(oldPart.ContentType);
  3224. var ResourceID = newFontTablePart.GetIdOfPart(newPart);
  3225. using (Stream oldFont = oldPart.GetStream(FileMode.Open, FileAccess.Read))
  3226. using (Stream newFont = newPart.GetStream(FileMode.Create, FileAccess.ReadWrite))
  3227. {
  3228. int byteCount;
  3229. byte[] buffer = new byte[65536];
  3230. while ((byteCount = oldFont.Read(buffer, 0, 65536)) != 0)
  3231. newFont.Write(buffer, 0, byteCount);
  3232. }
  3233. fontReference.Attribute(R.id).Value = ResourceID;
  3234. }
  3235. }
  3236. private static void CopyChartObjects(ChartPart oldChart, ChartPart newChart)
  3237. {
  3238. foreach (XElement dataReference in newChart.GetXDocument().Descendants(C.externalData))
  3239. {
  3240. string relId = dataReference.Attribute(R.id).Value;
  3241. var ipp1 = oldChart.Parts.FirstOrDefault(z => z.RelationshipId == relId);
  3242. if (ipp1 != null)
  3243. {
  3244. var oldRelatedPart = ipp1.OpenXmlPart;
  3245. if (oldRelatedPart is EmbeddedPackagePart)
  3246. {
  3247. EmbeddedPackagePart oldPart = (EmbeddedPackagePart)ipp1.OpenXmlPart;
  3248. EmbeddedPackagePart newPart = newChart.AddEmbeddedPackagePart(oldPart.ContentType);
  3249. using (Stream oldObject = oldPart.GetStream(FileMode.Open, FileAccess.Read))
  3250. using (Stream newObject = newPart.GetStream(FileMode.Create, FileAccess.ReadWrite))
  3251. {
  3252. int byteCount;
  3253. byte[] buffer = new byte[65536];
  3254. while ((byteCount = oldObject.Read(buffer, 0, 65536)) != 0)
  3255. newObject.Write(buffer, 0, byteCount);
  3256. }
  3257. dataReference.Attribute(R.id).Value = newChart.GetIdOfPart(newPart);
  3258. }
  3259. else if (oldRelatedPart is EmbeddedObjectPart)
  3260. {
  3261. EmbeddedObjectPart oldPart = (EmbeddedObjectPart)ipp1.OpenXmlPart;
  3262. var relType = oldRelatedPart.RelationshipType;
  3263. var conType = oldRelatedPart.ContentType;
  3264. var g = new Guid();
  3265. string id = $"R{g:N}".Substring(0, 8);
  3266. var newPart = newChart.AddExtendedPart(relType, conType, ".bin", id);
  3267. using (Stream oldObject = oldPart.GetStream(FileMode.Open, FileAccess.Read))
  3268. using (Stream newObject = newPart.GetStream(FileMode.Create, FileAccess.ReadWrite))
  3269. {
  3270. int byteCount;
  3271. byte[] buffer = new byte[65536];
  3272. while ((byteCount = oldObject.Read(buffer, 0, 65536)) != 0)
  3273. newObject.Write(buffer, 0, byteCount);
  3274. }
  3275. dataReference.Attribute(R.id).Value = newChart.GetIdOfPart(newPart);
  3276. }
  3277. }
  3278. else
  3279. {
  3280. ExternalRelationship oldRelationship = oldChart.GetExternalRelationship(relId);
  3281. Guid g = Guid.NewGuid();
  3282. string newRid = $"R{g:N}";
  3283. var oldRel = oldChart.ExternalRelationships.FirstOrDefault(h => h.Id == relId);
  3284. if (oldRel == null)
  3285. throw new DocumentBuilderInternalException("Internal Error 0007");
  3286. newChart.AddExternalRelationship(oldRel.RelationshipType, oldRel.Uri, newRid);
  3287. dataReference.Attribute(R.id).Value = newRid;
  3288. }
  3289. }
  3290. }
  3291. private static void CopyStartingParts(WordprocessingDocument sourceDocument, WordprocessingDocument newDocument,
  3292. List<ImageData> images)
  3293. {
  3294. // A Core File Properties part does not have implicit or explicit relationships to other parts.
  3295. CoreFilePropertiesPart corePart = sourceDocument.CoreFilePropertiesPart;
  3296. if (corePart != null && corePart.GetXDocument().Root != null)
  3297. {
  3298. newDocument.AddCoreFilePropertiesPart();
  3299. XDocument newXDoc = newDocument.CoreFilePropertiesPart.GetXDocument();
  3300. newXDoc.Declaration.Standalone = Yes;
  3301. newXDoc.Declaration.Encoding = Utf8;
  3302. XDocument sourceXDoc = corePart.GetXDocument();
  3303. newXDoc.Add(sourceXDoc.Root);
  3304. }
  3305. // An application attributes part does not have implicit or explicit relationships to other parts.
  3306. ExtendedFilePropertiesPart extPart = sourceDocument.ExtendedFilePropertiesPart;
  3307. if (extPart != null)
  3308. {
  3309. OpenXmlPart newPart = newDocument.AddExtendedFilePropertiesPart();
  3310. XDocument newXDoc = newDocument.ExtendedFilePropertiesPart.GetXDocument();
  3311. newXDoc.Declaration.Standalone = Yes;
  3312. newXDoc.Declaration.Encoding = Utf8;
  3313. newXDoc.Add(extPart.GetXDocument().Root);
  3314. }
  3315. // An custom file properties part does not have implicit or explicit relationships to other parts.
  3316. CustomFilePropertiesPart customPart = sourceDocument.CustomFilePropertiesPart;
  3317. if (customPart != null)
  3318. {
  3319. newDocument.AddCustomFilePropertiesPart();
  3320. XDocument newXDoc = newDocument.CustomFilePropertiesPart.GetXDocument();
  3321. newXDoc.Declaration.Standalone = Yes;
  3322. newXDoc.Declaration.Encoding = Utf8;
  3323. newXDoc.Add(customPart.GetXDocument().Root);
  3324. }
  3325. DocumentSettingsPart oldSettingsPart = sourceDocument.MainDocumentPart.DocumentSettingsPart;
  3326. if (oldSettingsPart != null)
  3327. {
  3328. DocumentSettingsPart newSettingsPart = newDocument.MainDocumentPart.AddNewPart<DocumentSettingsPart>();
  3329. XDocument settingsXDoc = oldSettingsPart.GetXDocument();
  3330. AddRelationships(oldSettingsPart, newSettingsPart, new[] { settingsXDoc.Root });
  3331. CopyFootnotesPart(sourceDocument, newDocument, settingsXDoc, images);
  3332. CopyEndnotesPart(sourceDocument, newDocument, settingsXDoc, images);
  3333. XDocument newXDoc = newDocument.MainDocumentPart.DocumentSettingsPart.GetXDocument();
  3334. newXDoc.Declaration.Standalone = Yes;
  3335. newXDoc.Declaration.Encoding = Utf8;
  3336. newXDoc.Add(settingsXDoc.Root);
  3337. CopyRelatedPartsForContentParts(oldSettingsPart, newSettingsPart, new[] { newXDoc.Root }, images);
  3338. }
  3339. WebSettingsPart oldWebSettingsPart = sourceDocument.MainDocumentPart.WebSettingsPart;
  3340. if (oldWebSettingsPart != null)
  3341. {
  3342. WebSettingsPart newWebSettingsPart = newDocument.MainDocumentPart.AddNewPart<WebSettingsPart>();
  3343. XDocument settingsXDoc = oldWebSettingsPart.GetXDocument();
  3344. AddRelationships(oldWebSettingsPart, newWebSettingsPart, new[] { settingsXDoc.Root });
  3345. XDocument newXDoc = newDocument.MainDocumentPart.WebSettingsPart.GetXDocument();
  3346. newXDoc.Declaration.Standalone = Yes;
  3347. newXDoc.Declaration.Encoding = Utf8;
  3348. newXDoc.Add(settingsXDoc.Root);
  3349. }
  3350. ThemePart themePart = sourceDocument.MainDocumentPart.ThemePart;
  3351. if (themePart != null)
  3352. {
  3353. ThemePart newThemePart = newDocument.MainDocumentPart.AddNewPart<ThemePart>();
  3354. XDocument newXDoc = newDocument.MainDocumentPart.ThemePart.GetXDocument();
  3355. newXDoc.Declaration.Standalone = Yes;
  3356. newXDoc.Declaration.Encoding = Utf8;
  3357. newXDoc.Add(themePart.GetXDocument().Root);
  3358. CopyRelatedPartsForContentParts(themePart, newThemePart, new[] { newThemePart.GetXDocument().Root }, images);
  3359. }
  3360. // If needed to handle GlossaryDocumentPart in the future, then
  3361. // this code should handle the following parts:
  3362. // MainDocumentPart.GlossaryDocumentPart.StyleDefinitionsPart
  3363. // MainDocumentPart.GlossaryDocumentPart.StylesWithEffectsPart
  3364. // A Style Definitions part shall not have implicit or explicit relationships to any other part.
  3365. StyleDefinitionsPart stylesPart = sourceDocument.MainDocumentPart.StyleDefinitionsPart;
  3366. if (stylesPart != null)
  3367. {
  3368. newDocument.MainDocumentPart.AddNewPart<StyleDefinitionsPart>();
  3369. XDocument newXDoc = newDocument.MainDocumentPart.StyleDefinitionsPart.GetXDocument();
  3370. newXDoc.Declaration.Standalone = Yes;
  3371. newXDoc.Declaration.Encoding = Utf8;
  3372. newXDoc.Add(new XElement(W.styles,
  3373. new XAttribute(XNamespace.Xmlns + "w", W.w),
  3374. stylesPart.GetXDocument().Descendants(W.docDefaults)
  3375. //,
  3376. //stylesPart.GetXDocument().Descendants(W.docDefaults)
  3377. //,
  3378. //new XElement(W.latentStyles, stylesPart.GetXDocument().Descendants(W.latentStyles).Attributes())
  3379. ));
  3380. MergeDocDefaultStyles(stylesPart.GetXDocument(), newXDoc);
  3381. MergeStyles(sourceDocument, newDocument, stylesPart.GetXDocument(), newXDoc, Enumerable.Empty<XElement>());
  3382. MergeLatentStyles(stylesPart.GetXDocument(), newXDoc);
  3383. }
  3384. // A Font Table part shall not have any implicit or explicit relationships to any other part.
  3385. FontTablePart fontTablePart = sourceDocument.MainDocumentPart.FontTablePart;
  3386. if (fontTablePart != null)
  3387. {
  3388. newDocument.MainDocumentPart.AddNewPart<FontTablePart>();
  3389. XDocument newXDoc = newDocument.MainDocumentPart.FontTablePart.GetXDocument();
  3390. newXDoc.Declaration.Standalone = Yes;
  3391. newXDoc.Declaration.Encoding = Utf8;
  3392. CopyFontTable(sourceDocument.MainDocumentPart.FontTablePart, newDocument.MainDocumentPart.FontTablePart);
  3393. newXDoc.Add(fontTablePart.GetXDocument().Root);
  3394. }
  3395. }
  3396. private static void CopyFootnotesPart(WordprocessingDocument sourceDocument, WordprocessingDocument newDocument,
  3397. XDocument settingsXDoc, List<ImageData> images)
  3398. {
  3399. int number = 0;
  3400. XDocument oldFootnotes = null;
  3401. XDocument newFootnotes = null;
  3402. XElement footnotePr = settingsXDoc.Root.Element(W.footnotePr);
  3403. if (footnotePr == null)
  3404. return;
  3405. if (sourceDocument.MainDocumentPart.FootnotesPart == null)
  3406. return;
  3407. foreach (XElement footnote in footnotePr.Elements(W.footnote))
  3408. {
  3409. if (oldFootnotes == null)
  3410. oldFootnotes = sourceDocument.MainDocumentPart.FootnotesPart.GetXDocument();
  3411. if (newFootnotes == null)
  3412. {
  3413. if (newDocument.MainDocumentPart.FootnotesPart != null)
  3414. {
  3415. newFootnotes = newDocument.MainDocumentPart.FootnotesPart.GetXDocument();
  3416. newFootnotes.Declaration.Standalone = Yes;
  3417. newFootnotes.Declaration.Encoding = Utf8;
  3418. var ids = newFootnotes.Root.Elements(W.footnote).Select(f => (int)f.Attribute(W.id));
  3419. if (ids.Any())
  3420. number = ids.Max() + 1;
  3421. }
  3422. else
  3423. {
  3424. newDocument.MainDocumentPart.AddNewPart<FootnotesPart>();
  3425. newFootnotes = newDocument.MainDocumentPart.FootnotesPart.GetXDocument();
  3426. newFootnotes.Declaration.Standalone = Yes;
  3427. newFootnotes.Declaration.Encoding = Utf8;
  3428. newFootnotes.Add(new XElement(W.footnotes, NamespaceAttributes));
  3429. }
  3430. }
  3431. string id = (string)footnote.Attribute(W.id);
  3432. XElement element = oldFootnotes.Descendants()
  3433. .Elements(W.footnote)
  3434. .Where(p => ((string)p.Attribute(W.id)) == id)
  3435. .FirstOrDefault();
  3436. if (element != null)
  3437. {
  3438. XElement newElement = new XElement(element);
  3439. // the following adds the footnote into the new settings part
  3440. newElement.Attribute(W.id).Value = number.ToString();
  3441. newFootnotes.Root.Add(newElement);
  3442. footnote.Attribute(W.id).Value = number.ToString();
  3443. number++;
  3444. }
  3445. }
  3446. }
  3447. private static void CopyEndnotesPart(WordprocessingDocument sourceDocument, WordprocessingDocument newDocument,
  3448. XDocument settingsXDoc, List<ImageData> images)
  3449. {
  3450. int number = 0;
  3451. XDocument oldEndnotes = null;
  3452. XDocument newEndnotes = null;
  3453. XElement endnotePr = settingsXDoc.Root.Element(W.endnotePr);
  3454. if (endnotePr == null)
  3455. return;
  3456. if (sourceDocument.MainDocumentPart.EndnotesPart == null)
  3457. return;
  3458. foreach (XElement endnote in endnotePr.Elements(W.endnote))
  3459. {
  3460. if (oldEndnotes == null)
  3461. oldEndnotes = sourceDocument.MainDocumentPart.EndnotesPart.GetXDocument();
  3462. if (newEndnotes == null)
  3463. {
  3464. if (newDocument.MainDocumentPart.EndnotesPart != null)
  3465. {
  3466. newEndnotes = newDocument.MainDocumentPart.EndnotesPart.GetXDocument();
  3467. newEndnotes.Declaration.Standalone = Yes;
  3468. newEndnotes.Declaration.Encoding = Utf8;
  3469. var ids = newEndnotes.Root
  3470. .Elements(W.endnote)
  3471. .Select(f => (int)f.Attribute(W.id));
  3472. if (ids.Any())
  3473. number = ids.Max() + 1;
  3474. }
  3475. else
  3476. {
  3477. newDocument.MainDocumentPart.AddNewPart<EndnotesPart>();
  3478. newEndnotes = newDocument.MainDocumentPart.EndnotesPart.GetXDocument();
  3479. newEndnotes.Declaration.Standalone = Yes;
  3480. newEndnotes.Declaration.Encoding = Utf8;
  3481. newEndnotes.Add(new XElement(W.endnotes, NamespaceAttributes));
  3482. }
  3483. }
  3484. string id = (string)endnote.Attribute(W.id);
  3485. XElement element = oldEndnotes.Descendants()
  3486. .Elements(W.endnote)
  3487. .Where(p => ((string)p.Attribute(W.id)) == id)
  3488. .FirstOrDefault();
  3489. if (element != null)
  3490. {
  3491. XElement newElement = new XElement(element);
  3492. newElement.Attribute(W.id).Value = number.ToString();
  3493. newEndnotes.Root.Add(newElement);
  3494. endnote.Attribute(W.id).Value = number.ToString();
  3495. number++;
  3496. }
  3497. }
  3498. }
  3499. public static void FixRanges(XDocument sourceDocument, IEnumerable<XElement> newContent)
  3500. {
  3501. FixRange(sourceDocument,
  3502. newContent,
  3503. W.commentRangeStart,
  3504. W.commentRangeEnd,
  3505. W.id,
  3506. W.commentReference);
  3507. FixRange(sourceDocument,
  3508. newContent,
  3509. W.bookmarkStart,
  3510. W.bookmarkEnd,
  3511. W.id,
  3512. null);
  3513. FixRange(sourceDocument,
  3514. newContent,
  3515. W.permStart,
  3516. W.permEnd,
  3517. W.id,
  3518. null);
  3519. FixRange(sourceDocument,
  3520. newContent,
  3521. W.moveFromRangeStart,
  3522. W.moveFromRangeEnd,
  3523. W.id,
  3524. null);
  3525. FixRange(sourceDocument,
  3526. newContent,
  3527. W.moveToRangeStart,
  3528. W.moveToRangeEnd,
  3529. W.id,
  3530. null);
  3531. DeleteUnmatchedRange(sourceDocument,
  3532. newContent,
  3533. W.moveFromRangeStart,
  3534. W.moveFromRangeEnd,
  3535. W.moveToRangeStart,
  3536. W.name,
  3537. W.id);
  3538. DeleteUnmatchedRange(sourceDocument,
  3539. newContent,
  3540. W.moveToRangeStart,
  3541. W.moveToRangeEnd,
  3542. W.moveFromRangeStart,
  3543. W.name,
  3544. W.id);
  3545. }
  3546. private static void AddAtBeginning(IEnumerable<XElement> newContent, XElement contentToAdd)
  3547. {
  3548. if (newContent.First().Element(W.pPr) != null)
  3549. newContent.First().Element(W.pPr).AddAfterSelf(contentToAdd);
  3550. else
  3551. newContent.First().AddFirst(new XElement(contentToAdd));
  3552. }
  3553. private static void AddAtEnd(IEnumerable<XElement> newContent, XElement contentToAdd)
  3554. {
  3555. if (newContent.Last().Element(W.pPr) != null)
  3556. newContent.Last().Element(W.pPr).AddAfterSelf(new XElement(contentToAdd));
  3557. else
  3558. newContent.Last().Add(new XElement(contentToAdd));
  3559. }
  3560. // If the set of paragraphs from sourceDocument don't have a complete start/end for bookmarks,
  3561. // comments, etc., then this adds them to the paragraph. Note that this adds them to
  3562. // sourceDocument, and is impure.
  3563. private static void FixRange(XDocument sourceDocument, IEnumerable<XElement> newContent,
  3564. XName startElement, XName endElement, XName idAttribute, XName refElement)
  3565. {
  3566. foreach (XElement start in newContent.DescendantsAndSelf(startElement))
  3567. {
  3568. string rangeId = start.Attribute(idAttribute).Value;
  3569. if (newContent
  3570. .DescendantsAndSelf(endElement)
  3571. .Where(e => e.Attribute(idAttribute).Value == rangeId)
  3572. .Count() == 0)
  3573. {
  3574. XElement end = sourceDocument
  3575. .Descendants(endElement)
  3576. .Where(o => o.Attribute(idAttribute).Value == rangeId)
  3577. .FirstOrDefault();
  3578. if (end != null)
  3579. {
  3580. AddAtEnd(newContent, new XElement(end));
  3581. if (refElement != null)
  3582. {
  3583. XElement newRef = new XElement(refElement, new XAttribute(idAttribute, rangeId));
  3584. AddAtEnd(newContent, new XElement(newRef));
  3585. }
  3586. }
  3587. }
  3588. }
  3589. foreach (XElement end in newContent.Elements(endElement))
  3590. {
  3591. string rangeId = end.Attribute(idAttribute).Value;
  3592. if (newContent
  3593. .DescendantsAndSelf(startElement)
  3594. .Where(s => s.Attribute(idAttribute).Value == rangeId)
  3595. .Count() == 0)
  3596. {
  3597. XElement start = sourceDocument
  3598. .Descendants(startElement)
  3599. .Where(o => o.Attribute(idAttribute).Value == rangeId)
  3600. .FirstOrDefault();
  3601. if (start != null)
  3602. AddAtBeginning(newContent, new XElement(start));
  3603. }
  3604. }
  3605. }
  3606. private static void DeleteUnmatchedRange(XDocument sourceDocument, IEnumerable<XElement> newContent,
  3607. XName startElement, XName endElement, XName matchTo, XName matchAttr, XName idAttr)
  3608. {
  3609. List<string> deleteList = new List<string>();
  3610. foreach (XElement start in newContent.Elements(startElement))
  3611. {
  3612. string id = start.Attribute(matchAttr).Value;
  3613. if (!newContent.Elements(matchTo).Where(n => n.Attribute(matchAttr).Value == id).Any())
  3614. deleteList.Add(start.Attribute(idAttr).Value);
  3615. }
  3616. foreach (string item in deleteList)
  3617. {
  3618. newContent.Elements(startElement).Where(n => n.Attribute(idAttr).Value == item).Remove();
  3619. newContent.Elements(endElement).Where(n => n.Attribute(idAttr).Value == item).Remove();
  3620. newContent.Where(p => p.Name == startElement && p.Attribute(idAttr).Value == item).Remove();
  3621. newContent.Where(p => p.Name == endElement && p.Attribute(idAttr).Value == item).Remove();
  3622. }
  3623. }
  3624. private static void CopyFootnotes(WordprocessingDocument sourceDocument, WordprocessingDocument newDocument,
  3625. IEnumerable<XElement> newContent, List<ImageData> images)
  3626. {
  3627. int number = 0;
  3628. XDocument oldFootnotes = null;
  3629. XDocument newFootnotes = null;
  3630. foreach (XElement footnote in newContent.DescendantsAndSelf(W.footnoteReference))
  3631. {
  3632. if (oldFootnotes == null)
  3633. oldFootnotes = sourceDocument.MainDocumentPart.FootnotesPart.GetXDocument();
  3634. if (newFootnotes == null)
  3635. {
  3636. if (newDocument.MainDocumentPart.FootnotesPart != null)
  3637. {
  3638. newFootnotes = newDocument.MainDocumentPart.FootnotesPart.GetXDocument();
  3639. var ids = newFootnotes
  3640. .Root
  3641. .Elements(W.footnote)
  3642. .Select(f => (int)f.Attribute(W.id));
  3643. if (ids.Any())
  3644. number = ids.Max() + 1;
  3645. }
  3646. else
  3647. {
  3648. newDocument.MainDocumentPart.AddNewPart<FootnotesPart>();
  3649. newFootnotes = newDocument.MainDocumentPart.FootnotesPart.GetXDocument();
  3650. newFootnotes.Declaration.Standalone = Yes;
  3651. newFootnotes.Declaration.Encoding = Utf8;
  3652. newFootnotes.Add(new XElement(W.footnotes, NamespaceAttributes));
  3653. }
  3654. }
  3655. string id = (string)footnote.Attribute(W.id);
  3656. XElement element = oldFootnotes
  3657. .Descendants()
  3658. .Elements(W.footnote)
  3659. .Where(p => ((string)p.Attribute(W.id)) == id)
  3660. .FirstOrDefault();
  3661. if (element != null)
  3662. {
  3663. XElement newElement = new XElement(element);
  3664. newElement.Attribute(W.id).Value = number.ToString();
  3665. newFootnotes.Root.Add(newElement);
  3666. footnote.Attribute(W.id).Value = number.ToString();
  3667. number++;
  3668. }
  3669. }
  3670. if (sourceDocument.MainDocumentPart.FootnotesPart != null &&
  3671. newDocument.MainDocumentPart.FootnotesPart != null)
  3672. {
  3673. AddRelationships(sourceDocument.MainDocumentPart.FootnotesPart,
  3674. newDocument.MainDocumentPart.FootnotesPart,
  3675. new[] { newDocument.MainDocumentPart.FootnotesPart.GetXDocument().Root });
  3676. CopyRelatedPartsForContentParts(sourceDocument.MainDocumentPart.FootnotesPart,
  3677. newDocument.MainDocumentPart.FootnotesPart,
  3678. new[] { newDocument.MainDocumentPart.FootnotesPart.GetXDocument().Root }, images);
  3679. }
  3680. }
  3681. private static void CopyEndnotes(WordprocessingDocument sourceDocument, WordprocessingDocument newDocument,
  3682. IEnumerable<XElement> newContent, List<ImageData> images)
  3683. {
  3684. int number = 0;
  3685. XDocument oldEndnotes = null;
  3686. XDocument newEndnotes = null;
  3687. foreach (XElement endnote in newContent.DescendantsAndSelf(W.endnoteReference))
  3688. {
  3689. if (oldEndnotes == null)
  3690. oldEndnotes = sourceDocument.MainDocumentPart.EndnotesPart.GetXDocument();
  3691. if (newEndnotes == null)
  3692. {
  3693. if (newDocument.MainDocumentPart.EndnotesPart != null)
  3694. {
  3695. newEndnotes = newDocument
  3696. .MainDocumentPart
  3697. .EndnotesPart
  3698. .GetXDocument();
  3699. var ids = newEndnotes
  3700. .Root
  3701. .Elements(W.endnote)
  3702. .Select(f => (int)f.Attribute(W.id));
  3703. if (ids.Any())
  3704. number = ids.Max() + 1;
  3705. }
  3706. else
  3707. {
  3708. newDocument.MainDocumentPart.AddNewPart<EndnotesPart>();
  3709. newEndnotes = newDocument.MainDocumentPart.EndnotesPart.GetXDocument();
  3710. newEndnotes.Declaration.Standalone = Yes;
  3711. newEndnotes.Declaration.Encoding = Utf8;
  3712. newEndnotes.Add(new XElement(W.endnotes, NamespaceAttributes));
  3713. }
  3714. }
  3715. string id = (string)endnote.Attribute(W.id);
  3716. XElement element = oldEndnotes
  3717. .Descendants()
  3718. .Elements(W.endnote)
  3719. .Where(p => ((string)p.Attribute(W.id)) == id)
  3720. .First();
  3721. XElement newElement = new XElement(element);
  3722. newElement.Attribute(W.id).Value = number.ToString();
  3723. newEndnotes.Root.Add(newElement);
  3724. endnote.Attribute(W.id).Value = number.ToString();
  3725. number++;
  3726. }
  3727. if (sourceDocument.MainDocumentPart.EndnotesPart != null &&
  3728. newDocument.MainDocumentPart.EndnotesPart != null)
  3729. {
  3730. AddRelationships(sourceDocument.MainDocumentPart.EndnotesPart,
  3731. newDocument.MainDocumentPart.EndnotesPart,
  3732. new[] { newDocument.MainDocumentPart.EndnotesPart.GetXDocument().Root });
  3733. CopyRelatedPartsForContentParts(sourceDocument.MainDocumentPart.EndnotesPart,
  3734. newDocument.MainDocumentPart.EndnotesPart,
  3735. new[] { newDocument.MainDocumentPart.EndnotesPart.GetXDocument().Root }, images);
  3736. }
  3737. }
  3738. // General function for handling images that tries to use an existing image if they are the same
  3739. private static ImageData ManageImageCopy(ImagePart oldImage, OpenXmlPart newContentPart, List<ImageData> images)
  3740. {
  3741. ImageData oldImageData = new ImageData(oldImage);
  3742. foreach (ImageData item in images)
  3743. {
  3744. if (newContentPart != item.ImagePart)
  3745. continue;
  3746. if (item.Compare(oldImageData))
  3747. return item;
  3748. }
  3749. images.Add(oldImageData);
  3750. return oldImageData;
  3751. }
  3752. private static XAttribute[] NamespaceAttributes =
  3753. {
  3754. new XAttribute(XNamespace.Xmlns + "wpc", WPC.wpc),
  3755. new XAttribute(XNamespace.Xmlns + "mc", MC.mc),
  3756. new XAttribute(XNamespace.Xmlns + "o", O.o),
  3757. new XAttribute(XNamespace.Xmlns + "r", R.r),
  3758. new XAttribute(XNamespace.Xmlns + "m", M.m),
  3759. new XAttribute(XNamespace.Xmlns + "v", VML.vml),
  3760. new XAttribute(XNamespace.Xmlns + "wp14", WP14.wp14),
  3761. new XAttribute(XNamespace.Xmlns + "wp", WP.wp),
  3762. new XAttribute(XNamespace.Xmlns + "w10", W10.w10),
  3763. new XAttribute(XNamespace.Xmlns + "w", W.w),
  3764. new XAttribute(XNamespace.Xmlns + "w14", W14.w14),
  3765. new XAttribute(XNamespace.Xmlns + "wpg", WPG.wpg),
  3766. new XAttribute(XNamespace.Xmlns + "wpi", WPI.wpi),
  3767. new XAttribute(XNamespace.Xmlns + "wne", WNE.wne),
  3768. new XAttribute(XNamespace.Xmlns + "wps", WPS.wps),
  3769. new XAttribute(MC.Ignorable, "w14 wp14"),
  3770. };
  3771. }
  3772. public class DocumentBuilderException : Exception
  3773. {
  3774. public DocumentBuilderException(string message) : base(message) { }
  3775. }
  3776. public class DocumentBuilderInternalException : Exception
  3777. {
  3778. public DocumentBuilderInternalException(string message) : base(message) { }
  3779. }
  3780. }