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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM