问题
I have a C# program that generates documents using OpenXml. It replaces bookmarks with values using the following method :
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);
}
In this particular word document, the font used is Raleway. There are several bookmarks and after the execution of this method, two bookmarks are using the Calibri font. I tried to rewrite theses bookmarks to be sure they are in Raleway but they continue to change to Calibri.
How is this possible ?
回答1:
First of all your code creates new element without previous RunProperties. So, you get something like next snippet:
<w:r>
<w:t>valuexX</w:t>
</w:r>
instead of it:
<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>
You can copy any properties like this:
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);
}
回答2:
Bookmarks are a bit weird. It would be natural to think that a bookmark is something that can contain fx a Run
, like so (NB: This is not valid OpenXML, it's just to illustrate a point):
<w:bookmark>
<w:run>
<w:text>Some text</w:text>
</w:run>
</w:bookmark>
But that's not how they work. Instead they are defined using BookmarkStart
and BookmarkEnd
- using the attribute id
to match corresponding start- and end-elements.
The BookmarkStart
and BookmarkEnd
can span all kind of stuff - they don't even have to be in the same paragraph (as illustrated by this example on MSDN).
A word-document with two bookmarks that appear to be adjacent can be nested in a weird way. Here is an example from a Word-document I just threw together: it has a paragraph with two bookmarks: b1
and b2
. Notice that the bookmarkStart
for b2
is 'inside' the bookmark 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>
It's hard to guess exactly what happens in your example, but my guess would be that the bookmarkStart
and bookmarkEnd
is not structured like you expect.
I find it usefull to use OpenXML Productivity Tool to help when debugging stuff like this.
(Also the BookmarkStart
doesn't have children, so the call to bookmark.RemoveAllChildren
is not needed).
来源:https://stackoverflow.com/questions/42515339/edit-word-bookmark-changes-the-font