【问题标题】:How to modify Excel [Content_Types].xml file generated by C# OpenXML如何修改 C# OpenXML 生成的 Excel [Content_Types].xml 文件
【发布时间】:2020-03-10 07:23:55
【问题描述】:

我正在使用 OpenXML SDK 库在 C# 中生成 Excel 文件。 我注意到生成的内容文件 ([Content_Types].xml) 与 Excel 在保存文件时生成的内容不同。

由于某种原因,我的 OpenXML 生成的文件缺少

<Default ContentType="application/xml" Extension="xml"/>

元素并放置

&lt;Default Extension="xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml" /&gt;

元素代替。

OpenXML 生成的文件如下所示:

<?xml version="1.0" encoding="utf-8"?>
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml" />
<Default Extension="xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml" />
<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml" />
<Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml" />
<Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml" />
<Override PartName="/xl/theme/theme1.xml" ContentType="application/vnd.openxmlformats-officedocument.theme+xml" />
<Override PartName="/xl/sharedStrings.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml" />
<Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml" />
</Types>

我想实现以下目标:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
<Default Extension="bin" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.printerSettings"/>
<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
<Default Extension="xml" ContentType="application/xml"/>
<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>
<Override PartName="/xl/worksheets/sheet1.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>
<Override PartName="/xl/theme/theme1.xml" ContentType="application/vnd.openxmlformats-officedocument.theme+xml"/>
<Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/>
<Override PartName="/xl/sharedStrings.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"/>
<Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/>
<Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/>
</Types>

也是一个缺失的元素,我想补充一下

<Default Extension="bin" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.printerSettings"/>

有没有使用 OpenXML 库访问内容类型的方法? 我想避免手动解包 xlsx 文件并修改 [Content_Types].xml 的来源的方法

【问题讨论】:

  • 为什么改变这些很重要?涉及哪个版本的 Excel? Open XML SDK default 是为了兼容 Office 2007。因此,较新版本的 Excel 可能会生成不同的内容。 Open XML SDK允许直接访问这些东西。您可以尝试在 Excel 中打开这样的文件,稍作更改以使其“变脏”,然后保存为新文件名。在 Open XML SDK Productivity Tool 中打开原始版本,然后使用比较功能打开更改后的版本。这应该会向您显示将第一个“转换”为第二个的代码。
  • 我正在使用 OpenXML SDK 生成 Excel 文件,稍后应该由 OleDB 读取。由于某种原因,“外部表不是预期的格式。”错误。我知道使用 EPPlus Lib 文件可以被 OLE 解析。也许是出于好奇,或者我只是很固执,我想这样做OpenXML。这个想法是生成与 EPPlus 或 Excel 完全相同的内容。

标签: c# excel openxml content-type openxml-sdk


【解决方案1】:

最简单的解决方案是使用具有所需内容类型的适当 Excel 工作簿作为起点。

使用 Open XML SDK,您可以从 Excel 模板 (.xslt) 创建工作簿或克隆现有的 Excel 工作簿(.xlsx、.xlsm)。您可以通过在现有SpreadsheetDocument 对象上调用Clone() 方法或将数据读入MemoryStream、打开该MemoryStream 上的SpreadsheetDocument,然后将其保存到不同的文件来克隆工作簿(或数据库或其他)在最后。

以下示例从模板(或工作簿)创建 Excel 工作簿:

SpreadsheetDocument doc = SpreadsheetDocument.CreateFromTemplate("Template.xlst");

如果您查看CreateFromTemplate() 方法是如何实现的,您会发现它总是克隆工作簿或模板。对于模板,它会更改文档类型(使用ChangeDocumentType() 方法),以便您始终获得工作簿而不是模板。因此,如果您的入门模板或工作簿存储在文件系统中,这将是最直接的方法。

根据“模板”的存储方式和位置,还有其他方法可以达到相同的效果。但是,您通常会生成带有模板或工作簿数据的Stream(例如MemoryStream),然后在该Stream 上打开SpreadsheetDocument

【讨论】:

    【解决方案2】:
        using (var archive = ZipFile.Open(filePath, ZipArchiveMode.Update))
        {
            var entry = archive.GetEntry("[Content_Types].xml");
    
            //Replace the content
            StringBuilder sb = new StringBuilder();
            sb.Append("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\" ?>");
            sb.Append("<Types xmlns=\"http://schemas.openxmlformats.org/package/2006/content-types\">");
            //sb.Append("<Default Extension=\"bin\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.printerSettings\"/>");
            sb.Append("<Default Extension=\"rels\" ContentType=\"application/vnd.openxmlformats-package.relationships+xml\"/>");
            sb.Append("<Default Extension=\"xml\" ContentType=\"application/xml\"/>");
            sb.Append("<Override PartName=\"/xl/workbook.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml\" />");
            sb.Append("<Override PartName=\"/xl/worksheets/sheet1.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml\" />");
            sb.Append("<Override PartName=\"/xl/theme/theme1.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.theme+xml\" />");
            sb.Append("<Override PartName=\"/xl/styles.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml\" />");
            sb.Append("<Override PartName=\"/xl/sharedStrings.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml\" />");
            sb.Append("<Override PartName=\"/docProps/core.xml\" ContentType=\"application/vnd.openxmlformats-package.core-properties+xml\" />");
            sb.Append("<Override PartName=\"/docProps/app.xml\" ContentType=\"application/vnd.openxmlformats-officedocument.extended-properties+xml\" />");
            sb.Append("</Types>");
    
            entry.Delete();
            entry = archive.CreateEntry([Content_Types].xml);
            using (StreamWriter writer = new StreamWriter(entry.Open()))
            {
                writer.Write(sb);
            }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-21
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多