65.9K
CodeProject 正在变化。 阅读更多。
Home

C# Docx 转 HTML 转 Docx

starIconstarIconstarIconstarIconstarIcon

5.00/5 (18投票s)

2016年12月22日

CPOL

3分钟阅读

viewsIcon

74407

downloadIcon

6116

将 Docx 转换为 Html 再转换为 Docx

引言

GitHub: https://github.com/zaagan/Docx-Html-Docx.git

如果我写的这个文章使用的 WYSIWYG 编辑器也有一个 从 Docx 上传 按钮,我就可以在几秒钟内直接从我的 docx 文件上传整篇文章了。 好吧,我可以只使用 从 Word 粘贴 按钮。 但是要从 Word 文档粘贴,我们需要在系统(在 Windows 中)上安装 Microsoft Office 包。

本文是解决该问题的方法,也有助于 C# 开发人员执行 Docx-HTML-Docx 转换。 本文中的资源是从许多不同的地方收集的,以及全球许多优秀的开发人员提供的解决方案,并将它们组合成一个小型的示例应用程序,以便开发人员不必为了寻找常见问题的解决方案而四处奔波。

现在,我们将研究如何进行转换。 在本文的下一章中,我们将创建我们自己的 CKEditor 插件以从 Docx 上传(即将推出:D)。

要求

  1. DocumentFormat.OpenXml.dll (2.6.0.0) [ 用于 Docx 到 Html 转换 ]
  2. DocumentFormat.OpenXml.dll (2.5.5631.0) [ 用于 Html 到 Docx 转换 ]
    实际上我们不必包含两组相同的 DLL,但由于一些 DLL 问题,这是强制性的
  3. OpenXmlPowerTools.dll
  4. System.IO.Packaging.dll (1.0.0.0)
  5. HtmlToOpenXml(1.6.0.0)
  6. System.Drawing [ 添加引用 ]
  7. System.IO.Compression [ 添加引用 ]
  8. CKEditor (4.6.1 Standard) - 您的选择

注意:您也可以在我随本文一起附加的项目中找到上述 DLL。

背景

Docx 到 HTML 正在成为当今非常普遍的需求,主要是如果您有一个 CMS 或正在构建一个 CMS,并且您的 WYSIWYG 编辑器想要此功能。 如果您注意到,您还可以在 StackOverflow 中找到许多关于 Docx 到 Html 转换的问题。

我写这篇文章的编辑器也有自己的 从 Word 粘贴 按钮。 如果它有一个直接从 docx 文件上传的功能,那将会更好。 我希望此功能很快将在所有 WYSIWYG 编辑器中可用。

接下来本文打算做的是如下图所示

好吧,如果您不知道什么是 Docx 文件,那么它只是一个像我们普通的 zip 文件一样的打包文件,具有自己的一组标准化结构。 如果您尝试使用解压缩器或 Zip 提取器解压缩 docx 文件,您会得到这个

有关包装结构的完整详细信息,您可以前往以下链接

Using the Code

将 Docx 文件数据转换为 HTML 内容就像以下代码显示的那样简单

DocxToHTML.Converter.HTMLConverter converter = new DocxToHTML.Converter.HTMLConverter();
string htmlContent = converter.ConvertToHtml(YOUR-DOCX-FILE);

如果您正在构建一个 ASP.NET 应用程序,您可以将转换后的 HTML 内容发送到客户端,但出于演示目的,我已在 WinForm WebBrowser 控件内的 CKEditor 控件中显示了输出。

解析 docx 内容时我们需要注意的一件事是检查可能导致异常的损坏的超链接。 以下代码旨在处理该异常。

string htmlText = string.Empty;
try
{
    htmlText = ParseDOCX(fileInfo);
}
catch (OpenXmlPackageException e)
{
    if (e.ToString().Contains("Invalid Hyperlink"))
    {
        using (FileStream fs = new FileStream(fullFilePath, 
                                   FileMode.OpenOrCreate, FileAccess.ReadWrite))
        {
            UriFixer.FixInvalidUri(fs, brokenUri => FixUri(brokenUri));
        }
        htmlText = ParseDOCX(fileInfo);
    }
}

return htmlText;

实际的解析由以下方法完成

private string ParseDOCX(FileInfo fileInfo)
{
    try
    {
         byte[] byteArray = File.ReadAllBytes(fileInfo.FullName);
         using (MemoryStream memoryStream = new MemoryStream())
         {
              memoryStream.Write(byteArray, 0, byteArray.Length);
              using (WordprocessingDocument wDoc = 
                                        WordprocessingDocument.Open(memoryStream, true))
              {
                    int imageCounter = 0;
                    var pageTitle = fileInfo.FullName;
                    var part = wDoc.CoreFilePropertiesPart;
                    if (part != null)
                        pageTitle = (string)part.GetXDocument()
                                                .Descendants(DC.title)
                                                .FirstOrDefault() ?? fileInfo.FullName;
                    
                    WmlToHtmlConverterSettings settings = new WmlToHtmlConverterSettings()
                    {
                         AdditionalCss = "body { margin: 1cm auto; max-width: 20cm; padding: 0; }",
                         PageTitle = pageTitle,
                         FabricateCssClasses = true,
                         CssClassPrefix = "pt-",
                         RestrictToSupportedLanguages = false,
                         RestrictToSupportedNumberingFormats = false,
                         ImageHandler = imageInfo =>
                         {
                             ++imageCounter;
                             string extension = imageInfo.ContentType.Split('/')[1].ToLower();
                             ImageFormat imageFormat = null;
                             if (extension == "png") imageFormat = ImageFormat.Png;
                             else if (extension == "gif") imageFormat = ImageFormat.Gif;
                             else if (extension == "bmp") imageFormat = ImageFormat.Bmp;
                             else if (extension == "jpeg") imageFormat = ImageFormat.Jpeg;
                             else if (extension == "tiff")
                             {
                                 extension = "gif";
                                 imageFormat = ImageFormat.Gif;
                             }
                             else if (extension == "x-wmf")
                             {
                                  extension = "wmf";
                                  imageFormat = ImageFormat.Wmf;
                             }

                             if (imageFormat == null) return null;

                             string base64 = null;
                             try
                             {
                                  using (MemoryStream ms = new MemoryStream())
                                  {
                                        imageInfo.Bitmap.Save(ms, imageFormat);
                                        var ba = ms.ToArray();
                                        base64 = System.Convert.ToBase64String(ba);
                                  }
                             }
                             catch (System.Runtime.InteropServices.ExternalException)
                             { return null; }

                             ImageFormat format = imageInfo.Bitmap.RawFormat;
                             ImageCodecInfo codec = ImageCodecInfo.GetImageDecoders()
                                                       .First(c => c.FormatID == format.Guid);
                             string mimeType = codec.MimeType;

                             string imageSource = 
                                    string.Format("data:{0};base64,{1}", mimeType, base64);
                             
                             XElement img = new XElement(Xhtml.img,
                                   new XAttribute(NoNamespace.src, imageSource),
                                   imageInfo.ImgStyleAttribute,
                                   imageInfo.AltText != null ?
                                        new XAttribute(NoNamespace.alt, imageInfo.AltText) : null);
                             return img;                            
                          }   
                    };

                    XElement htmlElement = WmlToHtmlConverter.ConvertToHtml(wDoc, settings);
                    var html = new XDocument(new XDocumentType("html", null, null, null),
                                                                                htmlElement);
                    var htmlString = html.ToString(SaveOptions.DisableFormatting);
                    return htmlString;
              }
         }
    }
    catch
    {
        return "File contains corrupt data";
    }
}

Uri 修复代码如下

private static string FixUri(string brokenUri)
{
     string newURI = string.Empty;
     if (brokenUri.Contains("mailto:"))
     {
         int mailToCount = "mailto:".Length;
         brokenUri = brokenUri.Remove(0, mailToCount);
         newURI = brokenUri;
     }
     else
     {
        newURI = " ";
     }
     return newURI;
}

可以在以下链接中查看 HTML 到 Docx 的转换

来源

我要感谢每一个人为这个主题贡献的有益解决方案和遇到的各种问题。

© . All rights reserved.