【前言】从Word2007刚出来的时候,就发现这个问题了,但是修改的不是很细致,也不深入。
今天优化代码的时候(2013年11月),又研究了下这个问题,在我所查找到的资料中,只有这一个有参考性的帖子。
【问题】wrod通过InsertXML的方法插入Word ML的时候,word2003和2007-2013的版本效果不一样。
对于一个简单的Word ML来说,2007-2013的版本比word2003多一个换行符。
就一个简单的换行符,对一个要在行内插入内容的使用场景来说,真是糟糕透了。
更有外国朋友贴出了总结的规律:
in Word 2003:
- ending without para mark: inserted as is.
- ending with para mark: inserted without para mark.
- ending with double para mark: inserted without last para mark.
- ending with para mark + single space: inserted without para mark and without the space.
- ending with para mark + double space: inserted as is.
- ending with para mark + any printable char(s) other than space: inserted as is.
in Word 2010:
- ending without para mark: inserted with para mark added at the end.
- ending with para mark: inserted as is.
- ending with double para mark: inserted as is.
- ending with para mark + single space: inserted without space.
- ending with para mark + double space: inserted with para mark added at the end.
- ending with para mark + any printable char(s) other than space: inserted with para mark added at the end.
【解决方案】
我以前的解决方案是:插入Word ML,然后判断版本,非2003删除后面的回车。
帖子里的解决方案是:先添加个回车,然后再回车前插入代码,然后删除回车。
因为我遇到的情况更复杂一些,涉及到插入域和修改域(Word Field),所以暂时坚持我原来的方案。
【相关链接】
http://social.msdn.microsoft.com/Forums/en-US/62c41f9e-9037-4805-85e7-be7483367835/rangeinsertxml-bug-in-word-2010?forum=worddev
帖子里的相关链接:
OpenXMLDeveloper.org
http://social.msdn.microsoft.com/forums/en-US/oxmlsdk/threads/
http://social.msdn.microsoft.com/Forums/en-US/os_openXML-ecma/threads
今天优化代码的时候(2013年11月),又研究了下这个问题,在我所查找到的资料中,只有这一个有参考性的帖子。
【问题】wrod通过InsertXML的方法插入Word ML的时候,word2003和2007-2013的版本效果不一样。
对于一个简单的Word ML来说,2007-2013的版本比word2003多一个换行符。
就一个简单的换行符,对一个要在行内插入内容的使用场景来说,真是糟糕透了。
更有外国朋友贴出了总结的规律:
in Word 2003:
- ending without para mark: inserted as is.
- ending with para mark: inserted without para mark.
- ending with double para mark: inserted without last para mark.
- ending with para mark + single space: inserted without para mark and without the space.
- ending with para mark + double space: inserted as is.
- ending with para mark + any printable char(s) other than space: inserted as is.
in Word 2010:
- ending without para mark: inserted with para mark added at the end.
- ending with para mark: inserted as is.
- ending with double para mark: inserted as is.
- ending with para mark + single space: inserted without space.
- ending with para mark + double space: inserted with para mark added at the end.
- ending with para mark + any printable char(s) other than space: inserted with para mark added at the end.
【解决方案】
我以前的解决方案是:插入Word ML,然后判断版本,非2003删除后面的回车。
帖子里的解决方案是:先添加个回车,然后再回车前插入代码,然后删除回车。
因为我遇到的情况更复杂一些,涉及到插入域和修改域(Word Field),所以暂时坚持我原来的方案。
【相关链接】
http://social.msdn.microsoft.com/Forums/en-US/62c41f9e-9037-4805-85e7-be7483367835/rangeinsertxml-bug-in-word-2010?forum=worddev
帖子里的相关链接:
OpenXMLDeveloper.org
http://social.msdn.microsoft.com/forums/en-US/oxmlsdk/threads/
http://social.msdn.microsoft.com/Forums/en-US/os_openXML-ecma/threads
【链接中的代码】(好像是他们项目用的,不通用):
internal static void InsertXML_W14_mimic_W11(this Word.Range range, string text)
{
// W11:
// 1. Last paragraph is inserted with no ending '\r' and target paragraph formatting is retained.
// 2. Any preceding paragraphs are inserted with ending '\r' and source paragraph formatting is used.
// W14:
// All paragraphs are inserted with ending '\r' and source paragraph formatting is used.
// With W14 range stopped including the inserted text after InsertXML is called.
// The range of range is now a point before the inserted text.
//
// We want to keep W11 behaviour.
// range.End would move with rng if range includes end of header/footer or body
Word.Range max_range = range.Duplicate;
max_range.MoveEnd(Word.WdUnits.wdStory, 1); // End is moved as far as it goes (be it in header/footer or body)
if (range.End == max_range.End) range.End--;
Word.Range rng = range.Duplicate;
rng.InsertAfter("\r#"); // Needed to work out end of range after range.InsertXML()
// Get hold of target paragraph format.
// Ie last paragraph in target range or following paragraph if target range ends with '\r'.
Word.ParagraphFormat pf = rng.Paragraphs.Last.Format.Duplicate;
range.InsertXML(text);
// range.End is now equal range.Start (W14 bug, in W11 range.End would be after inserted text).
// rng is now range.Start + inserted text + "\r" + "#".
// Due to trailing \r paragraph format for last inserted paragraph is from source instead of target (as it would be with W11).
// Work out if last paragraph before "#" is not empty (ie not '\r').
// If so we will apply target paragraph markup to "last" paragraph.
bool use_target_p_markup_for_last_para
= rng.Paragraphs.Count > 1
&& (rng.Paragraphs[rng.Paragraphs.Count - 1].Range.Text != "\r" || rng.Paragraphs[rng.Paragraphs.Count - 1].Range.Fields.Count > 0);
// Remove "\r#" and set range as it would be using W11.
rng.Start = rng.End - 2;
rng.Delete();
range.End = rng.End;
// Now we should have same range as if W11 had been used with the simple Range.InsertXML only.
if (use_target_p_markup_for_last_para) range.Paragraphs.Last.Range.ParagraphFormat = pf;
}