2015-03-03 160 views
1

我有一個要求,我希望用戶在Word文檔中鍵入一些字符串標記,以便它們可以通過C#應用程序替換爲某些值。所以說,我有一個文件爲每個圖像使用OpenXML SDK簡單替換Word文檔中的標記

enter image description here

現在使用SDK我可以讀取文檔如下:

private void InternalParseTags(WordprocessingDocument aDocumentToManipulate) 
    { 
     StringBuilder sbDocumentText = new StringBuilder(); 
     using (StreamReader sr = new StreamReader(aDocumentToManipulate.MainDocumentPart.GetStream())) 
     { 
      sbDocumentText.Append(sr.ReadToEnd()); 
     } 
然而

,因爲這回來爲原始的XML我不能搜索對於標籤容易作爲底層XML看起來像:

<w:t>&lt;:</w:t></w:r><w:r w:rsidR="002E53FF" w:rsidRPr="000A794A"><w:t>Person.Meta.Age 

(顯然,這並不是我會擁有控制權),而不是我所希望的NAMEL Y:

<w:t>&lt;: Person.Meta.Age 

OR

<w:t><: Person.Meta.Age 

所以我的問題是怎麼做的我居然對字符串本身的工作即

<: Person.Meta.Age :> 

,仍然保留格式等,這樣,當我已經取代帶有值的令牌:

enter image description here

注意:第二個標記值的值加粗

是否需要迭代文檔元素或使用其他方法?所有的指針非常感謝。

+0

類似的問題:http://stackoverflow.com/questions/28697701/openxml-tag-search/28701007#28701007 – 2015-03-03 05:50:03

+0

你可以試試Eric White的Openxml powertools。檢查我的答案在這裏 - http://stackoverflow.com/a/15791797/860243 – Flowerking 2015-03-03 16:34:50

回答

0

這是OpenXML的一個棘手問題。最好的解決辦法我已經遇到在此說明: http://openxmldeveloper.org/blog/b/openxmldeveloper/archive/2011/06/13/open-xml-presentation-generation-using-a-template-presentation.aspx

基本上埃裏克擴展了內容,使得每個角色在自身運行,然後查找要啓動一個「<:」運行順序,然後結束序列。然後他進行替換並重新組合具有相同屬性的所有運行。

該示例適用於PowerPoint,通常內容密集程度要低得多,因此性能可能是Word中的一個因素;我希望有辦法縮小段落的範圍或任何你必須炸燬的東西。

例如,您可以提取段落的文本以查看它是否包含任何佔位符,並僅對這些段落執行展開/替換/濃縮操作。

0

不是直接使用OpenXML來查找/替換令牌,而是使用一些基於OpenXML的第三方模板,這種模板很容易使用,並且很快就會收回成本。

正如Scanny指出的那樣,OpenXML充滿了令人討厭的細節,必須逐個掌握。學習曲線漫長而陡峭。如果你想成爲OpenXML專家,那就去找它並開始攀登。如果你想有一些體面的社交生活的時間,還有其他的選擇:只需選擇一個基於OpenXML的第三方工具包。我評估過Docentric Toolkit。它提供基於模板的方法,您可以在其中準備模板,該模板是Word格式的文件,其中包含在運行時從應用程序合併的數據的佔位符。他們都支持MS Word支持的任何格式,您可以使用條件內容,表格等。

您也可以使用DOM方法創建或更改文檔。最終文件可以是.docx或.pdf。

Docentric是許可產品,但您很快就會通過使用其中一種工具來保存成本。

如果您將在服務器上運行您的應用程序,請勿使用互操作 - 請參閱以下鏈接以獲取更多詳細信息:(http://support2.microsoft.com/kb/257757)。

0

下面是一些代碼,我很快將它們放在一起,以計算在xml中運行的令牌。我不太瞭解這個圖書館,但能夠讓這個工作。由於所有的循環,這也可以使用一些性能增強。

/// <summary> 
    /// Iterates through texts, concatenates them and looks for tokens to replace 
    /// </summary> 
    /// <param name="texts"></param> 
    /// <param name="tokenNameValuePairs"></param> 
    /// <returns>T/F whether a token was replaced. Should loop this call until it returns false.</returns> 
    private bool IterateTextsAndTokenReplace(IEnumerable<Text> texts, IDictionary<string, object> tokenNameValuePairs) 
    { 
     List<Text> tokenRuns = new List<Text>(); 
     string runAggregate = String.Empty; 
     bool replacedAToken = false; 

     foreach (var run in texts) 
     { 
      if (run.Text.Contains(prefixTokenString) || runAggregate.Contains(prefixTokenString)) 
      { 
       runAggregate += run.Text; 
       tokenRuns.Add(run); 

       if (run.Text.Contains(suffixTokenString)) 
       { 
        if (possibleTokenRegex.IsMatch(runAggregate)) 
        { 
         string possibleToken = possibleTokenRegex.Match(runAggregate).Value; 
         string innerToken = possibleToken.Replace(prefixTokenString, String.Empty).Replace(suffixTokenString, String.Empty); 
         if (tokenNameValuePairs.ContainsKey(innerToken)) 
         { 
          //found token!!! 
          string replacementText = runAggregate.Replace(prefixTokenString + innerToken + suffixTokenString, Convert.ToString(tokenNameValuePairs[innerToken])); 
          Text newRun = new Text(replacementText); 
          run.InsertAfterSelf(newRun); 
          foreach (Text runToDelete in tokenRuns) 
          { 
           runToDelete.Remove(); 
          } 
          replacedAToken = true; 
         } 
        } 
        runAggregate = String.Empty; 
        tokenRuns.Clear(); 
       } 
      } 
     } 

     return replacedAToken; 
    } 

string prefixTokenString = "{"; 
    string suffixTokenString = "}"; 

    Regex possibleTokenRegex = new Regex(prefixTokenString + "[a-zA-Z0-9-_]+" + suffixTokenString); 

並調用函數的一些樣品:

using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(memoryStream, true)) 
         { 
          bool replacedAToken = true; 

          //continue to loop document until token's have not bee replaced. This is because some tokens are spread across 'runs' and may need a second iteration of processing to catch them. 
          while (replacedAToken) 
          { 
           //get all the text elements 
           IEnumerable<Text> texts = wordDoc.MainDocumentPart.Document.Body.Descendants<Text>(); 
           replacedAToken = this.IterateTextsAndTokenReplace(texts, tokenNameValuePairs); 
          } 
          wordDoc.MainDocumentPart.Document.Save(); 


          foreach (FooterPart footerPart in wordDoc.MainDocumentPart.FooterParts) 
          { 
           if (footerPart != null) 
           { 
            Footer footer = footerPart.Footer; 

            if (footer != null) 
            { 
             replacedAToken = true; 

             while (replacedAToken) 
             { 
              IEnumerable<Text> footerTexts = footer.Descendants<Text>(); 
              replacedAToken = this.IterateTextsAndTokenReplace(footerTexts, tokenNameValuePairs); 
             } 
             footer.Save(); 
            } 
           } 
          } 

          foreach (HeaderPart headerPart in wordDoc.MainDocumentPart.HeaderParts) 
          { 
           if (headerPart != null) 
           { 
            Header header = headerPart.Header; 

            if (header != null) 
            { 
             replacedAToken = true; 

             while (replacedAToken) 
             { 
              IEnumerable<Text> headerTexts = header.Descendants<Text>(); 
              replacedAToken = this.IterateTextsAndTokenReplace(headerTexts, tokenNameValuePairs); 
             } 
             header.Save(); 
            } 
           } 
          } 
         } 
相關問題