在使用 OpenXML SDK 解析 PPT 文档的文本占位符的时候,需要对 PPT 的格式有一定的了解,尽管整个 OpenXML SDK 包括文档等都很详细。但是有一些细节文档上虽然有写,但是没有强调一下,就被我忽略了
什么是文本占位符,其实这是在 PPT 添加的概念,在 PPT 里面用户可以编辑模版文件,在这里定义某个占位符文本的样式和坐标等
如何制作占位符请看 PPT占位符,居然这么好用! - 知乎
想要解析占位符还需要先学会如何使用占位符才好理解占位符是如何做的
在 OpenXML 里面文本是形状,也就是 DocumentFormat.OpenXml.Presentation.Shape
元素,可以使用下面代码获取页面的形状
在 PPT 里面是使用 p:ph
判断一个形状是占位符,下面是一个占位符的形状
在 slide.xml 里面的元素,通过设置 nvsppr->nvpr->ph 设置这个元素使用占位符,需要继承模版的占位符样式和坐标等值
从 Shape 里面拿到占位符可以使用下面代码
可以在 placeholderShape 里面找到两个主要的属性,一个是 Index 一个是 Type 属性,这两个属性是什么意思?从属性的注释可以看到写的很复杂,大概的做法就是占位符需要去找到模版里面相同的 Index 或相同的 Type 的占位符元素,获取这个元素的样式和坐标等
如果有仔细阅读上面文档就可以知道,如果用户在模版里面定义了占位符,那么仅仅表示页面里面的对应元素的默认样式,而元素本文可以覆盖此样式。也就是元素的最终样式是先尝试获取元素本文的样式,如果元素本文获取不到样式,那么尝试运行占位符元素,如果可以找到占位符元素,那么尝试获取占位符元素的对应样式
那么如何通过 placeholderShape 找到对应的放在模版里面的占位符元素?是否小伙伴还记得 Slide Layout 和 Slide Master 的概念,如果不知道的话,请复习一下 PPT 是如何制作的课程,这两个概念有点绕,需要小伙伴学会制作 PPT 才比较好说
获取 SlideLayout 和 SlideMaster 可以使用下面代码
下面这句话是错的
先从 layout 里面尝试找到有没有对应的占位符元素,如果没有找到再从 master 里面找
无论是 SlideLayout 还是 SlideMaster 都在 CommonSlideData 的 ShapeTree 存放占位符元素。因此寻找占位符方法是从 CommonSlideData 的 ShapeTree 寻找是否有对应的元素,那么什么是对应的元素,如果页面元素设置了 Type 那么要求 ShapeTree 的元素的占位符属性有完全相同的 Type 属性,如果页面元素设置了 Index 那么要求 ShapeTree 的有相同的 ShapeTree 属性。如果页面元素的 Type 是空,那么就不对 ShapeTree 的属性有要求,如果 Index 是空,那么对 ShapeTree 的属性也没有要求
获取的方法如下
下面这句话是不对的
此时的样式获取顺序就是先从元素获取,如果元素获取不到,就从 layoutPlaceholder 获取,如果获取不到从 masterPlaceholder 获取
注释里面的 文本占位符没有type和id的值.pptx 我就不放出来了,有需要的小伙伴发邮件给我
更多的 OpenXML 相关博客,还请自行百度 OpenXML 林德熙
就能找到我的博客了
更正一下
小伙伴可以看到我标记了文章一些说法是不对的。原因是 ECMA 376 文档里面其实只包含了 Placeholder 的定义,而没有包含他的实现方式。整个 ECMA 关于 Placeholder 仅有 274 个引用。因此我上面这里的说法完全只是因为没有实践而依靠不靠谱的博客找到的方法
以下为我通过 Office 2013 和 Office 2016 和 WPS 11.3.0.8742 版本测试拿到的规则
- 占位符元素需要同时在 SlideLayout 和 SlideMaster 里面查找
- 占位符元素的属性优先级是 Slide 里元素本身,然后是 SlideLayout 占位符元素最后是 SlideMaster 占位符元素
- 假定尝试获取元素的平移属性,此时在元素本身没有找到,就需要从 SlideLayout 占位符元素(如果存在)里尝试获取平移属性
- 假定从 SlideLayout 占位符元素获取不到平移属性,那么尝试从 SlideMaster 占位符元素获取平移属性
- 占位符元素如果设置了 Id 的值,那么标准文档里面这个 Id 在 SlideLayout 和 SlideMaster 仅能找到一个占位符元素,不会存在两个
- 对 WPS 非标准文档,可能存在两个相同 Id 元素,此时使用 xml 的第一个元素
- 占位符元素如果设置了 Id 的值,在 SlideMaster 里面没有找到对应的 Id 的占位符元素,那么尝试通过占位符元素的 Type 找到对应的 SlideMaster 的元素
- 如果占位符元素没有设置 Type 的值,那么默认值是 Body 的值
- 如果在 SlideMaster 里面存在多个 Body 元素,那么标准文档里面将会设置每个 Body 元素都有 Id 的值
- 对 WPS 非标准文档,如果定义多个 Body 元素,且没有给每个 Body 元素设置 Id 的值,那么使用 xml 的第一个 Body 元素
- 对 WPS 非标准文档,如果定义多个 Body 元素,其中有一个 Body 元素没有 Id 的值,且使用 Id 查找不到对应占位符元素,那么使用第一个没有 Id 的 Body 元素
大概逻辑如下,下面代码仅使用 SlideMaster 的占位符元素,原因是 SlideLayout 没有遇到此非标准文档,而我也不想去改文档代码测试
上面代码的逻辑不全对,我写在注释里面
更多请看 Office 使用 OpenXML SDK 解析文档博客目录
原文链接: http://blog.lindexi.com/post/dotnet-OpenXML-SDK-%E6%96%87%E6%9C%AC%E5%8D%A0%E4%BD%8D%E7%AC%A6%E8%A7%A3%E6%9E%90
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。
欢迎转载、使用、重新发布,但务必保留文章署名 林德熙 (包含链接: https://blog.lindexi.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我 联系。