代码之家  ›  专栏  ›  技术社区  ›  Jason

如何使用OpenXML SDK 2.0更改Word 2007中内容控件的内容?

  •  7
  • Jason  · 技术社区  · 16 年前

    就要为这个问题发疯了。我敢肯定这很简单,我只是错过了它,但我一辈子都找不到如何用C中的OpenXML SDK v2.0更改Word 2007中内容控件的内容。

    我用纯文本内容控件创建了一个Word文档。此控件的标记为“firstname”。在代码中,我希望打开Word文档,找到此内容控件,并在不丢失格式的情况下更改内容。

    我最终找到的解决方案包括找到内容控件,在其后面插入一个运行,然后删除内容控件,如下所示:

    using (WordprocessingDocument wordProcessingDocument = WordprocessingDocument.Open(filePath, true)) {
    MainDocumentPart mainDocumentPart = wordProcessingDocument.MainDocumentPart;
    SdtRun sdtRun = mainDocumentPart.Document.Descendants<SdtRun>()
     .Where(run => run.SdtProperties.GetFirstChild<Tag>().Val == "FirstName").Single();
    
    if (sdtRun != null) {
     sdtRun.Parent.InsertAfter(new Run(new Text("John")), sdtRun);
     sdtRun.Remove();
    }
    

    这确实会更改文本,但我会丢失所有格式。有人知道我怎么做吗?

    5 回复  |  直到 8 年前
        1
  •  7
  •   Jason    16 年前

    我找到了一个更好的方法来完成上面的工作 http://wiki.threewill.com/display/enterprise/SharePoint+and+Open+XML#SharePointandOpenXML-UsingWord2007ContentControls 作为参考。您的结果可能会有所不同,但我认为这将使您有一个良好的开端:

    using (WordprocessingDocument wordprocessingDocument = WordprocessingDocument.Open(filePath, true)) {
        var sdtRuns = mainDocumentPart.Document.Descendants<SdtRun>()
            .Where(run => run.SdtProperties.GetFirstChild<Tag>().Val.Value == contentControlTagValue);
    
        foreach (SdtRun sdtRun in sdtRuns) {
            sdtRun.Descendants<Text>().First().Text = replacementText;
        }
    
        wordprocessingDocument.MainDocumentPart.Document.Save();
    }
    

    我认为以上仅适用于纯文本内容控件。不幸的是,它没有摆脱最终文档中的内容控制。如果我能做到这一点,我会把它贴出来。

    http://msdn.microsoft.com/en-us/library/cc197932.aspx 如果要查找富文本内容控件,也是一个很好的引用。这一个讨论如何向放置在富文本内容控件中的表添加行。

        2
  •  3
  •   Bijay Kusle    16 年前

    第一种删除sdtrun并添加新的方法显然会删除格式,因为您只添加了一个运行,而不是运行样式。若要保留格式,应创建运行元素,如

    new Run( new RunProperties(new RunStyle(){ Val = "MyStyle" }),
                                new Text("Replacement Text"));
    

    你的第二种方法 Decendants<Text> 将仅适用于纯文本内容控件,因为富文本内容控件没有sdtrun元素。富文本内容控件是带有sdtcontent元素的sdtblock。富文本内容控件可以有多个段落、多个运行和多个文本。所以你的代码, sdtRun.Descendants<Text>().First().Text = replacementText ,对于富文本内容控件将是有缺陷的。没有一行代码可以替换富内容控件的整个文本,但保留所有格式。

    我不明白你所说的“它不能摆脱最终文档中的内容控制”是什么意思?我认为您在这里的要求是通过保留内容控件和格式来更改文本(内容)。

        3
  •  3
  •   user246091    16 年前

    解决如何获得所需结果的一个好方法是使用OpenXMLSDK2.0附带的文档反射工具….

    例如,您可以:

    1. 在文档中每个内容控件的“属性”对话框中,选中“编辑内容时删除内容控件”。
    2. 填写并保存为新文档。
    3. 使用反射镜比较原始版本和保存的版本。
    4. 单击“显示/隐藏代码”按钮,它将显示将原始版本转换为填充版本所需的代码。

    它并不完美,但却非常有用。您还可以直接查看任一文档的标记,并查看填充控件所导致的更改。

    这是一种有点脆弱的方法,因为文字处理ML可能很复杂;很容易把它弄乱。对于简单的文本控件,我只使用以下方法:

    private void FillSimpleTextCC(SdtRun simpleTextCC, string replacementText)
        {
            // remove the showing place holder element      
            SdtProperties ccProperties = simpleTextCC.SdtProperties;
            ccProperties.RemoveAllChildren<ShowingPlaceholder>();
    
            // fetch content block Run element            
            SdtContentRun contentRun = simpleTextCC.SdtContentRun;
            var ccRun = contentRun.GetFirstChild<Run>();
    
            // if there was no placeholder text in the content control, then the SdtContentRun
            // block will be empty -> ccRun will be null, so create a new instance
            if (ccRun == null)
            {
                ccRun = new Run(
                    new RunProperties() { RunStyle = null },
                    new Text());
                contentRun.Append(ccRun);
            }
    
            // remove revision identifier & replace text
            ccRun.RsidRunProperties = null;
            ccRun.GetFirstChild<Text>().Text = replacementText;
    
            // set the run style to that stored in the SdtProperties block, if there was
            // one. Otherwise the existing style will be used.            
            var props = ccProperties.GetFirstChild<RunProperties>();
            if (props != null)
            if (props != null)
            {
                RunStyle runStyle = props.RunStyle;
                if (runStyle != null)
                {
                    // set the run style to the same as content block property style.
                    var runProps = ccRun.RunProperties;
                    runProps.RunStyle = new RunStyle() { Val = runStyle.Val };
                    runProps.RunFonts = null;
                }
            }
        }
    

    希望在某种程度上有所帮助。D

        4
  •  1
  •   Jason    16 年前

    我还必须在页脚中查找和替换文本。您可以使用以下代码找到它们:

    using (WordprocessingDocument wordprocessingDocument = WordprocessingDocument.Open(file.PhysicalFile.FullName, true)) {
        foreach (FooterPart footerPart in wordprocessingDocument.MainDocumentPart.FooterParts) {
            var footerPartSdtRuns = footerPart.Footer.Descendants<SdtRun>()
                .Where(run => run.SdtProperties.GetFirstChild<Tag>().Val.Value == contentControlTag);
    
            foreach (SdtRun sdtRun in footerPartSdtRuns) {
               sdtRun.Descendants<Text>().First().Text = replacementTerm;
            }
        }
    
        wordprocessingDocument.MainDocumentPart.Document.Save();
    }
    
        5
  •  1
  •   pungggi    15 年前

    另一个解决方案是

            SdtRun rOld = p.Elements<SdtRun>().First();
    
            string OldNodeXML = rOld.OuterXml;
            string NewNodeXML = OldNodeXML.Replace("SearchString", "ReplacementString");
    
            SdtRun rNew = new SdtRun(NewNodeXML);
    
    
            p.ReplaceChild<SdtRun>(rNew, rOld);