Word 中的公式解析和還原方式與說明
Word 中的公式解析和還原方式與說明
首先我們知道doc(office 2003)是流,docx(> office 2007)是open xml格式
我想跨平台解析wrod 里面的公式 docx(> office 2007),於是我發現公式有3種格式(可能>3種)
這里有一個差異化文檔信息(Vsto和OpenXml對比):
https://kdocs.cn/l/seF0uZqMdfVc
目前Html里常用公式種類有:LaTex,MathML(點擊手寫生成公式)
目前Word里常用公式種類有:EQ公式域(eq field),OMath公式(omml),MathType公式,axMath公式(國產)
//附:域獲取方法(如需轉為圖片請看文章 https://www.cnblogs.com/ping9719/p/15205267.html) Application.ActiveDocument.Fields.Item(1).Code.Text
1.OMath公式(office>=2007)(只有這種支持open xml解析,通過OMML2MML.XSL文件;eq理論上也支持,但是需要自己寫)
2.老公式(office<2007)
3.wps老公式
於是我寫下了 這一篇文章 把 word 解析為html 希望支持 文字,圖片,公式(未實現),表格(未實現)
https://www.cnblogs.com/ping9719/p/12462478.html (如果需要簡單的解析為html的可以參考此文檔)
根據上面的文章,我並不想管其他2個公式(只支持“1.新ms office公式(>=2007)”這種方法),我發現也有很多的問題:
1.公式解析是別人寫的
2.公式前端還需要額外的js庫
3.公式沒有辦法逆轉回去(html->word),除非自己寫逆轉方法(太難了)。
於是我在換思路:
所以我這邊建議使用 wps 或者 ms office 轉為html+xml,這樣子就支持了所有的公式和格式
wps 支持跨平台(jsapi):
https://code.aliyun.com/zouyingfeng/wps/tree/master
https://zhuanlan.zhihu.com/c_1256350603921915904
但是為了方便我沒有使用wps+jsapi
我使用為wps+vsto,他們的類庫差不多的,可以有參考價值
實現的思路為:
代碼實現:
建立項目 net standard 2.0
隨便為了支持一下 net 4.5版本
編輯 .csproj 文件
<PropertyGroup> <TargetFrameworks>net45;netstandard20</TargetFrameworks> </PropertyGroup>
引用COM:
引用包對C#語言支持:
我的項目結構為:
這個結構方便我以后對ppt和excel的支持代碼,同事支持wps+ms office
下面開始:
加入文件 OfficeApp.cs
/// <summary> /// office應用 /// </summary> public class OfficeApp { /// <summary> /// WPS 2019+窗體模式 是否為整合模式 /// </summary> private bool? IsWpsFormMergeModel { get { return null; } } /// <summary> /// 得到進程中的word應用 /// </summary> /// <param name="appType">0沒有找到 1 office 2 wps</param> /// <returns>word應用</returns> public static object GetProcessesWordApp(out OfficeType officeType) { officeType = OfficeType.Null; //MS Office if (Process.GetProcessesByName("WINWORD").Count() > 0) { officeType = OfficeType.Microsoft; return DllImportHelp.GetActiveObject("Word.Application"); } else if (Process.GetProcessesByName("wps").Count() > 0) { //WPS Office V9 if (Type.GetTypeFromProgID("KWPS.Application") != null) { officeType = OfficeType.WPS; return DllImportHelp.GetActiveObject("KWPS.Application"); } //WPS Office V8 else if (Type.GetTypeFromProgID("WPS.Application") != null) { officeType = OfficeType.WPS; return DllImportHelp.GetActiveObject("WPS.Application"); } else return null; } else { return null; } } }
加入文件 RangeEx.cs
public static class RangeEx { /// <summary> /// 統一設置顏色(文字,下划線,音調符號,表格邊框) /// </summary> public static void SetColor(this Range range, WdColor wdColor) { range.Font.Color = wdColor; range.Font.DiacriticColor = wdColor; range.Font.UnderlineColor = wdColor; foreach (Table table in range.Tables) { table.Borders.InsideColor = wdColor; table.Borders.OutsideColor = wdColor; } } /// <summary> /// 是否無內容 /// </summary> public static bool IsNull(this Range range) { //對公式等檢測 if (range.Text.Length == range.End - range.Start) { //對圖片等檢測 string txt = range.Text.Replace("\r", "").Replace("\n", "").Replace("\v", ""); if (string.IsNullOrEmpty(txt)) return true; } return false; } /// <summary> /// 是否無內容或者空格組成 /// </summary> public static bool IsNullOrSpace(this Range range) { //對公式等檢測 if (range.Text.Length == range.End - range.Start) { //對圖片等檢測 string txt = range.Text.Trim(); if (string.IsNullOrWhiteSpace(txt)) return true; } return false; } /// <summary> /// 替換 /// </summary> /// <param name="range"></param> /// <param name="findText">查找內容</param> /// <param name="replacementText">替換內容</param> public static bool Replace(this Range range, string findText, string newValue) { Find find = range.Find; find.Replacement.ClearFormatting(); find.Text = findText; find.Replacement.Text = newValue; find.Forward = false; find.Wrap = WdFindWrap.wdFindStop; find.Format = false; find.MatchCase = true;//區分大小寫 find.MatchWholeWord = false; find.MatchByte = true; find.MatchAllWordForms = false; find.MatchSoundsLike = false; find.MatchWildcards = false; find.MatchFuzzy = false; return find.Execute(MatchControl: WdReplace.wdReplaceAll); } /// <summary> /// 得到環繞模式為懸浮的表格 /// </summary> /// <param name="range"></param> public static List<Table> GetFloatTable(this Range range) { if (range == null) //....................此文件十分重要,只貼部分代碼......
加入文件 DllImportHelp.cs
public static class DllImportHelp { /// <summary> /// net core 沒有GetActiveObject()方法 所以調用dll /// </summary> /// <param name="progId"></param> /// <returns></returns> public static object GetActiveObject(string progId) { if (progId == null) return null; var hr = CLSIDFromProgIDEx(progId, out var clsid); if (hr < 0) return null; hr = GetActiveObject(clsid, IntPtr.Zero, out var obj); if (hr < 0) return null; return obj; } [DllImport("ole32")] private static extern int CLSIDFromProgIDEx([MarshalAs(UnmanagedType.LPWStr)] string lpszProgID, out Guid lpclsid); [DllImport("oleaut32")] private static extern int GetActiveObject([MarshalAs(UnmanagedType.LPStruct)] Guid rclsid, IntPtr pvReserved, [MarshalAs(UnmanagedType.IUnknown)] out object ppunk); }
/// <summary> /// office程序類型 /// </summary> public enum OfficeType { /// <summary> /// 為空的 /// </summary> Null, /// <summary> /// WPS Office /// </summary> WPS, /// <summary> /// Microsoft Office /// </summary> Microsoft, /// <summary> /// 未知的程序 /// </summary> Unknown, }
加入文件 WordApp.cs
/// <summary> /// Word應用 /// </summary> public class WordApp { /// <summary> /// 查找符:軟回車,同html中的br /// </summary> public const string Find_BlankRow = "^l"; /// <summary> /// 查找符:段落 /// </summary> public const string Find_Paragraph = "^p"; /// <summary> /// 查找符:段落 通配符 /// </summary> public const string Find_ParagraphASCII = "^13"; private OfficeType _AppType = OfficeType.Null; /// <summary> /// Office類型 /// </summary> public OfficeType AppType { get { if (_AppType != OfficeType.Null) return _AppType; if (File.Exists(App.Path + "/wps.exe") || File.Exists(App.Path + "wpsoffice.exe")) _AppType = OfficeType.WPS; else if (File.Exists(App.Path + "/MSOHTMED.EXE") || File.Exists(App.Path + "MSQRY32.EXE")) _AppType = OfficeType.Microsoft; else _AppType = OfficeType.Unknown; return _AppType; } private set { _AppType = value; } } /// <summary> /// 整個應用程序 /// </summary> public Application App { get; private set; } /// <summary> /// 活動中(正在操作)的Word文檔 /// </summary> public Document Doc { get; private set; } /// <summary> /// 是否存在文件路徑 /// </summary> public bool IsExistFilePath { get => Doc.FullName.Contains(':'); } ///// <summary> ///// 初始化程序和活動中的word (vsto) ///// </summary> //public WordApp() //{ // App = Globals.ThisAddIn.Application; // try // { // Doc = App.ActiveDocument; // } // catch { } //} /// <summary> /// 初始化word程序 /// </summary> public WordApp() { var wordObj = OfficeApp.GetProcessesWordApp(out OfficeType officeType); if (wordObj == null) App = new Application(); else { App = (Application)wordObj; AppType = officeType; } Doc = App.Documents.Add(); } /// <summary> /// 初始化word程序 /// </summary> public WordApp(string fileName) { var wordObj = OfficeApp.GetProcessesWordApp(out OfficeType officeType); if (wordObj == null) App = new Application(); else { App = (Application)wordObj; AppType = officeType; } Doc = App.Documents.Open(fileName); } /// <summary> /// 初始化程序,需要有活動中的word /// </summary> public WordApp(Application app) { App = app; try { Doc = app.ActiveDocument; } catch { } } /// <summary> /// 初始化word程序 /// </summary> public WordApp(Document doc) { if (doc != null) { App = doc.Application; Doc = doc; } } /// <summary> /// 全新的文檔 /// </summary> public void NewDoc() { Close(); Doc = App.Documents.Add(); } /// <summary> /// 得到文檔的數量 /// </summary> public int GetDocCount() { if (App == null) return 0; return App.Documents.Count; } /// <summary> /// 替換(WPS 有些情況有bug) /// </summary> /// <param name="findText">查找內容</param> /// <param name="newValue">替換內容</param> public bool Replace(string findText, string newValue) { return RangeEx.Replace(Doc.Content, findText, newValue); }
//....................此文件十分重要,只貼部分代碼......
--------------------------------------------------
-----------------------------------------------
-----------------------
-----------
---
開始(最重要的代碼):
//導出 //全文 new WordApp().Doc.Content.ExportFragment(@"D:\123.html", WdSaveFormat.wdFormatHTML); //部分,段落,公式... Range.ExportFragment(@"D:\123.html", WdSaveFormat.wdFormatHTML); //全文 new WordApp().Doc.Content.ExportFragment(@"D:\123.xml", WdSaveFormat.wdFormatXMLDocument); //部分,段落,公式... Range.ExportFragment(@"D:\123.xml", WdSaveFormat.wdFormatXMLDocument);
html里面有很多無用的標簽,需要自己清除
//還原 Range.InsertFile(@"D:\123.html"); Range.InsertFile(@"D:\123.xml");
部署到IIS的問題:
1.需要安裝。net core 對應版本的運行時(自己百度)
2.需要給iis管理員權限(https://blog.csdn.net/q646926099/article/details/52421273)
ok,...