private static void InitializeParagraphInfo(XElement contentContext)
 {
     if (!(W.BlockLevelContentContainers.Contains(contentContext.Name)))
         throw new ArgumentException(
             "GetParagraphInfo called for element that is not child of content container");
     XElement prev = null;
     foreach (var content in contentContext.Elements())
     {
         // This may return null, indicating that there is no descendant paragraph.  For
         // example, comment elements have no descendant elements.
         XElement paragraph = content
             .DescendantsAndSelf()
             .Where(e => e.Name == W.p || e.Name == W.tc || e.Name == W.txbxContent)
             .FirstOrDefault();
         if (paragraph != null &&
             (paragraph.Name == W.tc || paragraph.Name == W.txbxContent))
             paragraph = null;
         BlockContentInfo pi = new BlockContentInfo()
         {
             PreviousBlockContentElement = prev,
             ThisBlockContentElement = paragraph
         };
         content.AddAnnotation(pi);
         prev = content;
     }
 }
 /// Accept deleted paragraphs.
 ///
 /// Group together all paragraphs that contain w:p/w:pPr/w:rPr/w:del elements.  Make a
 /// second group for the content element immediately following a paragraph that contains
 /// a w:del element.  The code uses the approach of dealing with paragraph content at
 /// 'levels', ignoring paragraph content at other levels.  Form a new paragraph that
 /// contains the content of the grouped paragraphs with deleted paragraph marks, and the
 /// content of the paragraph immediately following a paragraph that contains a deleted
 /// paragraph mark.  Include in the new paragraph the paragraph properties from the
 /// paragraph following.  When assembling the new paragraph, use a transform that collapses
 /// the paragraph nodes when adding content, thereby preserving custom XML and content
 /// controls.
 private static void AnnotateBlockContentElements(XElement contentContainer)
 {
     // For convenience, there is a ParagraphInfo annotation on the contentContainer.
     // It contains the same information as the ParagraphInfo annotation on the first
     //   paragraph.
     if (contentContainer.Annotation<BlockContentInfo>() != null)
         return;
     XElement firstContentElement = contentContainer
         .Elements()
         .DescendantsAndSelf()
         .FirstOrDefault(e => e.Name == W.p || e.Name == W.tbl);
     // Add the annotation on the contentContainer.
     BlockContentInfo currentContentInfo = new BlockContentInfo()
     {
         PreviousBlockContentElement = null,
         ThisBlockContentElement = firstContentElement,
         NextBlockContentElement = null
     };
     // Add as annotation even though NextParagraph is not set yet.
     contentContainer.AddAnnotation(currentContentInfo);
     while (true)
     {
         currentContentInfo.ThisBlockContentElement.AddAnnotation(currentContentInfo);
         // Find next sibling content element.
         XElement nextContentElement = null;
         XElement current = currentContentInfo.ThisBlockContentElement;
         while (true)
         {
             nextContentElement = current
                 .ElementsAfterSelf()
                 .DescendantsAndSelf()
                 .FirstOrDefault(e => e.Name == W.p || e.Name == W.tbl);
             if (nextContentElement != null)
             {
                 currentContentInfo.NextBlockContentElement = nextContentElement;
                 break;
             }
             current = current.Parent;
             // When we've backed up the tree to the contentContainer, we're done.
             if (current == contentContainer)
                 return;
         }
         currentContentInfo = new BlockContentInfo()
         {
             PreviousBlockContentElement = currentContentInfo.ThisBlockContentElement,
             ThisBlockContentElement = nextContentElement,
             NextBlockContentElement = null
         };
     }
 }