Powerpoint OpenXML空白正在消失

本文关键字:消失 空白 OpenXML Powerpoint | 更新日期: 2023-09-27 18:06:17

我遇到了一个问题,当我引用幻灯片时,powerpoint文档中的空白被删除了。下面的代码示例说明了我的意思—

//Open the document.
using(PresentationDocument presentationDocument = PresentationDocument.Open(pptxFileName, true))
{
 //Just making this reference modifies the whitespace in the slide.
 Slide slide = presentationDocument.PresentationPart.SlideParts.First().Slide;
}

若要重现此问题,请创建包含单个幻灯片的演示文稿,其中包含一个文本框,其中包含文本"[]"(不带引号)。现在,将方括号之间的空格的字体设置为与文本其余部分不同的颜色。这将导致只包含空白字符的Run。一旦上面的代码在这个演示中运行,引用幻灯片的那一行将导致run中的空白消失,最终留下一个比我们最初开始时视觉上改变的演示文稿,即使我们从未显式地改变任何东西-现在在powerpoint应用程序中打开文本将是"[]"。

在Word中,xml:space属性可以设置为'preserve'来保留文本元素中的空白,但是在Powerpoint中似乎没有相应的设置。

在使用空白作为幻灯片设计的关键组成部分的情况下,这是一个关键问题。有人想出了解决这个问题的方法吗?

Powerpoint OpenXML空白正在消失

是的,你在SDK中发现了一个bug。

@Chris,首先,根据Open XML SDK的语义,这些代码是在修改文件。当您访问部件的内容,然后超出using语句的作用域时,部件的内容将被写回包中。这是因为演示文稿被打开以供读/写(调用Open方法的第二个参数)。

问题是,当从包中读取部件的内容时,空间被剥离。

        //Open the document. 
    using (PresentationDocument presentationDocument = PresentationDocument.Open("test.pptx", true))
    {
        //Just making this reference modifies the whitespace in the slide. 
        Slide slide = presentationDocument.PresentationPart.SlideParts.First().Slide;
        var sh = slide.CommonSlideData.ShapeTree.Elements<DocumentFormat.OpenXml.Presentation.Shape>().First();
        Run r = sh.TextBody.Elements<Paragraph>().First().Elements<Run>().Skip(1).FirstOrDefault();
        Console.WriteLine(">{0}<", r.Text.Text);
        //r.Text.Text = " ";
    } 

如果您在演示文稿上运行上述代码,您可以看到,当您访问该文本元素时,文本元素的文本已经不正确了。

如果取消设置文本的行注释,有趣的是,幻灯片中确实包含空格。

这显然是一个bug。我已经向微软负责Open XML SDK的项目经理报告了。

由于这个场景对您很重要,我建议您在代码中使用LINQ to XML。下面的代码可以正常工作:

    using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Presentation;
using DocumentFormat.OpenXml.Drawing;
public static class PtOpenXmlExtensions
{
    public static XDocument GetXDocument(this OpenXmlPart part)
    {
        XDocument partXDocument = part.Annotation<XDocument>();
        if (partXDocument != null)
            return partXDocument;
        using (Stream partStream = part.GetStream())
        using (XmlReader partXmlReader = XmlReader.Create(partStream))
            partXDocument = XDocument.Load(partXmlReader);
        part.AddAnnotation(partXDocument);
        return partXDocument;
    }
    public static void PutXDocument(this OpenXmlPart part)
    {
        XDocument partXDocument = part.GetXDocument();
        if (partXDocument != null)
        {
            using (Stream partStream = part.GetStream(FileMode.Create, FileAccess.Write))
            using (XmlWriter partXmlWriter = XmlWriter.Create(partStream))
                partXDocument.Save(partXmlWriter);
        }
    }
}
class Program
{
    static void Main(string[] args)
    {
        using (PresentationDocument presentationDocument = PresentationDocument.Open("test.pptx", true))
        {
            XDocument slideXDoc = presentationDocument.PresentationPart.SlideParts.First().GetXDocument();
            XNamespace p = "http://schemas.openxmlformats.org/presentationml/2006/main";
            XNamespace a = "http://schemas.openxmlformats.org/drawingml/2006/main";
            XElement sh = slideXDoc.Root.Element(p + "cSld").Element(p + "spTree").Elements(p + "sp").First();
            XElement r = sh.Element(p + "txBody").Elements(a + "p").Elements(a + "r").Skip(1).FirstOrDefault();
            Console.WriteLine(">{0}<", r.Element(a + "t").Value);
        } 
    }
}

理论上,您可以编写一些泛型代码来挖掘LINQ to XML树,找到只包含有效空白的所有元素,然后遍历Open XML SDK元素树,并设置这些元素的文本。这有点混乱,但是一旦完成,您就可以使用Open XML SDK 2.0的强类型OM。这样,这些元素的值就应该是正确的。

使在Open XML中更容易使用LINQ to XML的一种技术是预原子化XName对象。见http://blogs.msdn.com/b/ericwhite/archive/2008/12/15/a-more-robust-approach-for-handling-xname-objects-in-linq-to-xml.aspx

eric

Open XML SDK 2.5已更正此问题