Esempio n. 1
0
        public void GenerateAndAppendTemplate(MemoryStream template, IDictionary <string, string> values, int idx)
        {
            try
            {
                Logger.Info($"Filling template for row {idx}.");
                using (WordprocessingDocument templateDoc = WordprocessingDocument.Open(template, true))
                {
                    OpenXmlPartRootElement root = templateDoc.MainDocumentPart.RootElement;

                    // TODO: Set text here as well so Update Fields doesn't need to be run.
                    foreach (SimpleField field in root.Descendants <SimpleField>())
                    {
                        Logger.Info($"Handling SimpleField of instruction: {field.Instruction.Value}.");
                        var(newInstruction, oldKey, newPropName) = TransformFieldProperty(field.Instruction.Value, idx);
                        field.Instruction.Value = newInstruction;

                        string value = null;
                        if (!values.TryGetValue(oldKey, out value))
                        {
                            throw new DocumentWriterException($"No key found for {oldKey}");
                        }

                        if (string.IsNullOrWhiteSpace(value))
                        {
                            Logger.Warn($"An entry exists for key {oldKey}, but the resulting value is blank");
                        }

                        AddCustomProperty(newPropName, value);
                    }

                    // TODO: Make more robust... FieldCodes are far more complex than this.
                    // See the ECMA standard for 2.16.18.
                    foreach (FieldCode field in root.Descendants <FieldCode>())
                    {
                        Logger.Info($"Handling FieldCode of text: {field.Text}.");
                        var(newInstruction, oldKey, newPropName) = TransformFieldProperty(field.Text, idx);
                        field.Text = newInstruction;

                        if (!values.TryGetValue(oldKey, out string value))
                        {
                            throw new DocumentWriterException($"No key found for {oldKey}");
                        }

                        if (string.IsNullOrWhiteSpace(value))
                        {
                            Logger.Warn($"An entry exists for key {oldKey}, but the resulting value is blank.");
                        }

                        AddCustomProperty(newPropName, value);
                    }
                }

                sources.Add(new Source(new WmlDocument(template.Length.ToString(), template), true));
            }
            catch (Exception ex)
            {
                Logger.Fatal(ex, "An error occurred while filling template.");
                throw ex;
            }
        }
Esempio n. 2
0
        /// <summary>
        /// Returns all block contained into the container given in argument.
        /// </summary>
        /// <param name="container">Container where the block items will be found.</param>
        /// <returns>All block contained into the container given in argument.</returns>
        protected override List <BlockItem> GetBlocks(OpenXmlPartContainer container)
        {
            OpenXmlPartRootElement rootContainer = GetRootContainer(container);
            var blocks = rootContainer.Descendants <SdtElement>()
                         .Select(_ => new BlockItem
            {
                OxpBlock  = _,
                XBlock    = XElement.Parse(_.OuterXml),
                Container = container
            })
                         .ToList();
            var addblocks = rootContainer.Descendants <DocProperties>()
                            .Where(_ => null != _.Description &&
                                   _.Description.HasValue &&
                                   !string.IsNullOrWhiteSpace(_.Description.Value) &&
                                   (_.Parent.Parent is Drawing || _.Parent.Parent is Table))
                            .Select(_ => new BlockItem
            {
                OxpBlock  = _.Parent.Parent,
                XBlock    = XElement.Parse(_.Parent.Parent.OuterXml),
                Container = container
            })
                            .ToList();;

            blocks.AddRange(addblocks);
            return(blocks);
        }
Esempio n. 3
0
        static string ProcessDocxPart(OpenXmlPartRootElement part)
        {
            string s = "";

            foreach (var p in part.Descendants <Paragraph>())
            {
                s += p.InnerText + "\n";
            }
            return(s);
        }
        /// <summary>
        /// Bind the content controls (w:sdt elements) contained in the content part's XML document to the
        /// custom XML part identified by the given storeItemId.
        /// </summary>
        /// <param name="contentRootElement">The content part's <see cref="OpenXmlPartRootElement" />.</param>
        /// <param name="customXmlRootElement">The custom XML part's root <see cref="XElement" />.</param>
        /// <param name="storeItemId">The w:storeItemId to be used for data binding.</param>
        public static void BindContentControls(OpenXmlPartRootElement contentRootElement,
                                               XElement customXmlRootElement, string storeItemId)
        {
            if (contentRootElement == null)
            {
                throw new ArgumentNullException("contentRootElement");
            }
            if (customXmlRootElement == null)
            {
                throw new ArgumentNullException("customXmlRootElement");
            }
            if (storeItemId == null)
            {
                throw new ArgumentNullException("storeItemId");
            }

            // Get all w:sdt elements with matching tags.
            var tags = customXmlRootElement.Descendants()
                       .Where(e => !e.HasElements)
                       .Select(e => e.Name.LocalName);
            var sdts = contentRootElement.Descendants <SdtElement>()
                       .Where(sdt => sdt.SdtProperties.GetFirstChild <Tag>() != null &&
                              tags.Contains(sdt.SdtProperties.GetFirstChild <Tag>().Val.Value));

            foreach (var sdt in sdts)
            {
                // The tag value is supposed to point to a descendant element of the custom XML
                // part's root element.
                var childElementName = sdt.SdtProperties.GetFirstChild <Tag>().Val.Value;
                var leafElement      = customXmlRootElement.Descendants()
                                       .First(e => e.Name.LocalName == childElementName);

                // Define the list of path elements, using one of the following two options:
                // 1. The following statement is used as the basis for building the full path
                // expression (the same as built by Microsoft Word).
                var pathElements = leafElement.AncestorsAndSelf().Reverse().ToList();

                // 2. The following statement is used as the basis for building the short xPath
                // expression "//ns0:leafElement[1]".
                // List<XElement> pathElements = new List<XElement>() { leafElement };

                // Build list of namespace names for building the prefix mapping later on.
                var nsList = pathElements
                             .Where(e => e.Name.Namespace != XNamespace.None)
                             .Aggregate(new HashSet <string>(), (set, e) => set.Append(e.Name.NamespaceName))
                             .ToList();

                // Build mapping from local names to namespace indices.
                var nsDict = pathElements
                             .ToDictionary(e => e.Name.LocalName, e => nsList.IndexOf(e.Name.NamespaceName));

                // Build prefix mappings.
                var prefixMappings = nsList.Select((ns, index) => new { ns, index })
                                     .Aggregate(new StringBuilder(), (sb, t) =>
                                                sb.Append("xmlns:ns").Append(t.index).Append("='").Append(t.ns).Append("' "))
                                     .ToString().Trim();

                // Build xPath, assuming we will always take the first element and using one
                // of the following two options (see above):
                // 1. The following statement defines the prefix for building a full path
                // expression "/ns0:path[1]/ns0:to[1]/ns0:leafElement[1]".
                Func <string, string> prefix = localName =>
                                               nsDict[localName] >= 0 ? "/ns" + nsDict[localName] + ":" : "/";

                // 2. The following statement defines the prefix for building the short path
                // expression "//ns0:leafElement[1]".
                // Func<string, string> prefix = localName =>
                //     nsDict[localName] >= 0 ? "//ns" + nsDict[localName] + ":" : "//";

                var xPath = pathElements
                            .Select(e => prefix(e.Name.LocalName) + e.Name.LocalName + "[1]")
                            .Aggregate(new StringBuilder(), (sb, pc) => sb.Append(pc)).ToString();

                // Create and configure new data binding.
                var dataBinding = new DataBinding();
                if (!String.IsNullOrEmpty(prefixMappings))
                {
                    dataBinding.PrefixMappings = prefixMappings;
                }
                dataBinding.XPath       = xPath;
                dataBinding.StoreItemId = storeItemId;

                // Add or replace data binding.
                var currentDataBinding = sdt.SdtProperties.GetFirstChild <DataBinding>();
                if (currentDataBinding != null)
                {
                    sdt.SdtProperties.ReplaceChild(dataBinding, currentDataBinding);
                }
                else
                {
                    sdt.SdtProperties.Append(dataBinding);
                }
            }
        }