使用C# Open XML SDK生成的PPT损坏空白问题排查修复
解决Open XML SDK生成PPT报错且内容为空的问题
一、版本兼容性说明
你使用的DocumentFormat.OpenXml 2.20.0版本完全兼容.NET 6和Office 365,版本本身无问题,报错并非版本导致。
二、代码中的核心问题及修复
你的代码存在3个关键问题,导致PowerPoint无法正常解析:
1. SlidePart未关联SlideLayoutPart
每个幻灯片必须绑定对应的版式,代码中创建了母版和版式,但未建立SlidePart与SlideLayoutPart的关联关系,PowerPoint无法识别幻灯片结构。
2. GraphicFrame尺寸设置为0
Transform中的Cx(宽度)和Cy(高度)设为0L,导致表格实际尺寸为0,PowerPoint会判定为无效内容并删除。
3. 母版和版式创建顺序错误且内容缺失
应先创建SlideMaster和SlideLayout,再创建SlidePart;同时空的母版和版式缺少必要的默认占位符元素,易引发兼容性问题。
修复后的完整核心代码
using DocumentFormat.OpenXml; using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Presentation; using D = DocumentFormat.OpenXml.Drawing; namespace OpenXMLBuilder { class Test3 { public void Doit(string[] args) { string filepath = "test3.pptx"; CreatePresentation(filepath); } public static void CreatePresentation(string filepath) { using (PresentationDocument presentationDocument = PresentationDocument.Create(filepath, PresentationDocumentType.Presentation)) { PresentationPart presentationPart = presentationDocument.AddPresentationPart(); presentationPart.Presentation = new Presentation(); // 先创建幻灯片母版和版式 SlideMasterPart slideMasterPart = presentationPart.AddNewPart<SlideMasterPart>(); InitializeSlideMaster(slideMasterPart); SlideLayoutPart slideLayoutPart = slideMasterPart.AddNewPart<SlideLayoutPart>(); InitializeSlideLayout(slideLayoutPart); // 创建幻灯片并关联版式 SlidePart slidePart = presentationPart.AddNewPart<SlidePart>(slideLayoutPart); CreateSlideContent(slidePart); // 配置幻灯片ID和尺寸 presentationPart.Presentation.SlideIdList = new SlideIdList( new SlideId() { Id = 256U, RelationshipId = presentationPart.GetIdOfPart(slidePart) }); presentationPart.Presentation.SlideSize = new SlideSize() { Cx = 9144000, Cy = 6858000 }; presentationPart.Presentation.Save(); } } private static void InitializeSlideMaster(SlideMasterPart slideMasterPart) { var slideMaster = new SlideMaster( new CommonSlideData( new ShapeTree( new D.NonVisualGroupShapeProperties( new D.NonVisualDrawingProperties() { Id = 1, Name = "" }, new D.NonVisualGroupShapeDrawingProperties(), new D.ApplicationNonVisualDrawingProperties()), new D.GroupShapeProperties(), new D.Shape( new D.NonVisualShapeProperties( new D.NonVisualDrawingProperties() { Id = 2, Name = "Title Placeholder 1" }, new D.NonVisualShapeDrawingProperties(new D.ShapeLocks() { NoGrouping = true }), new D.ApplicationNonVisualDrawingProperties(new D.PlaceholderShape() { Type = D.PlaceholderValues.Title })), new D.ShapeProperties(), new D.TextBody( new D.BodyProperties(), new D.ListStyle(), new D.Paragraph())))), new ColorMapOverride(new D.MasterColorMapping())); slideMasterPart.SlideMaster = slideMaster; slideMasterPart.SlideMaster.Save(); } private static void InitializeSlideLayout(SlideLayoutPart slideLayoutPart) { var slideLayout = new SlideLayout( new CommonSlideData( new ShapeTree( new D.NonVisualGroupShapeProperties( new D.NonVisualDrawingProperties() { Id = 1, Name = "" }, new D.NonVisualGroupShapeDrawingProperties(), new D.ApplicationNonVisualDrawingProperties()), new D.GroupShapeProperties(), new D.Shape( new D.NonVisualShapeProperties( new D.NonVisualDrawingProperties() { Id = 2, Name = "Title Placeholder 1" }, new D.NonVisualShapeDrawingProperties(new D.ShapeLocks() { NoGrouping = true }), new D.ApplicationNonVisualDrawingProperties(new D.PlaceholderShape() { Type = D.PlaceholderValues.Title, MasterId = 2 })), new D.ShapeProperties(), new D.TextBody( new D.BodyProperties(), new D.ListStyle(), new D.Paragraph())))), new SlideLayoutType() { Type = SlideLayoutValues.Title }); slideLayoutPart.SlideLayout = slideLayout; slideLayoutPart.SlideLayout.Save(); } private static void CreateSlideContent(SlidePart slidePart) { slidePart.Slide = new Slide(new CommonSlideData(new ShapeTree())); // 创建表格 D.Table table = new D.Table(); D.TableGrid tableGrid = new D.TableGrid(); tableGrid.Append(new D.GridColumn() { Width = 3124200 }); tableGrid.Append(new D.GridColumn() { Width = 3124200 }); table.Append(tableGrid); // 生成3行2列的单元格 for (int i = 0; i < 3; i++) { D.TableRow row = new D.TableRow() { Height = 370840 }; for (int j = 0; j < 2; j++) { D.TableCell cell = new D.TableCell(); D.TextBody body = new D.TextBody( new D.BodyProperties(), new D.ListStyle(), new D.Paragraph(new D.Run(new D.Text($"Cell {i + 1},{j + 1}")))); cell.Append(body); cell.Append(new D.TableCellProperties()); row.Append(cell); } table.Append(row); } // 创建GraphicFrame并设置正确尺寸 GraphicFrame graphicFrame = new GraphicFrame(); graphicFrame.NonVisualGraphicFrameProperties = new NonVisualGraphicFrameProperties( new NonVisualDrawingProperties() { Id = 1026, Name = "Table" }, new NonVisualGraphicFrameDrawingProperties(), new ApplicationNonVisualDrawingProperties()); // 设置表格位置和尺寸(总宽度为2列宽度之和,总高度为3行高度之和) graphicFrame.Transform = new Transform( new D.Offset() { X = 1000000L, Y = 1000000L }, new D.Extents() { Cx = 6248400L, Cy = 1112520L }); graphicFrame.Graphic = new D.Graphic(new D.GraphicData(table) { Uri = "http://schemas.openxmlformats.org/drawingml/2006/table" }); slidePart.Slide.CommonSlideData.ShapeTree.AppendChild(graphicFrame); slidePart.Slide.Save(); } } }
三、排查错误的实用工具
- Open XML SDK Productivity Tool:微软官方工具,可打开PPTX验证结构,对比正常PPT与生成PPT的XML差异,还能将手动创建的PPT反编译为代码,直接参考正确元素结构。
- 解压PPTX文件:将生成的
.pptx改为.zip解压,查看内部ppt/slides/slide1.xml等文件,与正常PPT的对应XML对比,定位缺失或错误的节点。 - PowerPoint修复日志:修复PPT后,PowerPoint会生成包含错误详情的日志文件,可查看具体被删除的内容,辅助定位问题。
四、其他解决方向
- 手动创建包含目标表格的PPT,用Open XML SDK Productivity Tool反编译代码,对比自身代码找出差异,这是最直接的排查方法。
- 严格遵循Open XML规范,确保每个元素都包含必填属性和子元素,避免省略必要节点(如幻灯片与版式的关联、元素尺寸属性等)。
内容的提问来源于stack exchange,提问作者GoWiser
相关产品推荐
相关产品推荐

