簡體   English   中英

使用OpenXML SDK輕松替換Word文檔中的令牌

[英]Simplistic replacement of tokens in a Word Document using OpenXML SDK

我有一個要求,我希望用戶在Word文檔中鍵入一些字符串標記,以便可以通過帶有某些值的C#應用​​程序替換它們。 所以說我有一個根據圖片的文件

在此處輸入圖片說明

現在,使用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

(而且顯然不是我可以控制的),而不是我希望的:

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

要么

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

所以我的問題是我該如何實際處理字符串本身

<: Person.Meta.Age :>

並仍然保留格式等。因此,當我用值替換令牌時,我有:

在此處輸入圖片說明

注意:第二個令牌值的值以粗體顯示

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

OpenXML有點棘手的問題。 這里介紹了我遇到的最佳解決方案: http : //openxmldeveloper.org/blog/b/openxmldeveloper/archive/2011/06/13/open-xml-presentation-generation-using-a-template-presentation。 ASPX

基本上,埃里克(Eric)會擴展內容,以使每個字符本身都在運行中,然后查找以'<:'序列開始,然后是結束序列的運行。 然后,他進行替換並重新組合具有相同屬性的所有運行。

該示例是針對PowerPoint的,它通常不需要大量的內容,因此性能可能是Word中的一個因素。 我希望有一些方法可以縮小段落的范圍或您必須炸掉的內容。

例如,您可以提取該段落的文本以查看其是否包含任何占位符,並且僅對這些段落進行擴展/替換/壓縮操作。

可以使用OpenXML而不是直接使用令牌來查找/替換令牌,而可以使用一些基於第三方的基於OpenXML的模板,該模板使用起來很簡單,並且很快就會得到回報。

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

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

Docentric是獲得許可的產品,但是您很快就會在使用這些工具之一節省下來的時間之前就補償了費用。

如果要在服務器上運行應用程序,請不要使用interop-有關更多詳細信息,請參見此鏈接:( http://support2.microsoft.com/kb/257757 )。

這是一些代碼,我很快就將它們拍打在一起,以說明在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();
                                    }
                                }
                            }
                        }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM