dotnet OpenXML SDK 文本占位符解析

在使用 OpenXML SDK 解析 PPT 文档的文本占位符的时候,须要对 PPT 的格式有必定的了解,尽管整个 OpenXML SDK 包括文档等都很详细。可是有一些细节文档上虽然有写,可是没有强调一下,就被我忽略了php

什么是文本占位符,其实这是在 PPT 添加的概念,在 PPT 里面用户能够编辑模版文件,在这里定义某个占位符文本的样式和坐标等app

如何制做占位符请看 PPT占位符,竟然这么好用! - 知乎ide

想要解析占位符还须要先学会如何使用占位符才好理解占位符是如何作的测试

在 OpenXML 里面文本是形状,也就是 DocumentFormat.OpenXml.Presentation.Shape 元素,可使用下面代码获取页面的形状.net

using (var presentationDocument = DocumentFormat.OpenXml.Packaging.PresentationDocument.Open("测试.pptx", false))
            {
                var presentationPart = presentationDocument.PresentationPart;
                var presentation = presentationPart.Presentation;

                // 先获取页面
                var slideIdList = presentation.SlideIdList;

                foreach (var slideId in slideIdList.ChildElements.OfType<SlideId>())
                {
                    // 获取页面内容
                    SlidePart slidePart = (SlidePart) presentationPart.GetPartById(slideId.RelationshipId);

                    var slide = slidePart.Slide;

                    foreach (var shape in
                        slidePart.Slide
                            .Descendants<DocumentFormat.OpenXml.Presentation.Shape>())
                    {
                       
                    }
                }
            }

在 PPT 里面是使用 p:ph 判断一个形状是占位符,下面是一个占位符的形状code

<p:sp>
    <p:nvsppr>
        <p:cnvpr id="2" name="标题 1">
        </p:cnvpr>
        <p:cnvsppr>
            <a:splocks nogrp="1">
            </a:splocks>
        </p:cnvsppr>
        <p:nvpr>
            <p:ph type="ctrTitle">
            </p:ph>
        </p:nvpr>
    </p:nvsppr>
    <p:sppr>
    </p:sppr>
    <p:txbody>
        <a:bodypr>
        </a:bodypr>
        <a:p>
            <a:r>
                <a:rpr altlang="en-US" lang="zh-CN">
                </a:rpr>
                <a:t>
                    PPT 解析
                </a:t>
            </a:r>
            <a:endpararpr altlang="en-US" lang="zh-CN">
            </a:endpararpr>
        </a:p>
    </p:txbody>
</p:sp>

在 slide.xml 里面的元素,经过设置 nvsppr->nvpr->ph 设置这个元素使用占位符,须要继承模版的占位符样式和坐标等值orm

从 Shape 里面拿到占位符可使用下面代码xml

// <p:nvSpPr>占位符的样式
NonVisualShapeProperties nonVisualShapeProperties = shape?.NonVisualShapeProperties;
// cNvSpPr
var nonVisualShapeDrawingProperties = nonVisualShapeProperties?.NonVisualShapeDrawingProperties;
// nvpr
var applicationNonVisualDrawingProperties = nonVisualShapeProperties?.ApplicationNonVisualDrawingProperties;

var placeholderShape = applicationNonVisualDrawingProperties?.PlaceholderShape;

能够在 placeholderShape 里面找到两个主要的属性,一个是 Index 一个是 Type 属性,这两个属性是什么意思?从属性的注释能够看到写的很复杂,大概的作法就是占位符须要去找到模版里面相同的 Index 或相同的 Type 的占位符元素,获取这个元素的样式和坐标等blog

若是有仔细阅读上面文档就能够知道,若是用户在模版里面定义了占位符,那么仅仅表示页面里面的对应元素的默认样式,而元素本文能够覆盖此样式。也就是元素的最终样式是先尝试获取元素本文的样式,若是元素本文获取不到样式,那么尝试运行占位符元素,若是能够找到占位符元素,那么尝试获取占位符元素的对应样式继承

那么如何经过 placeholderShape 找到对应的放在模版里面的占位符元素?是否小伙伴还记得 Slide Layout 和 Slide Master 的概念,若是不知道的话,请复习一下 PPT 是如何制做的课程,这两个概念有点绕,须要小伙伴学会制做 PPT 才比较好说

获取 SlideLayout 和 SlideMaster 可使用下面代码

var layout = slidePart.SlideLayoutPart.SlideLayout;
var master = slidePart.SlideLayoutPart.SlideMasterPart.SlideMaster;

先从 layout 里面尝试找到有没有对应的占位符元素,若是没有找到再从 master 里面找

寻找方法是从 CommonSlideData 的 ShapeTree 寻找是否有对应的元素,那么什么是对应的元素,若是页面元素设置了 Type 那么要求 ShapeTree 的元素的占位符属性有彻底相同的 Type 属性,若是页面元素设置了 Index 那么要求 ShapeTree 的有相同的 ShapeTree 属性。若是页面元素的 Type 是空,那么就不对 ShapeTree 的属性有要求,若是 Index 是空,那么对 ShapeTree 的属性也没有要求

private static Shape GetPlaceholderShape(PlaceholderShape placeholder, ShapeTree tree)
        {
            return tree.Elements<Shape>().FirstOrDefault(shape =>
            {
                var placeholderShape = shape?.NonVisualShapeProperties?.ApplicationNonVisualDrawingProperties
                    ?.PlaceholderShape;
                return placeholderShape != null && Equals(placeholder, placeholderShape);
            });
        }

        /// <summary>
        /// 比较<see cref="PlaceholderShape"/>的type和id是否相同
        /// <para></para>
        /// 若是 1 的 Type 或 Index 是空,那么跳过这个属性的判断
        /// <para></para>
        /// 若是这个属性不是空,那么必定要求 2 存在这个属性
        /// </summary>
        /// 这个规则经过 文本占位符没有type和id的值,获取第一个占位符做为坐标 和 WPS 对比测试拿到
        /// 测试课件:文本占位符没有type和id的值.pptx
        /// <param name="placeholder1"></param>
        /// <param name="placeholder2"></param>
        /// <returns></returns>
        private static bool Equals(PlaceholderShape placeholder1, PlaceholderShape placeholder2)
        {
            // 若是 placeholder1.Type 存在值,要求 2 必定存在值
            if (placeholder1.Type != null && 
                placeholder1.Type.Value != placeholder2.Type?.Value)
            {
                return false;
            }

            if (placeholder1.Index != null && placeholder1.Index.Value !=
                placeholder2.Index?.Value)
            {
                return false;
            }

            return true;
        }

获取的方法以下

layoutPlaceholder = GetPlaceholderShape(placeholder, layout?.CommonSlideData?.ShapeTree);
  masterPlaceholder = GetPlaceholderShape(placeholder, master?.CommonSlideData?.ShapeTree);

此时的样式获取顺序就是先从元素获取,若是元素获取不到,就从 layoutPlaceholder 获取,若是获取不到从 masterPlaceholder 获取

注释里面的 文本占位符没有type和id的值.pptx 我就不放出来了,有须要的小伙伴发邮件给我

更多的 OpenXML 相关博客,还请自行百度 OpenXML 林德熙 就能找到个人博客了

我搭建了本身的博客 https://blog.lindexi.com/ 欢迎你们访问,里面有不少新的博客。只有在我看到博客写成熟以后才会放在csdn或博客园,可是一旦发布了就再也不更新

若是在博客看到有任何不懂的,欢迎交流,我搭建了 dotnet 职业技术学院 欢迎你们加入

若有不方便在博客评论的问题,能够加我 QQ 2844808902 交流

知识共享许可协议
本做品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、从新发布,但务必保留文章署名林德熙(包含连接:http://blog.csdn.net/lindexi_gd ),不得用于商业目的,基于本文修改后的做品务必以相同的许可发布。若有任何疑问,请与我联系

相关文章
相关标签/搜索