我遇到一个问题,一旦我引用幻灯片,就会在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的等效项。
在将空白用作幻灯片设计的关键组件的情况下,这是一个关键问题。有没有人找到解决这个问题的方法?
答案 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已纠正此问题