2017-02-28 152 views
1

我有一个使用OpenXml生成文档的C#程序。它使用以下方法用值替换书签:编辑Word书签更改字体

private void FillBookmark(BookmarkStart bookmark, string value) 
{ 
    var text = new Text(value); 
    bookmark.RemoveAllChildren(); 

    IEnumerable<OpenXmlElement> elementsAfter = bookmark.ElementsAfter(); 
    IEnumerable<OpenXmlElement> insideBookmark = elementsAfter.TakeWhile(element => !(element is BookmarkEnd)); 
    foreach (OpenXmlElement element in insideBookmark) 
    { 
     element.RemoveAllChildren(); 
    } 
    OpenXmlElement previousSibling = bookmark.PreviousSibling(); 
    while (previousSibling is BookmarkStart || previousSibling is BookmarkEnd) 
    { 
     previousSibling = previousSibling.PreviousSibling(); 
    } 
    var container = new Run(text); 
    previousSibling.AppendChild(container); 
} 

在这个特定的word文档中,使用的字体是Raleway。有几个书签,执行此方法后,两个书签使用Calibri字体。我试图重写这些书签,以确保它们在Raleway中,但它们继续变为Calibri。

这怎么可能?

回答

2

首先,您的代码会创建没有以前的RunProperties的新元素。 所以,你喜欢的东西下一个片段:

<w:r> 
    <w:t>valuexX</w:t> 
</w:r> 

,而不是它:

<w:r w:rsidRPr="00DE66A4"> 
    <w:rPr> 
     <w:rFonts w:ascii="Algerian" w:hAnsi="Algerian" /> 
      <w:lang w:val="en-US" /> 
    </w:rPr> 
    <w:t>6</w:t>    
</w:r> 

可以复制任何像这样的属性:

private void FillBookmark(BookmarkStart bookmark, string value) 
{ 
    var text = new Text(value); 
    bookmark.RemoveAllChildren(); 

    IEnumerable<OpenXmlElement> elementsAfter = bookmark.ElementsAfter(); 
    IEnumerable<OpenXmlElement> insideBookmark = elementsAfter.TakeWhile(element => !(element is BookmarkEnd)); 
    foreach (OpenXmlElement element in insideBookmark) 
    { 
    element.RemoveAllChildren(); 
    } 
    OpenXmlElement previousSibling = bookmark.PreviousSibling(); 
    while (previousSibling is BookmarkStart || previousSibling is BookmarkEnd) 
    { 
    previousSibling = previousSibling.PreviousSibling(); 
    } 

    //Get previous font. 
    var runProperties = previousSibling.GetFirstChild<ParagraphMarkRunProperties>().GetFirstChild<RunFonts>(); 
    //var runProperties = previousSibling.GetFirstChild<RunProperties>(); - if its simple element. 

    // Clone. 
    var newProperty = (RunFonts)runProperties.Clone(); 

    // Create container with properties. 
    var container = new Run(text) 
    { 
    RunProperties = new RunProperties() { RunFonts = newProperty } 
    }; 

    previousSibling.AppendChild(container); 
} 
1

书签是有点怪。它会自然地认为,一个书签的东西,可以包含FX一个Run,像这样(注意:这不是有效的OpenXML,它只是想说明一个观点):

<w:bookmark> 
    <w:run> 
     <w:text>Some text</w:text> 
    </w:run> 
</w:bookmark> 

但是这是他们没怎么工作。相反,它们使用BookmarkStartBookmarkEnd定义 - 使用属性id来匹配相应的开始和结束元素。

BookmarkStartBookmarkEnd可以涵盖所有类型的东西 - 它们甚至不必在同一段落中(如this example on MSDN所示)。

具有两个看起来相邻的书签的单词文档可以以奇怪的方式嵌套。下面是一个我刚刚扔在一起的Word文档的例子:它有一个带有两个书签的段落:b1b2。请注意,b2bookmarkStart位于书签b1的“内部”。

<w:p xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"> 
    <w:r> 
     <w:t>Some text with a</w:t> 
    </w:r> 
    <w:bookmarkStart w:name="b1" w:id="1" /> 
    <w:r> 
     <w:t>couple</w:t> 
    </w:r> 
    <w:bookmarkStart w:name="b2" w:id="2" /> 
    <w:bookmarkEnd w:id="1" /> 
    <w:r> 
     <w:t xml:space="preserve"> of bookmarks.</w:t> 
    </w:r> 
    <w:bookmarkEnd w:id="2" /> 
</w:p> 

很难猜测在你的例子究竟发生了什么,但我的猜测是,在bookmarkStartbookmarkEnd像你期望不规整。

我觉得使用OpenXML生产力工具来帮助调试这样的东西是有用的。

(此外BookmarkStart没有子女,所以不需要致电bookmark.RemoveAllChildren)。