2011-08-22 42 views
4

我遇到了一個問題,只要我參考一張幻燈片,就會在PowerPoint文檔中刪除空格。下面的代碼示例說明了什麼我均值Powerpoint OpenXML空白正在消失

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

有一定是別的事情上...上面的代碼甚至不會在文件上執行任何IO。即使它做了,它應該做的就是創建對第一張幻燈片的引用....我建議通過手動從pptx中提取原始XML或使用PackageExplorer(http://packageexplorer.codeplex的.com /)。 –

+0

我同意你100%,這是沒有意義的,我必須做錯事,我只是無法弄清楚什麼。我一直在查看原始XML,並且在運行上面發佈的代碼後,文本標記實際上從''變爲''。我甚至嘗試在文件中的各個位置(run,paragraph,text,slide,presentation)中添加xml:space =「preserve」屬性無濟於事。 – ptrc

+0

我將在今晚深入研究PresentationML項目......它不應該花我很長時間來重現這種情況。如果我能弄清楚什麼,我會告訴你。 –

回答

6

是的,您發現SDK中存在一個錯誤。

@Chris首先根據Open XML SDK的語義修改文件。當您訪問零件的內容,然後超出使用說明的範圍時,零件的內容將被寫回到包裝中。這是因爲演示文稿已被打開以進行讀取/寫入(調用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到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

+1

謝謝,埃裏克,高興地知道我不只是在做可怕的錯誤。 如果有其他人在這種情況下可能會感興趣,我結束了與LINQ to XML only選項。儘管Open XML SDK提供的強類型對象模型非常好,但我並不準備嘗試並預測並隨後撤銷此錯誤可能對'甲板設計者'創建的演示文稿所產生的所有效果,這些效果遠比我更精通。到目前爲止,LINQ to XML工作良好,實際上移植Open XML SDK代碼非常簡單。 – ptrc

+1

我很高興看到我沒有瘋狂,因爲我用了一個小時來找出爲什麼所有的空白都消失了。我無法浪費時間使用Linq到Xml來更改我的代碼,但我將它保存在我的未來項目中。我希望這個bug能夠在下一個版本的SDK –

2

的Open XML SDK 2.5有這個問題糾正

+0

Woop中得到解決!很高興這個問題得到解決,因爲這使得Open XML SDK 2.5成爲一項可行且現在已經成熟和可行的解決方案,以應對極其艱鉅的任務。所有產品仍然適用於ClosedXML。很高興看到更多這樣的。 – Coops