/// <inheritdoc />
        public async Task <MemoryStream> Save()
        {
            MemoryStream stream = DocxFilePath.Create();

            stream = await Document.WriteInto(stream, "word/document.xml");

            stream = await Footnotes.WriteInto(stream, "word/footnotes.xml");

            stream = await ContentTypes.WriteInto(stream, ContentTypesInfo.Path);

            stream = await DocumentRelations.WriteInto(stream, DocumentRelsInfo.Path);

            stream = await FootnoteRelations.WriteInto(stream, "word/_rels/footnotes.xml.rels");

            stream = await Styles.WriteInto(stream, "word/styles.xml");

            stream = await Numbering.WriteInto(stream, "word/numbering.xml");

            stream = await Theme1.WriteInto(stream, "word/theme/theme1.xml");

            foreach (ChartInformation item in Charts)
            {
                stream = await item.Chart.WriteInto(stream, $"word/{item.Name}");
            }

            return(stream);
        }
        public virtual IOpenXmlVisitor Visit(DocxFilePath file)
        {
            if (file is null)
            {
                throw new ArgumentNullException(nameof(file));
            }

            IOpenXmlVisitor subject                 = new OpenXmlVisitor(file);
            IOpenXmlVisitor documentVisitor         = VisitDocument(subject, NextRevisionId);
            IOpenXmlVisitor footnoteVisitor         = VisitFootnotes(documentVisitor, NextFootnoteId, NextRevisionId);
            IOpenXmlVisitor documentRelationVisitor = VisitDocumentRelations(footnoteVisitor, NextDocumentRelationId);
            IOpenXmlVisitor footnoteRelationVisitor = VisitFootnoteRelations(documentRelationVisitor, NextFootnoteRelationId);
            IOpenXmlVisitor styleVisitor            = VisitStyles(footnoteRelationVisitor);
            IOpenXmlVisitor numberingVisitor        = VisitNumbering(styleVisitor);

            return(numberingVisitor);
        }
        /// <inheritdoc />
        public void Save(DocxFilePath result)
        {
            if (result is null)
            {
                throw new ArgumentNullException(nameof(result));
            }

            Document.WriteInto(result, "word/document.xml");
            Footnotes.WriteInto(result, "word/footnotes.xml");
            ContentTypes.WriteInto(result, ContentTypesInfo.Path);
            DocumentRelations.WriteInto(result, DocumentRelsInfo.Path);
            FootnoteRelations.WriteInto(result, "word/_rels/footnotes.xml.rels");
            Styles.WriteInto(result, "word/styles.xml");
            Numbering.WriteInto(result, "word/numbering.xml");
            Theme1.WriteInto(result, "word/theme/theme1.xml");

            foreach (ChartInformation item in Charts)
            {
                item.Chart.WriteInto(result, $"word/{item.Name}");
            }
        }
 /// <inheritdoc />
 /// <summary>
 /// Initialize a <see cref="ReportVisitor"/> based on the supplied <see cref="DocxFilePath"/>.
 /// </summary>
 /// <param name="result">
 /// The base path used to initialize the new <see cref="ReportVisitor"/>.
 /// </param>
 public ReportVisitor([NotNull] DocxFilePath result) : base(result)
 {
 }
        public IActionResult Index(
            [NotNull] [ItemNotNull] IEnumerable<IFormFile> files,
            [CanBeNull] string format,
            [CanBeNull] string title,
            [CanBeNull] string publisher,
            [CanBeNull] string website,
            [CanBeNull] string stylesheetUrl,
            [CanBeNull] IFormFile stylesheet)
        {
            if (files is null)
                throw new ArgumentNullException(nameof(files));

            IFormFile[] uploadedFiles = files.ToArray();

            if (uploadedFiles.Length == 0)
                return BadRequest("No files uploaded.");

            if (uploadedFiles.Any(x => x.Length <= 0))
                return BadRequest("Invalid file length.");

            if (uploadedFiles.Any(x => x.ContentType != MicrosoftWordDocument.ToString() &&
                                       x.FileName.EndsWith(".docx", StringComparison.OrdinalIgnoreCase) &&
                                       x.FileName.EndsWith(".md", StringComparison.OrdinalIgnoreCase)))
                return BadRequest("Invalid file format.");

            if (stylesheet is IFormFile s && !s.FileName.EndsWith(".css"))
                return BadRequest($"Invalid stylesheet:{stylesheet.FileName}.");

            Queue<Package> packagesQueue = new Queue<Package>(uploadedFiles.Length);

            foreach (IFormFile file in uploadedFiles)
            {
                if (file.FileName.EndsWith(".docx", StringComparison.OrdinalIgnoreCase))
                {
                    packagesQueue.Enqueue(Package.Open(file.OpenReadStream()));
                }
                else if (file.FileName.EndsWith(".md", StringComparison.OrdinalIgnoreCase))
                {
                    MDocument mDocument = new MDocument();
                    using (StreamReader reader = new StreamReader(file.OpenReadStream()))
                    {
                        MarkdownVisitor visitor = new MarkdownVisitor();
                        ReadOnlySpan<char> span;
                        while ((span = reader.ReadLine()) != null)
                        {
                            mDocument.Append(visitor.Visit(in span));
                        }
                    }

                    Package package = DocxFilePath.Create().ToPackage(FileAccess.ReadWrite);

                    mDocument.ToOpenXml().WriteTo(package.GetPart(Document.PartUri));

                    packagesQueue.Enqueue(package);
                }
            }

            Package output =
                Process(
                    packagesQueue,
                    title ?? "[REPORT TITLE]",
                    publisher ?? "[PUBLISHER]",
                    website ?? "[PUBLISHER WEBSITE]");

            foreach (Package package in packagesQueue)
            {
                package.Close();
            }

            switch (format)
            {
                case "docx":
                {
                    return File(output.ToStream(), MicrosoftWordDocument, $"{title ?? "result"}.docx");
                }
                case "html":
                {
                    string styles = stylesheet is null ? null : new StreamReader(stylesheet.OpenReadStream()).ReadToEnd();
                    OpenXmlPackageVisitor ooxml = new OpenXmlPackageVisitor(output);
                    HtmlVisitor html = new HtmlVisitor(ooxml.Document.ChartReferences, ooxml.Document.ImageReferences);
                    XObject htmlResult = html.Visit(ooxml.Document.Content, ooxml.Footnotes.Content, title, stylesheetUrl, styles);
                    return File(Encoding.UTF8.GetBytes(htmlResult.ToString()), "text/html", $"{title ?? "result"}.html");
                }
                case "xml":
                {
                    OpenXmlPackageVisitor xml = new OpenXmlPackageVisitor(output);
                    XElement xmlResult = xml.Document.Content;
                    return File(Encoding.UTF8.GetBytes(xmlResult.ToString()), "application/xml", $"{title ?? "result"}.xml");
                }
                default:
                {
                    return BadRequest(ModelState);
                }
            }
        }
        /// <summary>
        /// Initializes an <see cref="OpenXmlVisitor"/> by reading document parts into memory.
        /// </summary>
        /// <param name="result">
        /// The file to which changes can be saved.
        /// </param>
        /// <exception cref="ArgumentNullException"/>
        public OpenXmlVisitor([NotNull] DocxFilePath result)
        {
            if (result is null)
            {
                throw new ArgumentNullException(nameof(result));
            }

            ContentTypes =
                result.ReadAsXml(ContentTypesInfo.Path) ?? throw new FileNotFoundException(ContentTypesInfo.Path);

            Document =
                result.ReadAsXml() ?? throw new FileNotFoundException("word/document.xml");

            DocumentRelations =
                result.ReadAsXml(DocumentRelsInfo.Path) ?? throw new FileNotFoundException(DocumentRelsInfo.Path);

            Footnotes =
                result.ReadAsXml("word/footnotes.xml") ?? new XElement(W + "footnotes");

            FootnoteRelations =
                result.ReadAsXml("word/_rels/footnotes.xml.rels") ?? new XElement(P + "Relationships");

            Styles =
                result.ReadAsXml("word/styles.xml") ?? throw new FileNotFoundException("word/styles.xml");

            Numbering =
                result.ReadAsXml("word/numbering.xml");

            Theme1 =
                result.ReadAsXml("word/theme/theme1.xml");

            if (Numbering is null)
            {
                Numbering = new XElement(W + "numbering");

                DocumentRelations =
                    new XElement(
                        DocumentRelations.Name,
                        DocumentRelations.Attributes(),
                        DocumentRelations.Elements()
                        .Where(x => !x.Attribute("Tartget")?.Value.Equals("numbering.xml", StringComparison.OrdinalIgnoreCase) ?? true),
                        new XElement(
                            P + "Relationship",
                            new XAttribute("Id", $"rId{NextDocumentRelationId}"),
                            new XAttribute("Type", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering"),
                            new XAttribute("Target", "numbering.xml")));

                ContentTypes =
                    new XElement(
                        ContentTypes.Name,
                        ContentTypes.Attributes(),
                        ContentTypes.Elements()
                        .Where(x => !x.Attribute("PartName")?.Value.Equals("/word/numbering.xml", StringComparison.OrdinalIgnoreCase) ?? true),
                        new XElement(T + "Override",
                                     new XAttribute("PartName", "/word/numbering.xml"),
                                     new XAttribute("ContentType", "application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml")));
            }

            Charts =
                result.ReadAsXml(DocumentRelsInfo.Path)
                .Elements()
                .Select(x => x.Attribute("Target")?.Value)
                .Where(x => x?.StartsWith("charts/") ?? false)
                .Select(x => new ChartInformation(x, result.ReadAsXml($"word/{x}")))
                .ToImmutableList();
        }
 /// <inheritdoc />
 /// <summary>
 /// Initializes an <see cref="T:AD.OpenXml.Visitors.OpenXmlVisitor" /> by reading document parts into memory from a default <see cref="MemoryStream"/>.
 /// </summary>
 public OpenXmlVisitor() : this(DocxFilePath.Create())
 {
 }