2016-09-04 7 views
0

contact_name과 같은 특정 변수를 사용하도록 사용자가 디자인 한 단일 페이지 입력 docx 템플릿 파일이 있습니다. OpenXml SDK + Open-Xml-PowerTools를 사용하여 처리하는 동안이 템플릿을 기반으로 한 docx 파일의 인스턴스를 많이 만들고 실제 값을 변수로 대체합니다. 결국 하나의 docx 출력이 필요하므로 Open-Xml-PowerTools DocumentBuilder를 사용하여 하나의 docx로 병합합니다.docx 파일을 하나에 병합하고 번호 목록 서식을 유지합니다.

사용자가 번호 매기기 목록을 템플릿에 넣을 때까지 작동하는 것처럼 보입니다. 내 원래의 문제는 번호가 매겨진 목록이 문서 인스턴스의 병합 이후 번호 매김을 계속했습니다. 즉, 문서의 모든 항목이 동일한 목록 ID를 참조한다고 생각하여 목록의 두 번째 페이지의 번호가 1-10 대신 11-20이었습니다.

문서 본문에서 고유 한 num ID를 지정하여 문제를 해결할 수 있었지만 목록의 형식이 첫 번째 페이지를 넘어 손실되었습니다. 첫 번째 페이지에서 번호가 매겨진 목록 항목은 들여 쓰기되어 있지만 두 번째 이후에는 번호가 매겨지지 않은 목록처럼 페이지에 남아 있지 않습니다. 스타일 매기기 및 번호 매기기 섹션을 업데이트하여 이러한 새 num id를 일치시켜야하지만이 작업을 수행 할 수없는 것 같습니다.

나는이 문제를 ericwhite.com의 포럼에 올렸지 만 최신 문제 (http://ericwhite.com/blog/forums/topic/list-numbering-on-merged-docs/)에 관해서들은 적이 없습니다.

이 문제를 해결하기위한 최근의 시도로 OpenXml-Power-Tools에서 예외가 발생하므로 새 목록 ID로 일부 섹션을 업데이트하지 않을 것으로 생각됩니다. 누구든지이 작업을 수행하는 방법을 알고 있습니까? 다음은 예외를 따르는 코드입니다.

public bool Merge(List<InterchangeableWordProcessingDocument> inputFiles, string outputFilePath) 
    { 
     if (inputFiles == null) 
     { 
      logger.LogDebug("No files to merge."); 
      return true; 
     } 
     try 
     { 

      List<OpenXmlPowerTools.Source> sources = new List<OpenXmlPowerTools.Source>(); 
      int highestListNumbering = 0; 
      int highestAbstractListNumbering = 0; 
      foreach (var inputFile in inputFiles) 
      { 
       //Sometimes merge puts start of next page onto end of previous one so prevent 
       //Seems to cause extra blank page when there are labels so don't do on labels pages 
       if (inputFile.DocType == DocType.Letter) 
       { 
        using (var wordDoc = inputFile.GetAsWordProcessingDocument()) 
        { 
         var para = wordDoc.MainDocumentPart.Document.Body.ChildElements.First<Paragraph>(); 

         if (para.ParagraphProperties == null) 
         { 
          para.ParagraphProperties = new ParagraphProperties(); 
         } 

         para.ParagraphProperties.PageBreakBefore = new PageBreakBefore(); 

         //http://ericwhite.com/blog/forums/topic/list-numbering-on-merged-docs/ 
         //Numberings should be unique to each page otherwise they continue from the previous 
         //Keep track of how many we have so we can add on to always have a unique number 
         var numIds = wordDoc.MainDocumentPart.Document.Body.Descendants<NumberingId>().ToList(); 

         logger.LogDebug("Found " + numIds.Count + " num ids."); 

         foreach (var numId in numIds) 
          numId.Val += highestListNumbering; 

         var styleNumIds = wordDoc.MainDocumentPart.StyleDefinitionsPart.RootElement.Descendants<NumberingId>().ToList(); 

         if (wordDoc.MainDocumentPart.StyleDefinitionsPart != null) 
         { 

          logger.LogDebug("Found " + styleNumIds.Count + " stlye num ids."); 
          foreach (var styleNumId in styleNumIds) 
           styleNumId.Val += highestListNumbering; 
         } 

         if (wordDoc.MainDocumentPart.NumberingDefinitionsPart != null) 
         { 

          var numberingNumIds = wordDoc.MainDocumentPart.NumberingDefinitionsPart.RootElement.Descendants<NumberingInstance>().ToList(); 

          logger.LogDebug("Found " + numberingNumIds.Count + " numbering num ids."); 
          foreach (var numberingNumId in numberingNumIds) 
          { 
           numberingNumId.NumberID += highestListNumbering; 
           numberingNumId.AbstractNumId.Val += highestAbstractListNumbering; 
          } 

          var abstractNumberingNumIds = wordDoc.MainDocumentPart.NumberingDefinitionsPart.RootElement.Descendants<AbstractNumId>().ToList(); 

          logger.LogDebug("Found " + abstractNumberingNumIds.Count + " abstract num ids." + wordDoc.MainDocumentPart.NumberingDefinitionsPart.RootElement.XName.LocalName); 
          foreach (var abstractNumberingNumId in abstractNumberingNumIds) 
           abstractNumberingNumId.Val += highestAbstractListNumbering; 

          //Keep the max nums up to date 
          if (abstractNumberingNumIds.Count > 0) 
           highestAbstractListNumbering = Math.Max(highestAbstractListNumbering, abstractNumberingNumIds.Max(ln => (ln.Val.HasValue ? ln.Val.Value : 0))); 

         } 


         if (numIds.Count > 0) 
          highestListNumbering = Math.Max(highestListNumbering, numIds.Max(ln => (ln.Val.HasValue ? ln.Val.Value : 0))); 



         wordDoc.MainDocumentPart.Document.Save(); 
        } 
       } 
       sources.Add(new OpenXmlPowerTools.Source(inputFile.GetAsWmlDocument(), true)); 

      } 
      DocumentBuilder.BuildDocument(sources, outputFilePath); 
      return true; 

     } 
     catch (SystemException ex) 
     { 
      logger.LogError("Error occured while generating bereavement letters. ", ex); 

      return false; 
     } 
     finally 
     { 
      foreach (var inputFile in inputFiles) 
      { 
       inputFile.Dispose(); 
      } 
     } 
    } 

예외 :

각 패스 동안 동일한 AbstractNumId 참조 값을 두 번 업데이트하고 마치
System.InvalidOperationException: Sequence contains no elements 
at System.Linq.Enumerable.First[TSource](IEnumerable`1 source) 
at OpenXmlPowerTools.DocumentBuilder.CopyNumbering(WordprocessingDocument sourceDocument, WordprocessingDocument newDocument, IEnumerable1 newContent, List1 images) 
at OpenXmlPowerTools.DocumentBuilder.AppendDocument(WordprocessingDocument sourceDocument, WordprocessingDocument newDocument, List1 newContent, Boolean keepSection, String insertId, List1 images) 
at OpenXmlPowerTools.DocumentBuilder.BuildDocument(List`1 sources, WordprocessingDocument output) 
at OpenXmlPowerTools.DocumentBuilder.BuildDocument(List`1 sources, String fileName) 
at BereavementMailing.TemplateEngine.Merge(List`1 inputFiles, String outputFilePath) in C:\caw\Underdog\Apps\Services\BereavementMailingEngine\BM_RequestProcessor\TemplateEngine.cs:line 508 

답변

1

. 대신에 AbstractNum 정의 id 값을 업데이트해야합니다. 당신의 NumberingPart XML의

참조 값은 다음과 같이 :

<w:num w:numId="58"> 
     <w:abstractNumId w:val="2"/> 
    </w:num> 

당신은 두 번들을 업데이트하고 있습니다.

abstractNumber 정의

는 다음과 같다 :

<w:abstractNum w:abstractNumId="0" 
       w15:restartNumberingAfterBreak="0"> 
    <w:nsid w:val="FFFFFF88"/> 
    <w:multiLevelType w:val="singleLevel"/> 
    <w:tmpl w:val="8EE6963C"/> 
    <w:lvl w:ilvl="0"> 
     <w:start w:val="1"/> 
     <w:numFmt w:val="decimal"/> 
     <w:pStyle w:val="ListNumber"/> 
     <w:lvlText w:val="%1."/> 
     <w:lvlJc w:val="left"/> 
     <w:pPr> 
      <w:tabs> 
       <w:tab w:val="num" 
         w:pos="360"/> 
      </w:tabs> 
      <w:ind w:left="360" 
        w:hanging="360"/> 
     </w:pPr> 
    </w:lvl> 
</w:abstractNum> 

이 섹션 변경해보십시오 :

원본을

var abstractNumberingNumIds = wordDoc.MainDocumentPart.NumberingDefinitionsPart.RootElement.Descendants<AbstractNumId>().ToList(); 

logger.LogDebug("Found " + abstractNumberingNumIds.Count + " abstract num ids." + wordDoc.MainDocumentPart.NumberingDefinitionsPart.RootElement.XName.LocalName); 
foreach (var abstractNumberingNumId in abstractNumberingNumIds) 
abstractNumberingNumId.Val += highestAbstractListNumbering; 

//Keep the max nums up to date 
if (abstractNumberingNumIds.Count > 0) 
    highestAbstractListNumbering = Math.Max(highestAbstractListNumbering, abstractNumberingNumIds.Max(ln => (ln.Val.HasValue ? ln.Val.Value : 0))); 

새로운

var abstractNums = wordDoc.MainDocumentPart.NumberingDefinitionsPart.RootElement.Descendants<AbstractNum>().ToList(); 

logger.LogDebug("Found " + abstractNums.Count + " abstract nums." + wordDoc.MainDocumentPart.NumberingDefinitionsPart.RootElement.XName.LocalName); 
foreach (var abstractNum in abstractNums) 
    abstractNum.AbstractNumberId += highestAbstractListNumbering; 

//Keep the max nums up to date 
if (abstractNums.Count > 0) 
    highestAbstractListNumbering = Math.Max(highestAbstractListNumbering, abstractNums.Select(a => a.AbstractNumberId).Max(n => n.HasValue ? n.Value : 0));