这是Creating Word file from ObservableCollection with C#的后续问题
我有一个带有Body
的.docx文件,其SectionProperties
有2列。我有一个外来词典和翻译。在每一行我需要[Word] = [翻译],每当一个新的字母开始时,它应该在它自己的行中,在该字母之前和之后有2或3个换行符,如下所示:
A
A-word =翻译
A-word =翻译B
B-word =翻译
B字 =翻译
......
我在for循环中对此进行了结构化,因此在每次迭代中我都会创建一个新的段落,其中可能有Run
字母(如果新的开头),Run
为单词和Run
用于翻译。因此,带有第一个字母的Run
与单词和翻译Paragraph
位于同一Run
,并且在Break
之前和之后附加2或3个Text
个对象}。
在这样做时,第二列有时可以从1或2个空行开始。或者下一页的第一列可以以空行开头
这是我想要避免的。
所以我的问题是,我可以以某种方式检查是否到达了页面的末尾,或者文本是否在列的顶部,所以我不必添加Break
?或者,我可以格式化Column
本身,以便它不以空行开头吗?
我已尝试将字母Run
放在单独的,可选的Paragraph
中,但我再次发现自己必须输入换行符,问题仍然存在。
答案 0 :(得分:0)
本着other answer的精神,您可以扩展模板功能。 使用“生产力”工具生成单个分页符对象,如:
private readonly Paragraph PageBreakPara = new Paragraph(new Run(new Break() { Type = BreakValues.Page}));
创建一个帮助方法来查找文本标记的容器:
public IEnumerable FindElements(OpenXmlCompositeElement searchParent,string tagRegex) 其中T:OpenXmlElement { var regex = new Regex(tagRegex);
return searchParent.Descendants()
.Where(e=>(!(e is OpenXmlCompositeElement)
&& regex.IsMatch(e.InnerText)))
.SelectMany(e =>
e.Ancestors()
.OfType<T>()
.Union(e is T ? new T[] { (T)e } : new T[] {} ))
.ToList(); // can skip, prevents reevaluations
}
另一个与文档重复范围并删除范围:
public IEnumerable<T> DuplicateRange<T>(OpenXmlCompositeElement root, string tagRegex)
where T: OpenXmlElement
{
// tagRegex must describe exactly two tags, such as [pageStart] and [pageEnd]
// or [page] [/page] - or whatever pattern you choose
var tagElements = FindElements(root, tagRegex);
var fromEl = tagElements.First();
var toEl = tagElements.Skip(1).First(); // throws exception if less than 2 el
// you may want to find a common parent here
// I'll assume you've prepared the template so the elements are siblings.
var result = new List<OpenXmlElement>();
var step = fromEl.NextSibling();
while (step !=null && toEl!=null && step!=toEl){
// another method called DeleteRange will instead delete elements in that range within this loop
var copy = step.CloneNode();
toEl.InsertAfterSelf(copy);
result.Add(copy);
step = step.NextSibling();
}
return result;
}
public IEnumerable<OpenXmlElement> ReplaceTag(OpenXmlCompositeElement parent, string tagRegex, string replacement){
var replaceElements = FindElements<OpenXmlElement>(parent, tagRegex);
var regex = new Regex(tagRegex);
foreach(var el in replaceElements){
el.InnerText = regex.Replace(el.InnerText, replacement);
}
return replaceElements;
}
现在您可以拥有一个如下所示的文档:
[页] [TitleLetter]
[WordTemplate] [Word]:[翻译] [/ WordTemplate]
[分页符] [/页]
使用该文档,您可以复制[page] .. [/ page]范围,按字母处理,一旦您没有字母 - 删除模板范围:
var vocabulary = Dictionary&gt ;;
foreach (var letter in vocabulary.Keys.OrderByDescending(c=>c)){
// in reverse order because the copy range comes after the template range
var pageTemplate = DuplicateRange(wordDocument,"\\[/?page\\]");
foreach (var p in pageTemplate.OfType<OpenXmlCompositeElement>()){
ReplaceTag(p, "[TitleLetter]",""+letter);
var pageBr = ReplaceTag(p, "[pageBreak]","");
if (pageBr.Any()){
foreach(var pbr in pageBr){
pbr.InsertAfterSelf(PageBreakPara.CloneNode());
}
}
var wordTemplateFound = FindElements(p, "\\[/?WordTemplate\\]");
if (wordTemplateFound .Any()){
foreach (var word in vocabulary[letter].Keys){
var wordTemplate = DuplicateRange(p, "\\[/?WordTemplate\\]")
.First(); // since it's a single paragraph template
ReplaceTag(wordTemplate, "\\[/?WordTemplate\\]","");
ReplaceTag(wordTemplate, "\\[Word]",word);
ReplaceTag(wordTemplate, "\\[Translation\\]",vocabulary[letter][word]);
}
}
}
}
......或类似的东西。