Powerpoint OpenXML空白正在消失

时间:2011-08-22 20:45:19

标签: c# powerpoint openxml openxml-sdk drawingml

我遇到一个问题,一旦我引用幻灯片,就会在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仅包含空格字符。一旦上面的代码针对此演示文稿运行,引用幻灯片的行将导致运行中的空白消失,最终使我们的视觉更改演示文稿比我们最初开始时,即使我们从未明确更改任何内容 - 在powerpoint应用程序中打开时,文本现在将为“[]”。

在Word中,可以在文本元素上将xml:space属性设置为“保留”以保留空格,但似乎没有Powerpoint的等效项。

在将空白用作幻灯片设计的关键组件的情况下,这是一个关键问题。有没有人找到解决这个问题的方法?

2 个答案:

答案 0 :(得分:6)

是的,您在SDK中发现了一个错误。

@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 = " ";
    } 

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

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

这显然是一个错误。我已经向负责Open XML SDK的Microsoft程序经理报告过。

由于这种情况对您很重要,我建议您使用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对象进行preatomization。见http://blogs.msdn.com/b/ericwhite/archive/2008/12/15/a-more-robust-approach-for-handling-xname-objects-in-linq-to-xml.aspx

-Eric

答案 1 :(得分:2)

Open XML SDK 2.5已纠正此问题