diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..1ff0c42
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,63 @@
+###############################################################################
+# Set default behavior to automatically normalize line endings.
+###############################################################################
+* text=auto
+
+###############################################################################
+# Set default behavior for command prompt diff.
+#
+# This is need for earlier builds of msysgit that does not have it on by
+# default for csharp files.
+# Note: This is only used by command line
+###############################################################################
+#*.cs diff=csharp
+
+###############################################################################
+# Set the merge driver for project and solution files
+#
+# Merging from the command prompt will add diff markers to the files if there
+# are conflicts (Merging from VS is not affected by the settings below, in VS
+# the diff markers are never inserted). Diff markers may cause the following
+# file extensions to fail to load in VS. An alternative would be to treat
+# these files as binary and thus will always conflict and require user
+# intervention with every merge. To do so, just uncomment the entries below
+###############################################################################
+#*.sln merge=binary
+#*.csproj merge=binary
+#*.vbproj merge=binary
+#*.vcxproj merge=binary
+#*.vcproj merge=binary
+#*.dbproj merge=binary
+#*.fsproj merge=binary
+#*.lsproj merge=binary
+#*.wixproj merge=binary
+#*.modelproj merge=binary
+#*.sqlproj merge=binary
+#*.wwaproj merge=binary
+
+###############################################################################
+# behavior for image files
+#
+# image files are treated as binary by default.
+###############################################################################
+#*.jpg binary
+#*.png binary
+#*.gif binary
+
+###############################################################################
+# diff behavior for common document formats
+#
+# Convert binary document formats to text before diffing them. This feature
+# is only available from the command line. Turn it on by uncommenting the
+# entries below.
+###############################################################################
+#*.doc diff=astextplain
+#*.DOC diff=astextplain
+#*.docx diff=astextplain
+#*.DOCX diff=astextplain
+#*.dot diff=astextplain
+#*.DOT diff=astextplain
+#*.pdf diff=astextplain
+#*.PDF diff=astextplain
+#*.rtf diff=astextplain
+#*.RTF diff=astextplain
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ba3eab0
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,68 @@
+bin
+obj
+v14
+packages
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+*.userprefs
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+[Xx]64/
+[Xx]86/
+[Bb]uild/
+bld/
+#[Bb]in/
+[Oo]bj/
+.vs/
+[Tt]est[Rr]esult*/
+[Bb]uild[Ll]og.*
+*.VisualState.xml
+TestResult.xml
+[Dd]ebugPS/
+[Rr]eleasePS/
+dlldata.c
+project.lock.json
+artifacts/
+*_i.c
+*_p.c
+*_i.h
+*.ilk
+*.meta
+*.obj
+*.pch
+*.pdb
+*.pgc
+*.pgd
+*.rsp
+*.sbr
+*.tlb
+*.tli
+*.tlh
+*.tmp
+*.tmp_proj
+*.log
+*.vspscc
+*.vssscc
+.builds
+*.pidb
+*.svclog
+*.scc
+_Chutzpah*
+ipch/
+*.aps
+*.ncb
+*.opendb
+*.opensdf
+*.sdf
+*.cachefile
+*.VC.db
+*.psess
+*.vsp
+*.vspx
+*.sap
+
+node_modules/
\ No newline at end of file
diff --git a/MSWordLite.Cmd/App.config b/MSWordLite.Cmd/App.config
new file mode 100644
index 0000000..787dcbe
--- /dev/null
+++ b/MSWordLite.Cmd/App.config
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/MSWordLite.Cmd/MSWordLite.Cmd.csproj b/MSWordLite.Cmd/MSWordLite.Cmd.csproj
new file mode 100644
index 0000000..8881faa
--- /dev/null
+++ b/MSWordLite.Cmd/MSWordLite.Cmd.csproj
@@ -0,0 +1,62 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {8B51C380-7197-4191-BED0-9B7DDF9C7ACC}
+ Exe
+ MSWordLite.Cmd
+ MSWordLite.Cmd
+ v4.7.1
+ 512
+ true
+ true
+
+
+ AnyCPU
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ AnyCPU
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {2f59728e-ddab-426a-9c71-4aa1373b11c2}
+ MSWordLite
+
+
+
+
\ No newline at end of file
diff --git a/MSWordLite.Cmd/Program.cs b/MSWordLite.Cmd/Program.cs
new file mode 100644
index 0000000..3b666d7
--- /dev/null
+++ b/MSWordLite.Cmd/Program.cs
@@ -0,0 +1,89 @@
+using MSWordLite.Orders;
+using MSWordLite.Tasks;
+using System;
+using System.Collections.Generic;
+
+namespace MSWordLite.Cmd
+{
+ class ReplaceContent
+ {
+ public string Bookmark0 { get; set; } = "NewText0";
+ public string Bookmark1 { get; set; } = "NewText1";
+ public string Bookmark2 { get; set; } = "NewText2";
+ }
+
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ var task = new GenerateTask()
+ {
+ //TemplatePath = @"C:\Developing\MSWordLite\template_replaceBookmark.docx",
+ TemplatePath = @"C:\Developing\MSWordLite\template_expandTable.docx",
+ //TemplatePath = @"C:\Developing\MSWordLite\template_duplicateTable.docx",
+ OutputPath = @"C:\Developing\MSWordLite\out.docx"
+ };
+
+ try
+ {
+ task.Orders.Add(ReplaceBookmarkOrder.CreateFrom(new ReplaceContent()));
+
+ //task.Orders.Add(ReplaceBookmarkOrder.CreateFrom(new Dictionary()
+ //{
+ // { "Bookmark0", "NewText0" },
+ // { "Bookmark1", "NewText1" },
+ // { "Bookmark2", "NewText2" }
+ //}));
+
+ task.Orders.Add(ExpandTableOrder.CreateFrom(0, new List>()
+ {
+ new List() { "1", "Data1", "Description1" },
+ new List() { "2", "Data2", "Description2" },
+ new List() { "3", "Data3", "Description3" },
+ }));
+
+ //task.Orders.Add(DuplicateTableOrder.CreateFrom(0, new List>()
+ //{
+ // new Dictionary()
+ // {
+ // { "Index", "1" },
+ // { "All", "2" },
+ // { "Insert0", "NewText0" },
+ // { "Insert1", "NewText1" },
+ // { "Insert2", "NewText2" },
+ // { "Insert3", "NewText3" },
+ // { "Insert4", "NewText4 NewText4 NewText4 NewText4" },
+ // { "Insert5", "NewText5 NewText5 NewText5 NewText5 NewText5 NewText5 NewText5" },
+ // },
+ // new Dictionary()
+ // {
+ // { "Index", "2" },
+ // { "All", "2" },
+ // { "Insert0", "NewText0-1" },
+ // { "Insert1", "NewText1-1" },
+ // { "Insert2", "NewText2-1" },
+ // { "Insert3", "NewText3-1" },
+ // { "Insert4", "NewText4-1 NewText4 NewText4 NewText4-1" },
+ // { "Insert5", "NewText5-1 NewText5 NewText5 NewText5 NewText5 NewText5 NewText5-1" },
+ // }
+ //}));
+
+ task.Orders.Add(new ClearBookmarkOrder());
+
+ WordProcess.Run(task).Wait();
+
+ if (task.State == ProcessState.Failure)
+ {
+ Console.WriteLine(task.Error);
+ }
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex.ToString());
+ }
+
+ Console.ReadLine();
+ task.Dispose();
+ }
+ }
+}
diff --git a/MSWordLite.Cmd/Properties/AssemblyInfo.cs b/MSWordLite.Cmd/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..2c52feb
--- /dev/null
+++ b/MSWordLite.Cmd/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 組件的一般資訊是由下列的屬性集控制。
+// 變更這些屬性的值即可修改組件的相關
+// 資訊。
+[assembly: AssemblyTitle("MSWordLite.Cmd")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("MSWordLite.Cmd")]
+[assembly: AssemblyCopyright("Copyright © 2019")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 將 ComVisible 設為 false 可對 COM 元件隱藏
+// 組件中的類型。若必須從 COM 存取此組件中的類型,
+// 的類型,請在該類型上將 ComVisible 屬性設定為 true。
+[assembly: ComVisible(false)]
+
+// 下列 GUID 為專案公開 (Expose) 至 COM 時所要使用的 typelib ID
+[assembly: Guid("8b51c380-7197-4191-bed0-9b7ddf9c7acc")]
+
+// 組件的版本資訊由下列四個值所組成:
+//
+// 主要版本
+// 次要版本
+// 組建編號
+// 修訂編號
+//
+// 您可以指定所有的值,或將組建編號或修訂編號設為預設值
+// 指定為預設值:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/MSWordLite.sln b/MSWordLite.sln
new file mode 100644
index 0000000..ededf4b
--- /dev/null
+++ b/MSWordLite.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.28307.168
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MSWordLite", "MSWordLite\MSWordLite.csproj", "{2F59728E-DDAB-426A-9C71-4AA1373B11C2}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MSWordLite.Cmd", "MSWordLite.Cmd\MSWordLite.Cmd.csproj", "{8B51C380-7197-4191-BED0-9B7DDF9C7ACC}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {2F59728E-DDAB-426A-9C71-4AA1373B11C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2F59728E-DDAB-426A-9C71-4AA1373B11C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2F59728E-DDAB-426A-9C71-4AA1373B11C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2F59728E-DDAB-426A-9C71-4AA1373B11C2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8B51C380-7197-4191-BED0-9B7DDF9C7ACC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8B51C380-7197-4191-BED0-9B7DDF9C7ACC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8B51C380-7197-4191-BED0-9B7DDF9C7ACC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8B51C380-7197-4191-BED0-9B7DDF9C7ACC}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {AC3A6807-E0DE-4525-9CFA-D4B61AA0BAA8}
+ EndGlobalSection
+EndGlobal
diff --git a/MSWordLite/Contexts/ProcessState.cs b/MSWordLite/Contexts/ProcessState.cs
new file mode 100644
index 0000000..70eb60c
--- /dev/null
+++ b/MSWordLite/Contexts/ProcessState.cs
@@ -0,0 +1,33 @@
+namespace MSWordLite
+{
+ ///
+ /// 執行狀態
+ ///
+ public enum ProcessState
+ {
+ ///
+ /// 等待中
+ ///
+ Waiting,
+
+ ///
+ /// 初始化中
+ ///
+ Initilized,
+
+ ///
+ /// 成功
+ ///
+ Success,
+
+ ///
+ /// 失敗
+ ///
+ Failure,
+
+ ///
+ /// 產出的檔案已刪除
+ ///
+ Disposed
+ }
+}
diff --git a/MSWordLite/Elements/Bookmark.cs b/MSWordLite/Elements/Bookmark.cs
new file mode 100644
index 0000000..1ca6c11
--- /dev/null
+++ b/MSWordLite/Elements/Bookmark.cs
@@ -0,0 +1,192 @@
+using DocumentFormat.OpenXml;
+using DocumentFormat.OpenXml.Wordprocessing;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace MSWordLite.Elements
+{
+ ///
+ /// Word 文件書籤
+ ///
+ class Bookmark
+ {
+ public string Id { get; set; }
+ public string Name { get; set; }
+ public BookmarkStart Start { get; set; }
+ public BookmarkEnd End { get; set; }
+ public bool Valid => !string.IsNullOrEmpty(Name) && Start != null && End != null;
+
+ public Bookmark(BookmarkStart start)
+ {
+ if (start != null)
+ {
+ Start = start;
+ Name = Start.Name;
+ Id = Start.Id;
+ }
+ }
+
+ public Bookmark AppendEnd(BookmarkEnd end)
+ {
+ End = end;
+ return this;
+ }
+
+ public bool Replace(string text)
+ {
+ if (!Valid) { return false; }
+
+ var splitedText = text.Split(new string[] { "
" }, StringSplitOptions.None);
+
+ _clearBetweenStartAndEnd(Start);
+
+ var run = _createRunFromTexts(Start, splitedText);
+ Start.Parent.InsertAfter(run, Start);
+
+ return true;
+ }
+
+ private static void _clearBetweenStartAndEnd(BookmarkStart start)
+ {
+ var elem = start.NextSibling();
+ var paragraph = start.Parent as Paragraph;
+
+ while (elem != null && !(elem is BookmarkEnd))
+ {
+ var nextElem = elem.NextSibling();
+ elem.Remove();
+ elem = nextElem;
+ }
+
+ if (!(elem is BookmarkEnd))
+ {
+ var pg = paragraph.NextSibling();
+ while (pg != null && !(elem is BookmarkEnd))
+ {
+ var bookmarkEnd = _findBookmarkEnd(pg, start.Id);
+ if (bookmarkEnd != null)
+ {
+ elem = bookmarkEnd;
+
+ var nextElem = bookmarkEnd.NextSibling();
+ paragraph.AppendChild(bookmarkEnd.CloneNode(true));
+ while (nextElem != null)
+ {
+ paragraph.AppendChild(nextElem.CloneNode(true));
+ nextElem = nextElem.NextSibling();
+ }
+
+ pg.Remove();
+ }
+ else
+ {
+ var nextPg = pg.NextSibling();
+ pg.Remove();
+ pg = nextPg;
+ }
+ }
+ }
+ }
+
+ private static BookmarkEnd _findBookmarkEnd(OpenXmlElement documentElement, string id)
+ {
+ foreach (var elem in documentElement.ChildElements)
+ {
+ if (!(elem is BookmarkEnd end) || end.Id != id)
+ {
+ var result = _findBookmarkEnd(elem, id);
+ if (result != null)
+ {
+ return result;
+ }
+ }
+ else
+ {
+ return end;
+ }
+ }
+
+ return null;
+ }
+
+ private static Run _createRunFromTexts(BookmarkStart start, IEnumerable text)
+ {
+ var run = new Run();
+ var count = text.Count();
+ for (var i = 0; i < count; i++)
+ {
+ run.Append(new Text(text.ElementAt(i)));
+ if (i < count - 1)
+ {
+ run.Append(new Break());
+ }
+ }
+
+ var paragraph = start.Parent as Paragraph;
+ var pgp = paragraph.ChildElements.Where(child => child is ParagraphProperties).FirstOrDefault();
+ if (pgp != null)
+ {
+ var pgmrp = pgp.ChildElements.Where(child => child is ParagraphMarkRunProperties).FirstOrDefault();
+ if (pgmrp != null)
+ {
+ run.RunProperties = new RunProperties(pgmrp.OuterXml);
+ }
+ }
+
+ return run;
+ }
+
+ public void Remove()
+ {
+ if (Start != null)
+ {
+ Start.Remove();
+ }
+
+ if (End != null)
+ {
+ End.Remove();
+ }
+ }
+
+ public static Dictionary SearchFrom(
+ OpenXmlElement documentElement, Dictionary existedMap = null)
+ {
+ if (existedMap == null)
+ {
+ existedMap = new Dictionary();
+ }
+
+ foreach (var element in documentElement.Elements())
+ {
+ if (element is BookmarkStart)
+ {
+ var start = new Bookmark(element as BookmarkStart);
+ if (!existedMap.ContainsKey(start.Name))
+ {
+ existedMap.Add(start.Name, start);
+ }
+ }
+
+ if (element is BookmarkEnd)
+ {
+ var end = element as BookmarkEnd;
+ var name = existedMap
+ .Where(item => item.Value.Id == end.Id)
+ .Select(item => item.Value.Name)
+ .FirstOrDefault();
+
+ if (!string.IsNullOrEmpty(name))
+ {
+ existedMap[name] = existedMap[name].AppendEnd(end);
+ }
+ }
+
+ SearchFrom(element, existedMap);
+ }
+
+ return existedMap;
+ }
+ }
+}
diff --git a/MSWordLite/Elements/Table.cs b/MSWordLite/Elements/Table.cs
new file mode 100644
index 0000000..c3466a8
--- /dev/null
+++ b/MSWordLite/Elements/Table.cs
@@ -0,0 +1,40 @@
+using DocumentFormat.OpenXml;
+using System.Collections.Generic;
+using System.Linq;
+using WordTable = DocumentFormat.OpenXml.Wordprocessing.Table;
+using WordTableRow = DocumentFormat.OpenXml.Wordprocessing.TableRow;
+
+namespace MSWordLite.Elements
+{
+ ///
+ /// Word 文件表格
+ ///
+ class Table
+ {
+ public WordTable WordTable { get; set; }
+ public IEnumerable Rows => WordTable.ChildElements
+ .Where(child => child is WordTableRow).Select(child => new TableRow(child as WordTableRow));
+ public TableRow FirstRow => Rows.FirstOrDefault();
+ public TableRow LastRow => Rows.LastOrDefault();
+ public bool Valid => WordTable != default(WordTable);
+
+ public Table(WordTable table)
+ {
+ WordTable = table;
+ }
+
+ public Table Append(TableRow row)
+ {
+ WordTable.InsertAfter(row.WordRow, LastRow.WordRow);
+ return this;
+ }
+
+ public static List SearchFrom(OpenXmlElement documentElement)
+ {
+ return documentElement.Elements()
+ .Where(element => element is WordTable)
+ .Select(element => new Table(element as WordTable))
+ .ToList();
+ }
+ }
+}
diff --git a/MSWordLite/Elements/TableCell.cs b/MSWordLite/Elements/TableCell.cs
new file mode 100644
index 0000000..5dff2f9
--- /dev/null
+++ b/MSWordLite/Elements/TableCell.cs
@@ -0,0 +1,64 @@
+using DocumentFormat.OpenXml.Wordprocessing;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using WordTableCell = DocumentFormat.OpenXml.Wordprocessing.TableCell;
+
+namespace MSWordLite.Elements
+{
+ ///
+ /// Word 文件表格欄位
+ ///
+ class TableCell
+ {
+ public WordTableCell WordCell { get; set; }
+ public IEnumerable Paragraphs => WordCell.ChildElements
+ .Where(child => child is Paragraph).Select(child => (Paragraph)child);
+ public IEnumerable Runs => Paragraphs
+ .SelectMany(pg => pg.ChildElements.Where(pgc => pgc is Run).Select(pgc => (Run)pgc));
+ public bool Valid => WordCell != default(WordTableCell);
+
+ public TableCell(WordTableCell cell)
+ {
+ WordCell = cell;
+ }
+
+ public TableCell ReplaceText(string text)
+ {
+ var splitedText = text.Split(new string[] { "
" }, StringSplitOptions.None);
+ var pg = Paragraphs.FirstOrDefault();
+ var run = Runs.FirstOrDefault();
+ if (run != null)
+ {
+ var t = run.ChildElements[1] as Text;
+ t.Text = text;
+ }
+ else if (pg != null)
+ {
+ var newRun = new Run();
+ var count = splitedText.Count();
+ for (var i = 0; i < count; i++)
+ {
+ newRun.Append(new Text(splitedText.ElementAt(i)));
+ if (i < count - 1)
+ {
+ newRun.Append(new Break());
+ }
+ }
+
+ var pgp = pg.ChildElements.Where(child => child is ParagraphProperties).FirstOrDefault();
+ if (pgp != null)
+ {
+ var pgmrp = pgp.ChildElements.Where(child => child is ParagraphMarkRunProperties).FirstOrDefault();
+ if (pgmrp != null)
+ {
+ newRun.RunProperties = new RunProperties(pgmrp.OuterXml);
+ }
+ }
+
+ pg.AppendChild(newRun);
+ }
+ return this;
+ }
+ }
+}
diff --git a/MSWordLite/Elements/TableRow.cs b/MSWordLite/Elements/TableRow.cs
new file mode 100644
index 0000000..ebaf388
--- /dev/null
+++ b/MSWordLite/Elements/TableRow.cs
@@ -0,0 +1,42 @@
+using System.Collections.Generic;
+using System.Linq;
+using WordTableRow = DocumentFormat.OpenXml.Wordprocessing.TableRow;
+using WordTableCell = DocumentFormat.OpenXml.Wordprocessing.TableCell;
+
+namespace MSWordLite.Elements
+{
+ ///
+ /// Word 文件表格行
+ ///
+ class TableRow
+ {
+ public WordTableRow WordRow { get; set; }
+ public IEnumerable Cells => WordRow.ChildElements
+ .Where(child => child is WordTableCell).Select(child => new TableCell(child as WordTableCell));
+ public TableCell FirstCell => Cells.FirstOrDefault();
+ public TableCell LastCell => Cells.LastOrDefault();
+
+ public TableRow(WordTableRow row)
+ {
+ WordRow = row;
+ }
+ public bool Valid => WordRow != default(WordTableRow);
+
+ public TableRow Clone() =>
+ new TableRow((WordTableRow)WordRow.Clone());
+
+ public TableRow ReplaceText(IEnumerable texts)
+ {
+ for (var i = 0; i < texts.Count(); i++)
+ {
+ var cell = Cells.ElementAtOrDefault(i);
+ var text = texts.ElementAtOrDefault(i);
+ if (cell != null && text != "#COPY#")
+ {
+ cell.ReplaceText(text);
+ }
+ }
+ return this;
+ }
+ }
+}
diff --git a/MSWordLite/MSWordLite.csproj b/MSWordLite/MSWordLite.csproj
new file mode 100644
index 0000000..dfd938f
--- /dev/null
+++ b/MSWordLite/MSWordLite.csproj
@@ -0,0 +1,28 @@
+
+
+
+ netstandard1.3
+ 7.3
+
+
+
+ true
+ true
+ Frank Tsai
+ https://creativecommons.org/licenses/by-sa/3.0/
+ office word lite
+ This package provide several simple function:
+- Replace bookmark in document, use dictionary or anonymous object as input.
+- Expand specific table in document by input list of data.
+- Duplicate table and replace bookmark in newly created table.
+
+
+
+ C:\Users\frank\Source\Repos\MSWordLite\MSWordLite\MSWordLite.xml
+
+
+
+
+
+
+
diff --git a/MSWordLite/Orders/ClearBookmarkOrder.cs b/MSWordLite/Orders/ClearBookmarkOrder.cs
new file mode 100644
index 0000000..0a1baba
--- /dev/null
+++ b/MSWordLite/Orders/ClearBookmarkOrder.cs
@@ -0,0 +1,43 @@
+using System.Collections.Generic;
+using System.Text.RegularExpressions;
+
+namespace MSWordLite.Orders
+{
+ ///
+ /// Remove bookmarks in document
+ ///
+ public class ClearBookmarkOrder : IOrder
+ {
+ ///
+ /// If this order is valid.
+ ///
+ public bool Valid => Names != null || Regex != null;
+
+ public List Names { get; set; } = new List();
+
+ public Regex Regex { get; set; }
+
+ ///
+ /// Create an clear order to remove all bookmarks in doucment.
+ ///
+ public ClearBookmarkOrder() { }
+
+ ///
+ /// Create an clear order to remove specific name of bookmarks in document.
+ ///
+ ///
+ public ClearBookmarkOrder(List names)
+ {
+ Names = names;
+ }
+
+ ///
+ /// Create an clear order and use regex pattern to test if bookmarks need to be remove in document.
+ ///
+ ///
+ public ClearBookmarkOrder(string regexPattern)
+ {
+ Regex = new Regex(regexPattern);
+ }
+ }
+}
diff --git a/MSWordLite/Orders/DuplicateTableOrder.cs b/MSWordLite/Orders/DuplicateTableOrder.cs
new file mode 100644
index 0000000..487fc43
--- /dev/null
+++ b/MSWordLite/Orders/DuplicateTableOrder.cs
@@ -0,0 +1,77 @@
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+
+namespace MSWordLite.Orders
+{
+ public class DuplicateTableOrder : IOrder
+ {
+ ///
+ /// Index of template table
+ ///
+ public int TableId { get; set; }
+
+ ///
+ /// Contents to replace
+ ///
+ public List> ReplaceContents { get; set; } = new List>();
+
+ ///
+ /// Check if this order is valid.
+ ///
+ public bool Valid => ReplaceContents != null && TableId >= 0;
+
+ ///
+ ///
+ ///
+ /// Index of template table.
+ /// Contents to replace.
+ public DuplicateTableOrder(int tableId, List> replaceContents)
+ {
+ TableId = tableId;
+ ReplaceContents = replaceContents;
+ }
+
+ ///
+ ///
+ ///
+ /// Index of template table.
+ /// Contents to replace.
+ public DuplicateTableOrder(int tableId, List