多列docx文件的条件新Break,C#

时间:2016-01-05 14:38:58

标签: c# multiple-columns docx

这是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中,但我再次发现自己必须输入换行符,问题仍然存在。

1 个答案:

答案 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]);
       }
    }
  }
}

......或类似的东西。

  • 如果事情开始变得太复杂,请查看SdtElements
  • 尽管该答案很受欢迎,但不要使用AltChunk,它需要Word才能打开并处理该文件,因此您无法使用某些库来制作PDF
  • Word文档很乱,上面的解决方案应该可以使用(尚未测试),但必须精心制作模板,经常备份模板
  • 制作一个强大的文档引擎并不容易(因为Word很麻烦),尽量做到最少,并依赖于你控制中的模板(不是用户可编辑的)。
  • 上面的代码远非优化或简化,我试图以可呈现性为代价以最小的占用空间压缩它。也有可能的错误:)