Word 中的公式解析和还原方式与说明
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,...

浙公网安备 33010602011771号