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中似乎没有相应的设置。
在使用空白作为幻灯片设计的关键组成部分的情况下,这是一个关键问题。有人想出了解决这个问题的方法吗?
是的,你在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已更正此问题