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,...
