简体   繁体   English

Powerpoint OpenXML空白正在消失

[英]Powerpoint OpenXML whitespace is disappearing

I'm coming across a problem where whitespace is being removed in powerpoint documents as soon as I reference a slide. 我遇到一个问题,一旦我引用幻灯片,就会在powerpoint文档中删除空格。 The following code sample illustrates what I mean- 以下代码示例说明了我的意思 -

//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;
}

To reproduce this issue, create a presentation with a single slide, containing a single text box with the text "[ ]" (no quotes) in it. 要重现此问题,请使用单个幻灯片创建演示文稿,其中包含单个文本框,其中包含文本“[]”(无引号)。 Now, set the font of the space between the square brackets to a different color than the rest of the text. 现在,将方括号之间的空格字体设置为与文本其余部分不同的颜色。 This will result in a Run containing only whitespace characters. 这将导致Run仅包含空格字符。 Once the code above is run against this presentation, the line that references the slide will cause the whitespace in the Run to disappear, ultimately leaving a us with a visually changed presentation than we originally started with, even though we never explicitly changed anything- the text will now be "[]" when opened in the powerpoint application. 一旦上面的代码针对此演示文稿运行,引用幻灯片的行将导致运行中的空白消失,最终使我们的视觉更改演示文稿比我们最初开始时,即使我们从未明确更改任何内容 - 在powerpoint应用程序中打开时,文本现在将为“[]”。

In Word, the xml:space attribute can be set to 'preserve' on text elements to preserve whitespace, but it appears that there is no equivalent for Powerpoint. 在Word中,可以将xml:space属性设置为“保留”文本元素以保留空格,但似乎没有Powerpoint的等效项。

This is a critical problem in situations where whitespace is used as a key component of slide design. 在将空白用作幻灯片设计的关键组件的情况下,这是一个关键问题。 Has anybody figured out a workaround for this issue? 有没有人找到解决这个问题的方法?

Yes, you have found a bug in the SDK. 是的,您在SDK中发现了一个错误。

@Chris, first of all, that code is, per the semantics of the Open XML SDK, modifying the file. @Chris,首先,根据Open XML SDK的语义,该代码是修改文件的。 When you access the contents of the part, and then go out of scope of the using statement, the contents of the part are written back into the package. 当您访问部件的内容,然后超出using语句的范围时,部件的内容将写回到包中。 This is because the presentation was opened for read/write (the second argument of the call to the Open method). 这是因为为读/写(调用Open方法的第二个参数)打开了演示文稿。

The problem is that when the contents of the part are read from the package, the space is being stripped off. 问题是当从包中读取部件的内容时,空间被剥离。

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

If you run the above code on the presentation, you can see that by the time you access that text element, the text of the text element is already incorrect. 如果在演示文稿上运行上述代码,则可以看到,当您访问该文本元素时,文本元素的文本已经不正确。

If you uncomment the line that sets the text, interestingly, the slide does contain the space. 如果取消注释设置文本的行,有趣的是,幻灯片确实包含空格。

This is obviously a bug. 这显然是一个错误。 I have reported it to the program manager at Microsoft who is responsible for the Open XML SDK. 我已向负责Open XML SDK的Microsoft程序经理报告。

As this scenario is important to you, I recommend that you use LINQ to XML for your code. 由于这种情况对您很重要,我建议您使用LINQ to XML代码。 The following code works fine: 以下代码工作正常:

    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);
        } 
    }
}

You could, in theory, write some generic code to dig through the LINQ to XML tree, find all elements that contain only significant white space, then traverse the Open XML SDK element tree, and set the text of those elements. 理论上,您可以编写一些通用代码来挖掘LINQ to XML树,查找仅包含重要空白区域的所有元素,然后遍历Open XML SDK元素树,并设置这些元素的文本。 That is a bit of a mess, but once done, you could use the strongly typed OM of the Open XML SDK 2.0. 这有点乱,但一旦完成,您可以使用Open XML SDK 2.0的强类型OM。 The values of such elements would then be correct. 这些元素的值将是正确的。

One technique that makes it more easy to use LINQ to XML with Open XML is to preatomize XName objects. 使用Open XML更容易使用LINQ to XML的一种技术是对XName对象进行preatomization。 See http://blogs.msdn.com/b/ericwhite/archive/2008/12/15/a-more-robust-approach-for-handling-xname-objects-in-linq-to-xml.aspx http://blogs.msdn.com/b/ericwhite/archive/2008/12/15/a-more-robust-approach-for-handling-xname-objects-in-linq-to-xml.aspx

-Eric -Eric

Open XML SDK 2.5已更正此问题

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM