Пример #1
0
        public void CanReplaceTextWithSymbolsAndTrackedChanges()
        {
            XDocument partDocument = XDocument.Parse(SymbolsAndTrackedChangesDocumentXmlString);
            XElement  p            = partDocument.Descendants(W.p).First();
            string    innerText    = InnerText(p);

            Assert.Equal("We can also use symbols such as \uF021 or \uF028.", innerText);

            using (var stream = new MemoryStream())
                using (WordprocessingDocument wordDocument = WordprocessingDocument.Create(stream, DocumentType))
                {
                    MainDocumentPart part = wordDocument.AddMainDocumentPart();
                    part.PutXDocument(partDocument);

                    IEnumerable <XElement> content = partDocument.Descendants(W.p);
                    var regex = new Regex(@"[\uF021]");
                    int count = OpenXmlRegex.Replace(content, regex, "\uF028", null, true, "John Doe");

                    p         = partDocument.Descendants(W.p).First();
                    innerText = InnerText(p);

                    Assert.Equal(1, count);
                    Assert.Equal("We can also use symbols such as \uF028 or \uF028.", innerText);

                    Assert.Contains(p.Descendants(W.ins), ins => ins.Descendants(W.sym).Any(
                                        sym => sym.Attribute(W.font).Value == "Wingdings" &&
                                        sym.Attribute(W._char).Value == "F028"));
                }
        }
Пример #2
0
        public DocX AddToC(string title = null)
        {
            var tableOfContents = new TableOfContents(document);

            var lastParagraph = MainDocumentPart
                                .GetXDocument()
                                .Descendants(W.p)
                                .LastOrDefault();

            if (lastParagraph == null)
            {
                var xdoc = MainDocumentPart.GetXDocument();

                xdoc.Add(XElement.Parse(Body.OuterXml));
                MainDocumentPart.PutXDocument();

                lastParagraph = MainDocumentPart
                                .GetXDocument()
                                .Descendants(W.p)
                                .LastOrDefault();
            }

            tableOfContents.AddToc(lastParagraph, @"TOC \o '1-3' \h \z \u", title, null);

            return(this);
        }
Пример #3
0
        public void CanRemoveContentControls()
        {
            XDocument partDocument = XDocument.Parse(SdtDocumentXmlString);

            Assert.True(partDocument.Descendants(W.sdt).Any());

            using (var stream = new MemoryStream())
                using (WordprocessingDocument wordDocument = WordprocessingDocument.Create(stream, DocumentType))
                {
                    MainDocumentPart part = wordDocument.AddMainDocumentPart();
                    part.PutXDocument(partDocument);

                    var settings = new SimplifyMarkupSettings {
                        RemoveContentControls = true
                    };
                    MarkupSimplifier.SimplifyMarkup(wordDocument, settings);

                    partDocument = part.GetXDocument();
                    XElement element = partDocument
                                       .Descendants(W.body)
                                       .Descendants()
                                       .First();

                    Assert.False(partDocument.Descendants(W.sdt).Any());
                    Assert.Equal(W.p, element.Name);
                }
        }
Пример #4
0
        public void CanRemoveGoBackBookmarks()
        {
            XDocument partDocument = XDocument.Parse(GoBackBookmarkDocumentXmlString);

            Assert.Contains(partDocument
                            .Descendants(W.bookmarkStart)
                            , e => e.Attribute(W.name).Value == "_GoBack" && e.Attribute(W.id).Value == "0");
            Assert.Contains(partDocument
                            .Descendants(W.bookmarkEnd)
                            , e => e.Attribute(W.id).Value == "0");

            using (var stream = new MemoryStream())
                using (WordprocessingDocument wordDocument = WordprocessingDocument.Create(stream, DocumentType))
                {
                    MainDocumentPart part = wordDocument.AddMainDocumentPart();
                    part.PutXDocument(partDocument);

                    var settings = new SimplifyMarkupSettings {
                        RemoveGoBackBookmark = true
                    };
                    MarkupSimplifier.SimplifyMarkup(wordDocument, settings);

                    partDocument = part.GetXDocument();
                    Assert.False(partDocument.Descendants(W.bookmarkStart).Any());
                    Assert.False(partDocument.Descendants(W.bookmarkEnd).Any());
                }
        }
Пример #5
0
        public void CanReplaceTextWithQuotationMarksAndTrackedChanges()
        {
            XDocument partDocument = XDocument.Parse(QuotationMarksAndTrackedChangesDocumentXmlString);
            XElement  p            = partDocument.Descendants(W.p).First();
            string    innerText    = InnerText(p);

            Assert.Equal(
                "Text can be enclosed in “normal double quotes” and in «double angle quotation marks».",
                innerText);

            using (var stream = new MemoryStream())
                using (WordprocessingDocument wordDocument = WordprocessingDocument.Create(stream, DocumentType))
                {
                    MainDocumentPart part = wordDocument.AddMainDocumentPart();
                    part.PutXDocument(partDocument);

                    IEnumerable <XElement> content = partDocument.Descendants(W.p);
                    var regex = new Regex(string.Format("{0}(?<words>{1}){2}", LeftDoubleQuotationMarks, Words,
                                                        RightDoubleQuotationMarks));
                    int count = OpenXmlRegex.Replace(content, regex, "‘changed ${words}’", null, true, "John Doe");

                    p         = partDocument.Descendants(W.p).First();
                    innerText = InnerText(p);

                    Assert.Equal(2, count);
                    Assert.Equal(
                        "Text can be enclosed in ‘changed normal double quotes’ and in ‘changed double angle quotation marks’.",
                        innerText);

                    Assert.Contains(p.Elements(W.ins), e => InnerText(e) == "‘changed normal double quotes’");
                    Assert.Contains(p.Elements(W.ins), e => InnerText(e) == "‘changed double angle quotation marks’");
                }
        }
Пример #6
0
        public static void SetContent(WordprocessingDocument document, IEnumerable <XElement> contents)
        {
            MainDocumentPart mainDocumentPart = document.MainDocumentPart;

            if (mainDocumentPart == null)
            {
                mainDocumentPart = document.AddMainDocumentPart();
            }
            XDocument mainDocumentPartContentToInsert = new XDocument(
                new XElement(W.document,
                             new XAttribute(XNamespace.Xmlns + "w", W.w),
                             new XAttribute(XNamespace.Xmlns + "r", R.r),
                             new XElement(W.body, contents)));
            XDocument mainDocumentPartContent = mainDocumentPart.GetXDocument();

            if (mainDocumentPartContent.Root == null)
            {
                mainDocumentPartContent.Add(mainDocumentPartContentToInsert.Root);
            }
            else
            {
                mainDocumentPartContent.Root.ReplaceWith(mainDocumentPartContentToInsert.Root);
            }
            mainDocumentPart.PutXDocument();
        }
Пример #7
0
        public void CanReplaceTextWithFields()
        {
            XDocument partDocument = XDocument.Parse(FieldsDocumentXmlString);
            XElement  p            = partDocument.Descendants(W.p).Last();
            string    innerText    = InnerText(p);

            Assert.Equal("As stated in Article {__1} and this Section {__1.1}, this is described in Schedule C (Performance Framework).",
                         innerText);

            using (var stream = new MemoryStream())
                using (WordprocessingDocument wordDocument = WordprocessingDocument.Create(stream, DocumentType))
                {
                    MainDocumentPart part = wordDocument.AddMainDocumentPart();
                    part.PutXDocument(partDocument);

                    IEnumerable <XElement> content = partDocument.Descendants(W.p);
                    var regex = new Regex(@"Schedule C \(Performance Framework\)");
                    int count = OpenXmlRegex.Replace(content, regex, "Exhibit 4", null, true, "John Doe");

                    p         = partDocument.Descendants(W.p).Last();
                    innerText = InnerText(p);

                    Assert.Equal(1, count);
                    Assert.Equal("As stated in Article {__1} and this Section {__1.1}, this is described in Exhibit 4.", innerText);
                }
        }
Пример #8
0
        private static void ChangeFootnoteEndnoteReferencesToUniqueRange(
            WordprocessingDocument wDoc,
            int startingIdForFootnotesEndnotes)
        {
            MainDocumentPart mainDocPart   = wDoc.MainDocumentPart;
            FootnotesPart    footnotesPart = wDoc.MainDocumentPart.FootnotesPart;
            EndnotesPart     endnotesPart  = wDoc.MainDocumentPart.EndnotesPart;

            XElement document =
                mainDocPart.GetXDocument().Root ?? throw new OpenXmlPowerToolsException("Invalid document.");

            XElement footnotes = footnotesPart?.GetXDocument().Root;
            XElement endnotes  = endnotesPart?.GetXDocument().Root;

            IEnumerable <XElement> references = document
                                                .Descendants()
                                                .Where(d => d.Name == W.footnoteReference || d.Name == W.endnoteReference);

            foreach (XElement r in references)
            {
                var    oldId = (string)r.Attribute(W.id);
                string newId = startingIdForFootnotesEndnotes.ToString();
                startingIdForFootnotesEndnotes++;
                r.SetAttributeValue(W.id, newId);
                if (r.Name == W.footnoteReference)
                {
                    XElement fn = footnotes?
                                  .Elements()
                                  .FirstOrDefault(e => (string)e.Attribute(W.id) == oldId);

                    if (fn == null)
                    {
                        throw new OpenXmlPowerToolsException("Invalid document");
                    }

                    fn.SetAttributeValue(W.id, newId);
                }
                else
                {
                    XElement en = endnotes?
                                  .Elements()
                                  .FirstOrDefault(e => (string)e.Attribute(W.id) == oldId);

                    if (en == null)
                    {
                        throw new OpenXmlPowerToolsException("Invalid document");
                    }

                    en.SetAttributeValue(W.id, newId);
                }
            }

            mainDocPart.PutXDocument();
            footnotesPart?.PutXDocument();
            endnotesPart?.PutXDocument();
        }
        private static MemoryStream CreateWordprocessingDocument(IEnumerable <string> runTexts)
        {
            var stream = new MemoryStream();
            const WordprocessingDocumentType type = WordprocessingDocumentType.Document;

            using (WordprocessingDocument wordDocument = WordprocessingDocument.Create(stream, type))
            {
                MainDocumentPart mainDocumentPart = wordDocument.AddMainDocumentPart();
                mainDocumentPart.PutXDocument(new XDocument(CreateDocument(runTexts)));
            }

            return(stream);
        }
Пример #10
0
        /// <summary>
        /// Creates a <see cref="WordprocessingDocument"/> for on a <see cref="MemoryStream"/>
        /// testing purposes, using the given <paramref name="document"/> as the w:document
        /// root element of the main document part.
        /// </summary>
        /// <param name="document">The w:document root element.</param>
        /// <returns>The <see cref="MemoryStream"/> containing the <see cref="WordprocessingDocument"/>.</returns>
        private static MemoryStream CreateWordprocessingDocument(XElement document)
        {
            var stream = new MemoryStream();
            const WordprocessingDocumentType type = WordprocessingDocumentType.Document;

            using (WordprocessingDocument wordDocument = WordprocessingDocument.Create(stream, type))
            {
                MainDocumentPart part = wordDocument.AddMainDocumentPart();
                part.PutXDocument(new XDocument(document));
            }

            return(stream);
        }
        /// <summary>
        /// Creates a new <see cref="WordprocessingDocument" /> on the given <see cref="Stream" />,
        /// having the given <see cref="XDocument" /> as the main document part's content and
        /// adding a default style definitions part.
        /// </summary>
        /// <param name="stream">The <see cref="Stream" />.</param>
        /// <param name="document">The <see cref="XDocument" />.</param>
        /// <returns>The new <see cref="WordprocessingDocument" />.</returns>
        protected static WordprocessingDocument CreateWordprocessingDocument(Stream stream, XDocument document)
        {
            WordprocessingDocument wordDocument = WordprocessingDocument.Create(stream, DocumentType);

            MainDocumentPart mainDocumentPart = wordDocument.AddMainDocumentPart();

            mainDocumentPart.PutXDocument(document);

            var styleDefinitionsPart = mainDocumentPart.AddNewPart <StyleDefinitionsPart>();

            styleDefinitionsPart.PutXDocument(XDocument.Parse(StylesXml));

            return(wordDocument);
        }
Пример #12
0
        public void MustEndPowerToolsBlockToUseStronglyTypedClasses()
        {
            using (var stream = new MemoryStream())
            {
                CreateEmptyWordprocessingDocument(stream);

                using (WordprocessingDocument wordDocument = WordprocessingDocument.Open(stream, true))
                {
                    MainDocumentPart part = wordDocument.MainDocumentPart;

                    // Add a paragraph through the SDK.
                    Body body = part.Document.Body;
                    body.AppendChild(new Paragraph(new Run(new Text("Added through SDK"))));

                    // Begin the PowerTools Block, which saves any changes made through the strongly
                    // typed SDK classes to the parts of the WordprocessingDocument.
                    // In this case, this could also be done by invoking the Save method on the
                    // WordprocessingDocument, which will save all parts that had changes, or by
                    // invoking part.RootElement.Save() for the one part that was changed.
                    wordDocument.BeginPowerToolsBlock();

                    // Add a paragraph through the PowerTools.
                    XDocument content     = part.GetXDocument();
                    XElement  bodyElement = content.Descendants(W.body).First();
                    bodyElement.Add(new XElement(W.p, new XElement(W.r, new XElement(W.t, "Added through PowerTools"))));
                    part.PutXDocument();

                    // Get the part's content through the SDK. However, we will only see what we
                    // added through the SDK, not what we added through the PowerTools functionality.
                    body = part.Document.Body;
                    List <Paragraph> paragraphs = body.Elements <Paragraph>().ToList();
                    Assert.Equal(1, paragraphs.Count);
                    Assert.Equal("Added through SDK", paragraphs[0].InnerText);

                    // Now, let's end the PowerTools Block, which reloads the root element of this
                    // one part. Reloading those root elements this way is fine if you know exactly
                    // which parts had their content changed by the Open XML PowerTools.
                    wordDocument.EndPowerToolsBlock();

                    // Get the part's content through the SDK. Having reloaded the root element,
                    // we should now see both paragraphs.
                    body       = part.Document.Body;
                    paragraphs = body.Elements <Paragraph>().ToList();
                    Assert.Equal(2, paragraphs.Count);
                    Assert.Equal("Added through SDK", paragraphs[0].InnerText);
                    Assert.Equal("Added through PowerTools", paragraphs[1].InnerText);
                }
            }
        }
Пример #13
0
        private static void InitializeWordprocessingDocument(
            WordprocessingDocument wordDocument,
            XElement customXmlRoot,
            XElement sdtContent)
        {
            MainDocumentPart mainDocumentPart = wordDocument.AddMainDocumentPart();
            string           storeItemId      = CreateCustomXmlPart(mainDocumentPart, customXmlRoot);

            mainDocumentPart.PutXDocument(new XDocument(
                                              new XElement(W.document,
                                                           new XAttribute(XNamespace.Xmlns + "w", W.w.NamespaceName),
                                                           new XElement(W.body,
                                                                        new XElement(W.sdt,
                                                                                     new XElement(W.sdtPr,
                                                                                                  new XElement(W.tag, new XAttribute(W.val, "Node")),
                                                                                                  new XElement(W.dataBinding,
                                                                                                               new XAttribute(W.prefixMappings, $"xmlns:{NsPrefix}='{NsName}'"),
                                                                                                               new XAttribute(W.xpath, $"{NsPrefix}:Root[1]/{NsPrefix}:Node[1]"),
                                                                                                               new XAttribute(W.storeItemID, storeItemId))),
                                                                                     sdtContent)))));
        }
Пример #14
0
        public void CanUsePowerToolsBlockToDemarcateApis()
        {
            using (var stream = new MemoryStream())
            {
                CreateEmptyWordprocessingDocument(stream);

                using (WordprocessingDocument wordDocument = WordprocessingDocument.Open(stream, true))
                {
                    MainDocumentPart part = wordDocument.MainDocumentPart;

                    // Add a paragraph through the SDK.
                    Body body = part.Document.Body;
                    body.AppendChild(new Paragraph(new Run(new Text("Added through SDK"))));

                    // This demonstrates the use of the PowerToolsBlock in a using statement to
                    // demarcate the intermittent use of the PowerTools.
                    using (new PowerToolsBlock(wordDocument))
                    {
                        // Assert that we can see the paragraph added through the strongly typed classes.
                        XDocument       content           = part.GetXDocument();
                        List <XElement> paragraphElements = content.Descendants(W.p).ToList();
                        Assert.Single(paragraphElements);
                        Assert.Equal("Added through SDK", paragraphElements[0].Value);

                        // Add a paragraph through the PowerTools.
                        XElement bodyElement = content.Descendants(W.body).First();
                        bodyElement.Add(new XElement(W.p, new XElement(W.r, new XElement(W.t, "Added through PowerTools"))));
                        part.PutXDocument();
                    }

                    // Get the part's content through the SDK. Having used the PowerToolsBlock,
                    // we should see both paragraphs.
                    body = part.Document.Body;
                    List <Paragraph> paragraphs = body.Elements <Paragraph>().ToList();
                    Assert.Equal(2, paragraphs.Count);
                    Assert.Equal("Added through SDK", paragraphs[0].InnerText);
                    Assert.Equal("Added through PowerTools", paragraphs[1].InnerText);
                }
            }
        }
Пример #15
0
        public void CanDataBindBlockLevelSdtToCustomXmlWithNsPrefixIfNsPrefixInPrefixMapping()
        {
            // The following root element has an explicitly created attribute
            // xmlns:ex="http://example.com":
            //
            //   <ex:Root xmlns:ex="http://example.com">
            //     <ex:Node>VALUE1</ex:Node>
            //   </ex:Root>
            //
            var customXmlRootElement =
                new XElement(Ns + "Root",
                             new XAttribute(XNamespace.Xmlns + NsPrefix, NsName),
                             new XElement(Ns + "Node", "VALUE1"));

            using WordprocessingDocument wordDocument =
                      WordprocessingDocument.Create("SdtBlock_NsPrefix_WithNsPrefixInMapping.docx", Type);

            MainDocumentPart mainDocumentPart = wordDocument.AddMainDocumentPart();
            string           storeItemId      = CreateCustomXmlPart(mainDocumentPart, customXmlRootElement);

            mainDocumentPart.PutXDocument(new XDocument(
                                              new XElement(W.document,
                                                           new XAttribute(XNamespace.Xmlns + "w", W.w.NamespaceName),
                                                           new XElement(W.body,
                                                                        new XElement(W.sdt,
                                                                                     new XElement(W.sdtPr,
                                                                                                  new XElement(W.dataBinding,
                                                                                                               // Note the w:prefixMapping attribute WITH a namespace
                                                                                                               // prefix and the corresponding w:xpath atttibute.
                                                                                                               new XAttribute(W.prefixMappings, $"xmlns:{NsPrefix}='{NsName}'"),
                                                                                                               new XAttribute(W.xpath, $"{NsPrefix}:Root[1]/{NsPrefix}:Node[1]"),
                                                                                                               new XAttribute(W.storeItemID, storeItemId))),
                                                                                     new XElement(W.sdtContent,
                                                                                                  new XElement(W.p)))))));

            // Note that we just added an empty w:p to the w:sdtContent element.
            // However, if you open the Word document created by the above code
            // in Microsoft Word, you should see a single paragraph saying
            // "VALUE1".
        }
Пример #16
0
        public void CannotDataBindBlockLevelSdtToCustomXmlWithDefaultNsIfNotNsPrefixInPrefixMapping()
        {
            // The following root element has an implicitly created attribute
            // xmlns='http://example.com':
            //
            //   <Root xmlns="http://example.com">
            //     <Node>VALUE1</Node>
            //   </Root>
            //
            var customXmlRootElement =
                new XElement(Ns + "Root",
                             new XElement(Ns + "Node", "VALUE1"));

            using WordprocessingDocument wordDocument =
                      WordprocessingDocument.Create("SdtBlock_DefaultNs_WithoutNsPrefixInMapping.docx", Type);

            MainDocumentPart mainDocumentPart = wordDocument.AddMainDocumentPart();
            string           storeItemId      = CreateCustomXmlPart(mainDocumentPart, customXmlRootElement);

            mainDocumentPart.PutXDocument(new XDocument(
                                              new XElement(W.document,
                                                           new XAttribute(XNamespace.Xmlns + "w", W.w.NamespaceName),
                                                           new XElement(W.body,
                                                                        new XElement(W.sdt,
                                                                                     new XElement(W.sdtPr,
                                                                                                  new XElement(W.dataBinding,
                                                                                                               // Note the w:prefixMapping attribute WITHOUT a namespace
                                                                                                               // prefix and the corresponding w:xpath atttibute.
                                                                                                               new XAttribute(W.prefixMappings, $"xmlns='{NsName}'"),
                                                                                                               new XAttribute(W.xpath, "Root[1]/Node[1]"),
                                                                                                               new XAttribute(W.storeItemID, storeItemId))),
                                                                                     new XElement(W.sdtContent,
                                                                                                  new XElement(W.p)))))));

            // Note that we just added an empty w:p to the w:sdtContent element.
            // If you open the Word document created by the above code in Microsoft
            // Microsoft Word, you will only see an EMPTY paragraph.
        }
Пример #17
0
        public void CanRemoveSmartTags()
        {
            XDocument partDocument = XDocument.Parse(SmartTagDocumentXmlString);

            Assert.True(partDocument.Descendants(W.smartTag).Any());

            using (var stream = new MemoryStream())
                using (WordprocessingDocument wordDocument = WordprocessingDocument.Create(stream, DocumentType))
                {
                    MainDocumentPart part = wordDocument.AddMainDocumentPart();
                    part.PutXDocument(partDocument);

                    var settings = new SimplifyMarkupSettings {
                        RemoveSmartTags = true
                    };
                    MarkupSimplifier.SimplifyMarkup(wordDocument, settings);

                    partDocument = part.GetXDocument();
                    XElement t = partDocument.Descendants(W.t).First();

                    Assert.False(partDocument.Descendants(W.smartTag).Any());
                    Assert.Equal(SmartTagDocumentTextValue, t.Value);
                }
        }
Пример #18
0
        public void CanUpdateCustomXmlAndMainDocumentPart()
        {
            // Define the initial and updated values of our custom XML element and
            // the data-bound w:sdt element.
            const string initialValue = "VALUE1";
            const string updatedValue = "value2";

            // Create the root element of the custom XML part with the initial value.
            var customXmlRoot =
                new XElement(Ns + "Root",
                             new XAttribute(XNamespace.Xmlns + NsPrefix, NsName),
                             new XElement(Ns + "Node", initialValue));

            // Create the w:sdtContent child element of our w:sdt with the initial value.
            var sdtContent =
                new XElement(W.sdtContent,
                             new XElement(W.p,
                                          new XElement(W.r,
                                                       new XElement(W.t, initialValue))));

            // Create a WordprocessingDocument with the initial values.
            using var stream = new MemoryStream();
            using (WordprocessingDocument wordDocument = WordprocessingDocument.Create(stream, Type))
            {
                InitializeWordprocessingDocument(wordDocument, customXmlRoot, sdtContent);
            }

            // Assert the WordprocessingDocument has the expected, initial values.
            using (WordprocessingDocument wordDocument = WordprocessingDocument.Open(stream, true))
            {
                AssertValuesAreAsExpected(wordDocument, initialValue);
            }

            // Update the WordprocessingDocument, using the updated value.
            using (WordprocessingDocument wordDocument = WordprocessingDocument.Open(stream, true))
            {
                MainDocumentPart mainDocumentPart = wordDocument.MainDocumentPart;

                // Change custom XML element, again using the simplifying assumption
                // that we only have a single custom XML part and a single ex:Node
                // element.
                CustomXmlPart customXmlPart = mainDocumentPart.CustomXmlParts.Single();
                XElement      root          = customXmlPart.GetXElement();
                XElement      node          = root.Elements(Ns + "Node").Single();
                node.Value = updatedValue;
                customXmlPart.PutXDocument();

                // Change the w:sdt contained in the MainDocumentPart.
                XElement document = mainDocumentPart.GetXElement();
                XElement sdt      = FindSdtWithTag("Node", document);
                sdtContent = sdt.Elements(W.sdtContent).Single();
                sdtContent.ReplaceAll(
                    new XElement(W.p,
                                 new XElement(W.r,
                                              new XElement(W.t, updatedValue))));

                mainDocumentPart.PutXDocument();
            }

            // Assert the WordprocessingDocument has the expected, updated values.
            using (WordprocessingDocument wordDocument = WordprocessingDocument.Open(stream, true))
            {
                AssertValuesAreAsExpected(wordDocument, updatedValue);
            }
        }