首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在C#中使用OpenXml SDK中的MergeField FieldCodes时,为什么字段代码会消失或碎片化?

在C#中使用OpenXml SDK中的MergeField FieldCodes时,为什么字段代码会消失或碎片化?
EN

Stack Overflow用户
提问于 2015-06-26 01:30:00
回答 3查看 2.6K关注 0票数 5

我已经成功地使用C# OpenXml SDK (来自NuGet的非官方MicrosoftPackage2.5)一段时间了,但最近注意到以下代码行返回不同的结果,这取决于保存文件时Microsoft Word的状态:

代码语言:javascript
复制
var fields = document.Descendants<FieldCode>();

据我所知,在创建文档时(使用Windows8.1上的Word 2013 ),如果您使用Insert->QuickParts->Field并从字段名称左侧窗格中选择MergeField,然后在字段属性中提供一个字段名称并单击OK,那么字段代码就会像我所期望的那样正确地保存在文档中。

然后,当使用前面提到的代码行时,我将收到1 field的field code count。如果我随后编辑了这个文档(甚至保留了这个字段),那么随后的保存可能意味着我的查询中不再返回这个字段代码。

同样令人好奇的另一个例子是,当我看到FieldCode节点被拆分到多个项目时。所以,与其看,不如说:

代码语言:javascript
复制
" MERGEFIELD  Author  \\* MERGEFORMAT "

作为节点名,我将看到:

代码语言:javascript
复制
" MERGEFIELD  Aut"
"hor  \\* MERGEFORMAT"

拆分为两个FieldCode节点值。我不知道为什么会这样,但这肯定会使我匹配节点的能力变得更加令人兴奋。这是预期的行为吗?一个已知的bug?我真的不想打开原始的xml并编辑这个文档来工作,直到我理解发生了什么。非常感谢大家。

EN

回答 3

Stack Overflow用户

发布于 2017-06-13 00:51:55

我自己遇到了这个问题,并在OpenXML中找到了一个解决方案:一个名为MarkupSimplifier的实用程序类,它是PowerTools for Open XML项目的一部分。使用这个类解决了你所描述的我遇到的所有问题。

The full article is located here.

以下是一些相关的练习:

执行的最有用的简化可能是合并具有相同格式的相邻运行。

它接着说:

Open XML应用程序,包括Word,可以根据需要任意拆分运行。例如,如果您向文档添加注释,则运行将在注释的开始和结束位置拆分。在MarkupSimplifier删除注释后,它可以合并运行,从而使标记更简单。

正在使用的实用程序类的一个示例是:

代码语言:javascript
复制
SimplifyMarkupSettings settings = new SimplifyMarkupSettings
{
    RemoveComments = true,
    RemoveContentControls = true,
    RemoveEndAndFootNotes = true,
    RemoveFieldCodes = false,
    RemoveLastRenderedPageBreak = true,
    RemovePermissions = true,
    RemoveProof = true,
    RemoveRsidInfo = true,
    RemoveSmartTags = true,
    RemoveSoftHyphens = true,
    ReplaceTabsWithSpaces = true,
};
MarkupSimplifier.SimplifyMarkup(wordDoc, settings);

我在使用VS2015 .Net框架4.5.2的Word 2010文档中多次使用它,它让我的生活变得非常非常轻松。

更新

我重新查看了这段代码,发现它在MERGEFIELDS上运行时会清除,但如果字段引用了合并字段,则不会清除。

代码语言:javascript
复制
{if {MERGEFIELD When39} = "Y???" "Y" "N" }

我不知道为什么会这样,而且对底层XML的检查也没有提供任何提示。

票数 4
EN

Stack Overflow用户

发布于 2015-06-26 01:39:20

Word经常会将文本串拆分成多个文本串,这是我从未理解过的。在进行搜索、比较、整理等操作时,我们使用将多个游程组合成一个文本游程的方法对正文进行预处理。

代码语言:javascript
复制
    /// <summary>
    /// Combines the identical runs.
    /// </summary>
    /// <param name="body">The body.</param>
    public static void CombineIdenticalRuns(W.Body body)
    {

        List<W.Run> runsToRemove = new List<W.Run>();

        foreach (W.Paragraph para in body.Descendants<W.Paragraph>())
        {
            List<W.Run> runs = para.Elements<W.Run>().ToList();
            for (int i = runs.Count - 2; i >= 0; i--)
            {
                W.Text text1 = runs[i].GetFirstChild<W.Text>();
                W.Text text2 = runs[i + 1].GetFirstChild<W.Text>();
                if (text1 != null && text2 != null)
                {
                    string rPr1 = "";
                    string rPr2 = "";
                    if (runs[i].RunProperties != null) rPr1 = runs[i].RunProperties.OuterXml;
                    if (runs[i + 1].RunProperties != null) rPr2 = runs[i + 1].RunProperties.OuterXml;
                    if (rPr1 == rPr2)
                    {
                        text1.Text += text2.Text;
                        runsToRemove.Add(runs[i + 1]);
                    }
                }
            }
        }
        foreach (W.Run run in runsToRemove)
        {
            run.Remove();
        }
    }
票数 2
EN

Stack Overflow用户

发布于 2020-03-09 23:55:25

我试图用Powertools简化文档,但结果是一个损坏的word文件。我将此例程设置为只简化具有特定名称的字段代码,它适用于文档的所有部分(主要文档部分、页眉和页脚):

代码语言:javascript
复制
internal static void SimplifyFieldCodes(WordprocessingDocument document)
    {
        var masks = new string[] { Constants.VAR_MASK, Constants.INP_MASK, Constants.TBL_MASK, Constants.IMG_MASK, Constants.GRF_MASK };
        SimplifyFieldCodesInElement(document.MainDocumentPart.RootElement, masks);

        foreach (var headerPart in document.MainDocumentPart.HeaderParts)
        {
            SimplifyFieldCodesInElement(headerPart.Header, masks);
        }

        foreach (var footerPart in document.MainDocumentPart.FooterParts)
        {
            SimplifyFieldCodesInElement(footerPart.Footer, masks);
        }

    }

    internal static void SimplifyFieldCodesInElement(OpenXmlElement element, string[] regexpMasks)
    {
        foreach (var run in element.Descendants<Run>()
            .Select(item => (Run)item)
            .ToList())
        {
            var fieldChar = run.Descendants<FieldChar>().FirstOrDefault();
            if (fieldChar != null && fieldChar.FieldCharType == FieldCharValues.Begin)
            {
                string fieldContent = "";
                List<Run> runsInFieldCode = new List<Run>();

                var currentRun = run.NextSibling();
                while ((currentRun is Run) && currentRun.Descendants<FieldCode>().FirstOrDefault() != null)
                {
                    var currentRunFieldCode = currentRun.Descendants<FieldCode>().FirstOrDefault();
                    fieldContent += currentRunFieldCode.InnerText;
                    runsInFieldCode.Add((Run)currentRun);
                    currentRun = currentRun.NextSibling();
                }

                // If there is more than one Run for the FieldCode, and is one we must change, set the complete text in the first Run and remove the rest
                if (runsInFieldCode.Count > 1)
                {
                    // Check fielcode to know it's one that we must simplify (for not to change TOC, PAGEREF, etc.)
                    bool applyTransform = false;
                    foreach (string regexpMask in regexpMasks)
                    {
                        Regex regex = new Regex(regexpMask);
                        Match match = regex.Match(fieldContent);
                        if (match.Success)
                        {
                            applyTransform = true;
                            break;
                        }
                    }

                    if (applyTransform)
                    {
                        var currentRunFieldCode = runsInFieldCode[0].Descendants<FieldCode>().FirstOrDefault();
                        currentRunFieldCode.Text = fieldContent;
                        runsInFieldCode.RemoveAt(0);

                        foreach (Run runToRemove in runsInFieldCode)
                        {
                            runToRemove.Remove();
                        }
                    }
                }
            }
        }
    }

希望这能有所帮助!

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31056953

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档