【问题标题】:How to keep style on open xml documents如何在打开的 xml 文档上保持样式
【发布时间】:2015-05-19 12:19:44
【问题描述】:

我使用 open XML(Microsoft Word - .docx) 作为文件模板来自动生成其他文档。在模板文档中,我定义了内容控件,并编写了代码来替换这些内容控件中的内容。

内容被替换并生成了文档,但我在努力保持风格。在 Word 中,当检查内容控件的属性时,我选中了“使用样式将文本格式化为空控件:样式”复选框,还选中了“编辑内容时删除内容控件”。当文档由代码生成时,这似乎没有任何影响。

这是我用于替换内容控件中的数据的代码(这里的社区成员很乐意提供帮助)。为了保持格式,我应该怎么做?格式是简单的文本格式,如大小和字体。请指教:

    private static void ReplaceTags(MainDocumentPart mainPart, string tagName, string tagValue)
    {
        //grab all the tag fields
        var tagFields = mainPart.Document.Body.Descendants<SdtBlock>().Where
            (r => r.SdtProperties.GetFirstChild<Tag>().Val == tagName);

        foreach (var field in tagFields)
        {
            //remove all paragraphs from the content block
            field.SdtContentBlock.RemoveAllChildren<DocumentFormat.OpenXml.Wordprocessing.Paragraph>();
            //create a new paragraph containing a run and a text element
            var newParagraph = new DocumentFormat.OpenXml.Wordprocessing.Paragraph();
            var newRun = new DocumentFormat.OpenXml.Wordprocessing.Run();
            var newText = new DocumentFormat.OpenXml.Wordprocessing.Text(tagValue);
            newRun.Append(newText);
            newParagraph.Append(newRun);
            //add the new paragraph to the content block
            field.SdtContentBlock.Append(newParagraph);
        }
    }

【问题讨论】:

    标签: c# ms-word openxml openxml-sdk


    【解决方案1】:

    当您为内容控件分配样式时,一个新的RunProperties 元素将添加到SdtProperties 下。例如,如果我指定一个名为 Style1 的新样式,我可以看到生成了以下 XML:

    <w:sdt>
        <w:sdtPr>
            <w:rPr>
                <w:rStyle w:val="Style1" />
            </w:rPr>
        <w:alias w:val="LastName" />
        <w:tag w:val="LastName" />
        ....
    

    您需要获取此值并将其分配给您正在创建的新 Paragraph,将 Paragraph 添加到与 SdtBlock 相同的级别,然后删除 SdtBlock选择“编辑内容时删除内容控件”选项。 RunProperties&lt;w:rPr&gt; 元素。以下应该做你所追求的。

    private static void ReplaceTags(MainDocumentPart mainPart, string tagName, string tagValue)
    {
        //grab all the tag fields
        IEnumerable<SdtBlock> tagFields = mainPart.Document.Body.Descendants<SdtBlock>().Where
            (r => r.SdtProperties.GetFirstChild<Tag>().Val == tagName);
    
        foreach (var field in tagFields)
        {
            //grab the RunProperties from the SdtBlcok
            RunProperties runProp = field.SdtProperties.GetFirstChild<RunProperties>();
    
            //create a new paragraph containing a run and a text element
            Paragraph newParagraph = new Paragraph();
            Run newRun = new Run();
            if (runProp != null)
            {
                //assign the RunProperties to our new run
                newRun.Append(runProp.CloneNode(true));
            }
            Text newText = new Text(tagValue);
            newRun.Append(newText);
            newParagraph.Append(newRun);
            //insert the new paragraph before the field we're going to remove
            field.Parent.InsertBefore(newParagraph, field);
    
            //remove the SdtBlock to mimic the Remove content control when contents are edited option
            field.Remove();
        }
    }
    

    【讨论】:

    • 再次嗨,感谢一百万您提供的出色编码帮助和非常好的解释。该代码在保持风格方面起作用,但在此过程中我遇到了一个新问题:)。运行此代码时,它会保持样式不变,但在内容控件中输入新文本后,文本会放置在页面底部。我把它放在上面。任何想法如何使它保持它的位置`?再次感谢
    • 谢谢@Ilyas。 field.Parent.AppendChild(newParagraph); 行在文档末尾添加了新段落。我已经编辑了使用field.Parent.InsertBefore(newParagraph, field); 的答案,它将在内容控件之前添加它(然后被删除,所以基本上它与内容控件在同一点)
    • 优秀的代码!您甚至可以在同一段落中创建多行时使用它来保持相同的格式,方法是在循环中调用以下命令: RunProperties runProps = newRun.AppendChild(new RunProperties());换行符 = new Break(); runProps.Append(linebreak);
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-07
    • 2019-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多