wordpress hit counter
Culling blank lines after paragraph insertion - WordprocessingML - Formats - OpenXML Developer

Culling blank lines after paragraph insertion

Formats

Discussions about working with different Open XML Formats

Culling blank lines after paragraph insertion

  • rated by 0 users
  • This post has 4 Replies |
  • 1 Follower
  • Hello,

     

    I am using OpenXML to cycle through a list of content controls in a document (template). This is typically done by locating a content control and then populating a paragraph with the text that I want using the Parent.Append for SdtRuns. I do basically the same thing with the SdtBlocks within the document, with the exception that I use Parent.InsertAfter. I finish up the process by performing a remove on the element/content control that I used to perform the insertion. This is working out well in that my insertions are showing up perfectly.

    However, I am noticing that when I perform the Parent.Append for an SdtRun, it also adds a blank line after the insertion with no whitespaces. I have formatted the document with spacing after and afterlines = 0. I have also set the style to NoSpacing. The saved document does not indeed have line spacing but the blank lines are still present.

     

     

    Is there any way to get around this. I can post cost if this is not helpful enough.

  • Yes, please post code, as well as a document to make it a complete example.

    -Eric

  • This is the class where the generation is perform. For reference, the OpenXMLDocument that is shown is nothing more than a wrapper on top of 
    WordProcessingDocument. It has no functions or methods.

    public sealed class OpenXMLDocumentGenerator : IDocumentGenerator<OpenXMLDocument>, IDisposable
        {
            #region Methods
            /// <summary>
            /// Attempt to populate a given node with a specific value
            /// </summary>
            /// <param name="document"></param>
            /// <param name="nodeName"></param>
            /// <param name="nodeValue"></param>
            public void TryPopulateNode(OpenXMLDocument document, string nodeName, string nodeValue, bool removeAfterInsertion = true)
            {
    
                //List<SdtElement> sdtElements = document.Data.MainDocumentPart.Document.Descendants<SdtElement>().Where(sdt => sdt.SdtProperties.GetFirstChild<SdtAlias>().Val.Value == nodeName).ToList();
    
                //foreach (SdtElement element in sdtElements)
                //{
                //    TryInsertNodeValue(element, nodeName, nodeValue);
                //}
                
    
                foreach (SdtRun run in document.ContentRuns)
                {
                    if (GetNodeAlias(run) == nodeName)
                    {                  
                        TryInsertNodeValue(run, GetNodeAlias(run), nodeValue, removeAfterInsertion);
                    }
                }
    
                foreach (SdtBlock block in document.ContentBlocks)
                {
                    if (GetNodeAlias(block) == nodeName)
                    {
                        TryInsertNodeValue(block, GetNodeAlias(block), nodeValue, removeAfterInsertion);
                    }
                }
            }
    
            /// <summary>
            /// Attempt to populate a node
            /// </summary>
            /// <param name="openXmlElement"></param>
            /// <param name="nodeValue"></param>
            private void TryInsertNodeValue(OpenXmlElement openXmlElement, string nodeAlias, string nodeValue, bool removeAfterInsertion = true)
            {
                try
                {
                    Paragraph paragraph = new Paragraph();
                    Run run = new Run();
                    Text text = new Text(nodeValue) { Space = SpaceProcessingModeValues.Preserve };
    
                    ParagraphProperties props = new ParagraphProperties();
                    SpacingBetweenLines spacing = new SpacingBetweenLines() { After = "0", AfterLines = 0, LineRule = LineSpacingRuleValues.Exact };
                    ParagraphStyleId style = new ParagraphStyleId() { Val = "NoSpacing"};
                    RunProperties runProperties = new RunProperties();
                    RunFonts font = new RunFonts() { Ascii = "Times New Roman", HighAnsi = "Times New Roman", ComplexScript = "Times New Roman" };
                    RunStyle runStyle = new RunStyle() { Val = "NoSpacing" };
    
                    runProperties.Append(runStyle);
                    runProperties.Append(font);
    
                    props.Append(spacing);
                    props.Append(style);
    
                    run.Append(new SpacingBetweenLines() { After = "0", AfterLines = 0, LineRule = LineSpacingRuleValues.Exact });
                    run.Append(runProperties);
                    run.Append(text);
                    paragraph.Append(props);
                    paragraph.Append(run);
    
    
                    if (openXmlElement.GetType() == typeof(SdtRun))
                    {
                        openXmlElement.Parent.Append(paragraph);
                    }
                    else if (openXmlElement.GetType() == typeof(SdtBlock))
                    {
                        openXmlElement.Parent.InsertAfter(paragraph, openXmlElement);
                    }
    
                    //We may want to use the insertion points to insert multiple values
                    //So we leave removing optional
                    if (removeAfterInsertion)
                    {
                        openXmlElement.RemoveAllChildren();
                        openXmlElement.Remove();
                    }
                }
                catch (Exception ex)
                {
                    throw new OpenXMLNodeInsertionException(nodeAlias, nodeValue, ex.ToString());
                }
    
            }
    
            public void TryRemoveSpacing(OpenXMLDocument document)
            {
    
                foreach (var paragraph in document.Data.MainDocumentPart.RootElement.Descendants<Paragraph>())
                {
                    if (paragraph.ParagraphProperties != null)
                    {
                        paragraph.RemoveAllChildren<ParagraphStyleId>();
                        paragraph.RemoveAllChildren<SpacingBetweenLines>();
    
                        paragraph.InsertAt(new SpacingBetweenLines() { After = "0", AfterLines = 0, BeforeLines = 0 }, 0);
                        paragraph.InsertAt(new ParagraphStyleId() { Val = "NoSpacing" }, 0);
                    }
                }
    
            }
    
            /// <summary>
            /// Returns the alias of a SdtRun
            /// </summary>
            /// <param name="run"></param>
            /// <returns></returns>
            private string GetNodeAlias(SdtRun run)
            {
                string retVal = String.Empty;
    
                retVal = run.SdtProperties.Descendants<SdtAlias>().FirstOrDefault<SdtAlias>().Val.Value.ToString();
    
                return retVal;
            }
    
            /// <summary>
            /// Returns the alias of a SdtBlock
            /// </summary>
            /// <param name="block"></param>
            /// <returns></returns>
            private string GetNodeAlias(SdtBlock block)
            {
                string retVal = String.Empty;
    
                retVal = block.SdtProperties.Descendants<SdtAlias>().FirstOrDefault<SdtAlias>().Val.Value.ToString();
    
                return retVal;
            }
    
            /// <summary>
            /// Returns the alias of a custom xml element
            /// </summary>
            /// <param name="element"></param>
            /// <returns></returns>
            private string GetNodeAlias(CustomXmlElement element)
            {
                string retVal = String.Empty;
    
                retVal = element.Element;
    
                return retVal;
            } 
            #endregion
    
            #region IDisposable Members
            /// <summary>
            /// Dispose of this object
            /// </summary>
            public void Dispose()
            {
                GC.SuppressFinalize(this);
            } 
            #endregion
        }

    This is the before template:
    https://www.box.com/s/be528c811851fac98195

    And the output:
    https://www.box.com/s/01ccc4b40764472f5bdb

    For usage you would just call into the TryInsertNodeValue with a word processing document and it should iterate until it finds a matching node. Please
    let me know if this is not enough, I will upload the whole project. I would have done so already, but I need to scrub it and make sure I have it cleaned up as
    I work in the Healthcare industry and cannot risk the chance of releases information.

  • I have discovered that this is caused by "something" inserting a line break after each SdtRun, where I am using Parent.Append. In the after doc, I performed an in text search within Word 2007 for the text ^p^p and I noticed it keyed onto the lines where SdtRuns were inserted (i.e. Line with a content control following other text on the same line).

    I don't know if that helps.

  • Well Eric,

    it seems that I have solved this problem and have gotten around the need to populate a content control by appending and removing the source. I found this a few moments ago and it works excellently. Even though I solved this myself (this may not be the best way), I want to thank you for hosting this forum and letting people like myself ask questions.

    private void FillSimpleTextCC(SdtRun simpleTextCC, string replacementText)

           {

               // remove the showing place holder element      

               SdtProperties ccProperties = simpleTextCC.SdtProperties;

               ccProperties.RemoveAllChildren<ShowingPlaceholder>();

               // fetch content block Run element            

               SdtContentRun contentRun = simpleTextCC.SdtContentRun;

               var ccRun = contentRun.GetFirstChild<Run>();

               // if there was no placeholder text in the content control, then the SdtContentRun

               // block will be empty -> ccRun will be null, so create a new instance

               if (ccRun == null)

               {

                   ccRun = new Run(

                       new RunProperties() { RunStyle = null },

                       new Text());

                   contentRun.Append(ccRun);

               }

               // remove revision identifier & replace text

               ccRun.RsidRunProperties = null;

               ccRun.GetFirstChild<Text>().Text = replacementText;

               // set the run style to that stored in the SdtProperties block, if there was

               // one. Otherwise the existing style will be used.            

               var props = ccProperties.GetFirstChild<RunProperties>();

               if (props != null)

                   if (props != null)

                   {

                       RunStyle runStyle = props.RunStyle;

                       if (runStyle != null)

                       {

                           // set the run style to the same as content block property style.

                           var runProps = ccRun.RunProperties;

                           runProps.RunStyle = new RunStyle() { Val = runStyle.Val };

                           runProps.RunFonts = null;

                       }

                   }

           }

Page 1 of 1 (5 items)