示例#1
0
        /// <summary>
        /// Create a DateField from the Document Object Model.
        /// </summary>
        /// <param name="fieldStart">The starting node in the DOM from which the DateField is constructed.</param>
        public DateField(FieldStart fieldStart)
            : base(fieldStart)
        {
            // Extract from the entire text of the field from the 'Run' nodes in the DOM.  The field seperator divides the text of the merge field from the
            // current contents of that merged field, otherwise the end of the field is used as the delimiter.
            String fieldText = String.Empty;

            for (Node node = this.FieldStart; node.NodeType != NodeType.FieldSeparator && node.NodeType != NodeType.FieldEnd; node = node.NextSibling)
            {
                if (node.NodeType == NodeType.Run)
                {
                    fieldText += ((Run)node).Text;
                }
            }

            // A regular expression is used to extract the name of the data element referenced by this DateField.
            Match match = DateField.dateExpression.Match(fieldText);

            // The default formatting is to use the native format for the data type.  This can be overridden with additional codes in the merge field.
            this.format = "{0}";

            // The field can have explicit formatting.  This will pull the format out of the DATE field.
            Group dateFormat = match.Groups["dateFormat"];

            if (dateFormat.Success)
            {
                this.format = String.Format("{{0:{0}}}", dateFormat.Value);
            }
        }
示例#2
0
            internal Hyperlink(FieldStart fieldStart)
            {
                if (fieldStart == null)
                {
                    throw new ArgumentNullException("fieldStart");
                }
                if (!fieldStart.FieldType.Equals(FieldType.FieldHyperlink))
                {
                    throw new ArgumentException("Field start type must be FieldHyperlink.");
                }

                mFieldStart = fieldStart;

                // Find the field separator node.
                mFieldSeparator = fieldStart.GetField().Separator;
                if (mFieldSeparator == null)
                {
                    throw new InvalidOperationException("Cannot find field separator.");
                }

                mFieldEnd = fieldStart.GetField().End;

                // Field code looks something like [ HYPERLINK "http:\\www.myurl.com" ], but it can consist of several runs.
                string fieldCode = fieldStart.GetField().GetFieldCode();
                Match  match     = gRegex.Match(fieldCode.Trim());

                mIsLocal = (match.Groups[1].Length > 0);    //The link is local if \l is present in the field code.
                mTarget  = match.Groups[2].Value;
            }
        internal Hyperlink(FieldStart fieldStart)
        {
            if (fieldStart == null)
            {
                throw new ArgumentNullException("fieldStart");
            }
            if (!fieldStart.FieldType.Equals(FieldType.FieldHyperlink))
            {
                throw new ArgumentException("Field start type must be FieldHyperlink.");
            }

            mFieldStart = fieldStart;

            // Find the field separator node
            mFieldSeparator = FindNextSibling(mFieldStart, NodeType.FieldSeparator);
            if (mFieldSeparator == null)
            {
                throw new InvalidOperationException("Cannot find field separator.");
            }

            // Find the field end node. Normally field end will always be found, but in the example document
            // there happens to be a paragraph break included in the hyperlink and this puts the field end
            // in the next paragraph. It will be much more complicated to handle fields which span several
            // paragraphs correctly, but in this case allowing field end to be null is enough for our purposes
            mFieldEnd = FindNextSibling(mFieldSeparator, NodeType.FieldEnd);

            // Field code looks something like [ HYPERLINK "http:\\www.myurl.com" ], but it can consist of several runs
            string fieldCode = GetTextSameParent(mFieldStart.NextSibling, mFieldSeparator);
            Match  match     = gRegex.Match(fieldCode.Trim());

            mIsLocal = match.Groups[1].Length > 0; //The link is local if \l is present in the field code
            mTarget  = match.Groups[2].Value;
        }
示例#4
0
        public static void ExtractContentUsingField()
        {
            //ExStart
            //ExFor:DocumentBuilder.MoveToMergeField(String, Boolean, Boolean)
            //ExId:ExtractBetweenNodes_UsingField
            //ExSummary:Shows how to extract content between a specific field and paragraph in the document using the ExtractContent method.
            // Load in the document
            Document doc = new Document(mDataDir + "TestFile.doc");

            // Use a document builder to retrieve the field start of a merge field.
            DocumentBuilder builder = new DocumentBuilder(doc);

            // Pass the first boolean parameter to get the DocumentBuilder to move to the FieldStart of the field.
            // We could also get FieldStarts of a field using GetChildNode method as in the other examples.
            builder.MoveToMergeField("Fullname", false, false);

            // The builder cursor should be positioned at the start of the field.
            FieldStart startField = (FieldStart)builder.CurrentNode;
            Paragraph  endPara    = (Paragraph)doc.FirstSection.GetChild(NodeType.Paragraph, 5, true);

            // Extract the content between these nodes in the document. Don't include these markers in the extraction.
            ArrayList extractedNodes = ExtractContent(startField, endPara, false);

            // Insert the content into a new separate document and save it to disk.
            Document dstDoc = GenerateDocument(doc, extractedNodes);

            dstDoc.Save(mDataDir + "TestFile.Fields Out.pdf");
            //ExEnd
        }
示例#5
0
        public static void Run()
        {
            //ExStart:ExtractContentUsingField
            // The path to the documents directory.
            string   dataDir  = RunExamples.GetDataDir_WorkingWithDocument();
            string   fileName = "TestFile.doc";
            Document doc      = new Document(dataDir + fileName);

            // Use a document builder to retrieve the field start of a merge field.
            DocumentBuilder builder = new DocumentBuilder(doc);

            // Pass the first boolean parameter to get the DocumentBuilder to move to the FieldStart of the field.
            // We could also get FieldStarts of a field using GetChildNode method as in the other examples.
            builder.MoveToMergeField("Fullname", false, false);

            // The builder cursor should be positioned at the start of the field.
            FieldStart startField = (FieldStart)builder.CurrentNode;
            Paragraph  endPara    = (Paragraph)doc.FirstSection.GetChild(NodeType.Paragraph, 5, true);

            // Extract the content between these nodes in the document. Don't include these markers in the extraction.
            ArrayList extractedNodes = Common.ExtractContent(startField, endPara, false);

            // Insert the content into a new separate document and save it to disk.
            Document dstDoc = Common.GenerateDocument(doc, extractedNodes);

            dataDir = dataDir + RunExamples.GetOutputFilePath(fileName);
            dstDoc.Save(dataDir);
            //ExEnd:ExtractContentUsingField
            Console.WriteLine("\nExtracted content using the Field successfully.\nFile saved at " + dataDir);
        }
示例#6
0
        internal MergeField(FieldStart fieldStart)
        {
            if (fieldStart.Equals(null))
            {
                throw new ArgumentNullException("fieldStart");
            }
            if (!fieldStart.FieldType.Equals(FieldType.FieldMergeField))
            {
                throw new ArgumentException("Field start type must be FieldMergeField.");
            }

            mFieldStart = fieldStart;

            // Find the field separator node.
            mFieldSeparator = FindNextSibling(mFieldStart, NodeType.FieldSeparator);
            if (mFieldSeparator == null)
            {
                throw new InvalidOperationException("Cannot find field separator.");
            }

            // Find the field end node. Normally field end will always be found, but in the example document
            // there happens to be a paragraph break included in the hyperlink and this puts the field end
            // in the next paragraph. It will be much more complicated to handle fields which span several
            // paragraphs correctly, but in this case allowing field end to be null is enough for our purposes.
            mFieldEnd = FindNextSibling(mFieldSeparator, NodeType.FieldEnd);
        }
        internal Hyperlink(FieldStart fieldStart)
        {
            if (fieldStart == null)
            {
                throw new ArgumentNullException("fieldStart");
            }
            if (fieldStart.FieldType != FieldType.FieldHyperlink)
            {
                throw new ArgumentException("Field start type must be FieldHyperlink.");
            }

            mFieldStart = fieldStart;

            // Find the field separator node.
            mFieldSeparator = FindNextSibling(mFieldStart, NodeType.FieldSeparator);
            if (mFieldSeparator == null)
            {
                throw new InvalidOperationException("Cannot find field separator.");
            }

            // Normally, we can always find the field's end node, but the example document
            // contains a paragraph break inside a hyperlink, which puts the field end
            // in the next paragraph. It will be much more complicated to handle fields which span several
            // paragraphs correctly. In this case allowing field end to be null is enough.
            mFieldEnd = FindNextSibling(mFieldSeparator, NodeType.FieldEnd);

            // Field code looks something like "HYPERLINK "http:\\www.myurl.com"", but it can consist of several runs.
            string fieldCode = GetTextSameParent(mFieldStart.NextSibling, mFieldSeparator);
            Match  match     = gRegex.Match(fieldCode.Trim());

            // The hyperlink is local if \l is present in the field code.
            mIsLocal = match.Groups[1].Length > 0;
            mTarget  = match.Groups[2].Value;
        }
        public Hyperlink(FieldStart fieldStart)
        {
            if (fieldStart == null)
                throw new ArgumentNullException("fieldStart");
            if (fieldStart.FieldType != FieldType.FieldHyperlink)
                throw new ArgumentException("Field start type must be FieldHyperlink.");

            mFieldStart = fieldStart;

            // Find field separator node.
            mFieldSeparator = FindNextSibling(mFieldStart, NodeType.FieldSeparator);
            if (mFieldSeparator == null)
                throw new Exception("Cannot find field separator.");

            // Find field end node. Normally field end will always be found, but in the example document
            // there happens to be a paragraph break included in the hyperlink and this puts the field end
            // in the next paragraph. It will be much more complicated to handle fields which span several
            // paragraphs correctly, but in this case allowing field end to be null is enough for our purposes.
            mFieldEnd = FindNextSibling(mFieldSeparator, NodeType.FieldEnd);

            // Field code looks something like [ HYPERLINK "http:\\www.myurl.com" ], but it can consist of several runs.
            string fieldCode = GetTextSameParent(mFieldStart.NextSibling, mFieldSeparator);
            Match match = gRegex.Match(fieldCode.Trim());
            mIsLocal = (match.Groups[1].Length > 0);        // The link is local if \l is present in the field code.
            mTarget = match.Groups[2].Value;
        }
        private static string GetDocumentVariableFromField(FieldStart fieldStart)
        {
            var nextSibling = (Run)fieldStart.NextSibling;
            var runText     = nextSibling.Text;
            int lengthOfDocumentVariablePrefix = DocumentVariablePrefix.Length;

            return(runText.Substring(lengthOfDocumentVariablePrefix + 1).Trim());
        }
示例#10
0
            /// <summary>
            /// Called when a FieldStart node is encountered in the document.
            /// </summary>
            public override VisitorAction VisitFieldStart(FieldStart fieldStart)
            {
                IndentAndAppendLine("[Field start] FieldType: " + fieldStart.FieldType);
                mDocTraversalDepth++;
                mVisitorIsInsideField = true;

                return(VisitorAction.Continue);
            }
示例#11
0
 private static string GetText(FieldStart start, string code, FieldSeparator separator = null, string result = null, FieldEnd end = null, bool useRawFieldChars = false)
 {
     return string.Format("{0}{1}{2}{3}{4}",
         start != null ? useRawFieldChars ? FieldStart : "{" : "",
         code ?? "",
         separator != null ? useRawFieldChars ? FieldSeparator : "|" : "",
         result ?? "",
         end != null ? useRawFieldChars ? FieldEnd : "}" : "");
 }
示例#12
0
        /// <summary>
        /// Create a hierarchical group of nodes from the start of the field.
        /// </summary>
        /// <param name="fieldStart">The node which represents the start of a field.</param>
        public WordField(FieldStart fieldStart)
        {
            // Create the object.
            this.endDictionary   = new Dictionary <Node, WordField>();
            this.startDictionary = new Dictionary <Node, WordField>();
            this.fieldStart      = fieldStart;

            // This will find the end of the field and acts as a kind of delimiter.  Since the DOM structure makes heavy use of linked lists, it can also act
            // to join the end of a field to the start and back again when navigating through the document.
            Boolean parsing = true;
            Node    node    = this.fieldStart.NextSibling;

            while (parsing)
            {
                // This is the field that is going to be parsed out of the stream.
                WordField wordField = default(WordField);

                // Each node is parsed to determine what kind of an object has been discovered here.
                switch (node.NodeType)
                {
                case NodeType.FieldStart:

                    // This will recurse into any of the embedded fields creating a hierarchical order of fields that can be evaluated from the inside out.
                    wordField = CreateField(node as FieldStart);

                    // Any field found in the field field result area is ignored.  All other fields are added to a collection that can be indexed sequentially
                    // using an enumerator or directly using the dictionary.
                    this.startDictionary.Add(wordField.FieldStart, wordField);
                    this.endDictionary.Add(wordField.FieldEnd, wordField);

                    // This moves the parser to the position after the field no matter how many levels of embedded fields were included.
                    node = wordField.FieldEnd;

                    break;

                case NodeType.FieldSeparator:

                    // This indicates where the literal portion of a field starts.
                    this.fieldSeperator = node as FieldSeparator;

                    break;

                case NodeType.FieldEnd:

                    // The end of the field is part of this obect and used when navigating forward or backward through the nodes of a paragraph.
                    this.fieldEnd = node as FieldEnd;

                    // When the final field is found the parsing of this field is completed.
                    parsing = false;

                    break;
                }

                // The parsing continues until the last field node is discovered.
                node = node.NextSibling;
            }
        }
示例#13
0
            /// <summary>
            /// Called when a FieldStart node is encountered in the document.
            /// </summary>
            public override VisitorAction VisitFieldStart(FieldStart fieldStart)
            {
                // If this node is hidden, then remove it.
                if (this.isHidden(fieldStart))
                {
                    fieldStart.Remove();
                }

                return(VisitorAction.Continue);
            }
示例#14
0
            /// <summary>
            /// Called when a FieldStart node is encountered in the document.
            /// </summary>
            public override VisitorAction VisitFieldStart(FieldStart fieldStart)
            {
                // In Microsoft Word, a field code (such as "MERGEFIELD FieldName") follows
                // after a field start character. We want to skip field codes and output field.
                // Result only, therefore we use a flag to suspend the output while inside a field code.
                // Note this is a very simplistic implementation and will not work very well.
                // If you have nested fields in a document.
                mIsSkipText = true;

                return(VisitorAction.Continue);
            }
示例#15
0
 /// <summary>
 /// Create an inline field for the given field start node.
 /// </summary>
 public static InlineField Create(FieldStart start)
 {
     switch (start.FieldType)
     {
         case FieldType.FieldMergeField:
             return new MergeField(start);
         case FieldType.FieldHyperlink:
             return new HyperlinkField(start);
         default:
             return new InlineField(start);
     }
 }
            /// <summary>
            /// Called when a FieldStart node is encountered in the document.
            /// </summary>
            public override VisitorAction VisitFieldStart(FieldStart fieldStart)
            {
                // In Microsoft Word, a field code (such as "MERGEFIELD FieldName") follows
                // After a field start character. We want to skip field codes and output field 
                // Result only, therefore we use a flag to suspend the output while inside a field code.
                //
                // Note this is a very simplistic implementation and will not work very well
                // If you have nested fields in a document. 
                mIsSkipText = true;

                return VisitorAction.Continue;
            }
示例#17
0
        /// <summary>
        /// Attempt to create an inline field for the given start field.
        /// </summary>
        public static bool TryParse(FieldStart start, out InlineField field)
        {
            var end = FindMatchingEnd(start);

            if (end != null)
            {
                field = Create(start);
                return true;
            }

            field = null;
            return false;
        }
示例#18
0
        /// <summary>
        /// Attempts to parse a field, starting at the given field start node, as a hyperlink field.
        /// </summary>
        public static bool TryParse(FieldStart start, out HyperlinkField field)
        {
            if (start.FieldType == FieldType.FieldHyperlink)
            {
                InlineField inlineField;
                if (InlineField.TryParse(start, out inlineField))
                {
                    field = (HyperlinkField)inlineField;
                    return true;
                }
            }

            field = null;
            return false;
        }
        private static string GetFieldCode(FieldStart fieldStart)
        {
            StringBuilder builder = new StringBuilder();

            for (Node node = fieldStart; node != null && node.NodeType != NodeType.FieldSeparator &&
                 node.NodeType != NodeType.FieldEnd; node = node.NextPreOrder(node.Document))
            {
                // Use text only of Run nodes to avoid duplication.
                if (node.NodeType == NodeType.Run)
                {
                    builder.Append(node.GetText());
                }
            }
            return(builder.ToString());
        }
        public override VisitorAction VisitFieldStart(FieldStart fieldStart)
        {
            // We must keep track of the starts and ends of fields incase of any nested fields.
            if (fieldStart.FieldType.Equals(mTargetFieldType))
            {
                mFieldDepth++;
                fieldStart.Remove();
            }
            else
            {
                // This removes the field start if it's inside a field that is being converted.
                CheckDepthAndRemoveNode(fieldStart);
            }

            return VisitorAction.Continue;
        }
示例#21
0
        public override VisitorAction VisitFieldStart(FieldStart fieldStart)
        {
            // We must keep track of the starts and ends of fields incase of any nested fields.
            if (fieldStart.FieldType.Equals(mTargetFieldType))
            {
                mFieldDepth++;
                fieldStart.Remove();
            }
            else
            {
                // This removes the field start if it's inside a field that is being converted.
                CheckDepthAndRemoveNode(fieldStart);
            }

            return(VisitorAction.Continue);
        }
            internal MergeField(FieldStart fieldStart)
            {
                if (fieldStart.Equals(null))
                    throw new ArgumentNullException("fieldStart");
                if (!fieldStart.FieldType.Equals(FieldType.FieldMergeField))
                    throw new ArgumentException("Field start type must be FieldMergeField.");

                mFieldStart = fieldStart;

                // Find the field separator node.
                mFieldSeparator = fieldStart.GetField().Separator;
                if (mFieldSeparator == null)
                    throw new InvalidOperationException("Cannot find field separator.");

                mFieldEnd = fieldStart.GetField().End;
            }
        private static void RemoveField(FieldStart fieldStart)
        {
            Node currentNode = fieldStart;
            bool isRemoving  = true;

            while (currentNode != null && isRemoving)
            {
                if (currentNode.NodeType == NodeType.FieldEnd)
                {
                    isRemoving = false;
                }

                Node nextNode = currentNode.NextPreOrder(currentNode.Document);
                currentNode.Remove();
                currentNode = nextNode;
            }
        }
示例#24
0
        /// <summary>
        /// Create a MergeField from the Document Object Model.
        /// </summary>
        /// <param name="fieldStart">The starting node in the DOM from which the MergeField is constructed.</param>
        public MergeField(FieldStart fieldStart)
            : base(fieldStart)
        {
            // Extract from the entire text of the field from the 'Run' nodes in the DOM.  The field seperator divides the text of the merge field from the
            // current contents of that merged field, otherwise the end of the field is used as the delimiter.
            String fieldText = String.Empty;

            for (Node node = this.FieldStart; node.NodeType != NodeType.FieldSeparator && node.NodeType != NodeType.FieldEnd; node = node.NextSibling)
            {
                if (node.NodeType == NodeType.Run)
                {
                    fieldText += ((Run)node).Text;
                }
            }

            // A regular expression is used to extract the name of the data element referenced by this MergeField.
            Match match = MergeField.mergeExpression.Match(fieldText);

            // The reference is the name of the field.  This name is cross referenced to the data dictionary when looking up values during a mail merge.
            Group referenceGroup = match.Groups["reference"];

            this.reference = referenceGroup.Success ? referenceGroup.Value : String.Empty;

            // The default formatting is to use the native format for the data type.  This can be overridden with additional codes in the merge field.
            this.format = "{0}";

            // The default formatting for numbers can be overridden with the number format syntax.
            Group numberFormatGroup = match.Groups["numberFormat"];

            if (numberFormatGroup.Success)
            {
                this.format = String.Format("{{0:{0}}}", numberFormatGroup.Value);
            }

            // The default formatting for dates and times can be overridden with the date format syntax.
            Group dateFormatGroup = match.Groups["dateFormat"];

            if (dateFormatGroup.Success)
            {
                this.format = String.Format("{{0:{0}}}", dateFormatGroup.Value);
            }
        }
        internal MergeField(FieldStart fieldStart)
        {
            if (fieldStart.Equals(null))
                throw new ArgumentNullException("fieldStart");
            if (!fieldStart.FieldType.Equals(FieldType.FieldMergeField))
                throw new ArgumentException("Field start type must be FieldMergeField.");

            this.mFieldStart = fieldStart;

            // Find the field separator node.
            this.mFieldSeparator = FindNextSibling(this.mFieldStart, NodeType.FieldSeparator);
            if (this.mFieldSeparator == null)
                throw new InvalidOperationException("Cannot find field separator.");

            // Find the field end node. Normally field end will always be found, but in the example document 
            // there happens to be a paragraph break included in the hyperlink and this puts the field end 
            // in the next paragraph. It will be much more complicated to handle fields which span several 
            // paragraphs correctly, but in this case allowing field end to be null is enough for our purposes.
            this.mFieldEnd = FindNextSibling(this.mFieldSeparator, NodeType.FieldEnd);
        }
示例#26
0
        public void GetFieldFromDocument()
        {
            //ExStart
            //ExFor:FieldChar.GetField
            //ExId:GetField
            //ExSummary:Demonstrates how to retrieve the field class from an existing FieldStart node in the document.
            Aspose.Words.Document doc = new Aspose.Words.Document(MyDir + "Document.TableOfContents.doc");

            FieldStart fieldStart = (FieldStart)doc.GetChild(NodeType.FieldStart, 0, true);

            // Retrieve the facade object which represents the field in the document.
            Field field = fieldStart.GetField();

            Console.WriteLine("Field code:" + field.GetFieldCode());
            Console.WriteLine("Field result: " + field.Result);
            Console.WriteLine("Is locked: " + field.IsLocked);

            // This updates only this field in the document.
            field.Update();
            //ExEnd
        }
示例#27
0
            internal MergeField(FieldStart fieldStart)
            {
                if (fieldStart.Equals(null))
                {
                    throw new ArgumentNullException("fieldStart");
                }
                if (!fieldStart.FieldType.Equals(FieldType.FieldMergeField))
                {
                    throw new ArgumentException("Field start type must be FieldMergeField.");
                }

                mFieldStart = fieldStart;

                // Find the field separator node.
                mFieldSeparator = fieldStart.GetField().Separator;
                if (mFieldSeparator == null)
                {
                    throw new InvalidOperationException("Cannot find field separator.");
                }

                mFieldEnd = fieldStart.GetField().End;
            }
示例#28
0
        public void ExtractContentUsingField()
        {
            //ExStart:ExtractContentUsingField
            Document        doc     = new Document(MyDir + "Extract content.docx");
            DocumentBuilder builder = new DocumentBuilder(doc);

            // Pass the first boolean parameter to get the DocumentBuilder to move to the FieldStart of the field.
            // We could also get FieldStarts of a field using GetChildNode method as in the other examples.
            builder.MoveToMergeField("Fullname", false, false);

            // The builder cursor should be positioned at the start of the field.
            FieldStart startField = (FieldStart)builder.CurrentNode;
            Paragraph  endPara    = (Paragraph)doc.FirstSection.GetChild(NodeType.Paragraph, 5, true);

            // Extract the content between these nodes in the document. Don't include these markers in the extraction.
            ArrayList extractedNodes = ExtractContentHelper.ExtractContent(startField, endPara, false);

            Document dstDoc = ExtractContentHelper.GenerateDocument(doc, extractedNodes);

            dstDoc.Save(ArtifactsDir + "ExtractContent.ExtractContentUsingField.docx");
            //ExEnd:ExtractContentUsingField
        }
        public override VisitorAction VisitFieldStart(FieldStart fieldStart)
        {
            if (fieldStart.FieldType == FieldType.FieldDocProperty)
            {
                this.currentDocumentProperty = GetDocumentPropertyFromField(fieldStart);
                this.currentFieldTagName     = GetXmlTagForDocumentProperty(this.currentDocumentProperty);

                this.structureBuilder
                .AppendFormat(
                    "<{0} {1} />",
                    this.currentFieldTagName + "Start",
                    FormatAttributes(new NamedValue("Name", HttpUtility.HtmlEncode(this.currentDocumentProperty))))
                .AppendLine();

                this.skipRun = true;
            }
            else if (fieldStart.FieldType == FieldType.FieldDocVariable)
            {
                this.currentDocumentVariable = GetDocumentVariableFromField(fieldStart);
                this.currentFieldTagName     = "DocumentVariable";

                this.structureBuilder
                .AppendFormat(
                    "<{0} {1} />",
                    this.currentFieldTagName + "Start",
                    FormatAttributes(new NamedValue("Name", HttpUtility.HtmlEncode(this.currentDocumentVariable))))
                .AppendLine();

                this.skipRun = true;
            }
            else
            {
                this.structureBuilder.AppendLine("<FieldStart />");
            }

            return(VisitorAction.Continue);
        }
示例#30
0
        /// <summary>
        /// Creates a strongly-typed field from the tokens in the WordProcessing DOM.
        /// </summary>
        /// <param name="fieldStart">The starting point for the field.</param>
        /// <returns>A strongly typed field based on the tokens found in the stream.</returns>
        public static WordField CreateField(FieldStart fieldStart)
        {
            // This is what is created if the type isn't recognized.
            WordField wordField = default(WordField);

            // The field type indicates what parser is used to evaluate the field.
            switch (fieldStart.FieldType)
            {
            case FieldType.FieldDate:

                // Create a new 'DATE' field.
                wordField = new DateField(fieldStart);
                break;

            case FieldType.FieldIf:

                // Create a new 'IF' field.
                wordField = new IfField(fieldStart);
                break;

            case FieldType.FieldMergeField:

                // Create a new 'MERGEFIELD' field.
                wordField = new MergeField(fieldStart);
                break;

            default:

                // All other fields are unhandled but parsed.
                wordField = new UnhandledField(fieldStart);
                break;
            }

            // This is a generic field that can be evaluated.
            return(wordField);
        }
示例#31
0
 internal MergeField(FieldStart start)
     : base(start)
 {
 }
        private static string GetDocumentVariableFromField(FieldStart fieldStart)
        {
            var nextSibling = fieldStart.NextSibling as Run;
            var runText = nextSibling.Text;
            int lengthOfDocumentVariablePrefix = DocumentVariablePrefix.Length;

            return runText.Substring(lengthOfDocumentVariablePrefix + 1).Trim();
        }
示例#33
0
 /// <summary>
 /// Creates a field not handled by the field evaluation logic.
 /// </summary>
 /// <param name="fieldstart">The start of the field.</param>
 public UnhandledField(FieldStart fieldstart) : base(fieldstart)
 {
 }
示例#34
0
        private static string ParseInlineResult(FieldStart start, string code, FieldSeparator separator, out Node lastNode)
        {
            var resultBuilder = new StringBuilder();

            lastNode = separator;

            foreach (var sibling in separator.GetFollowingSiblings().TakeWhile(n => !(n is FieldEnd)))
            {
                var run = sibling as Run;
                if (run != null)
                    resultBuilder.Append(run.GetText());
                else if (!(sibling is BookmarkStart) && !(sibling is BookmarkEnd))
                    throw new Exception(string.Format("Found unexpected node of type '{0}' after \"{1}\".", sibling.GetType().Name, GetText(start, code, separator, resultBuilder.ToString())));

                lastNode = sibling;
            }

            return resultBuilder.ToString();
        }
        private static string GetDocumentPropertyFromField(FieldStart fieldStart)
        {
            var nextSibling = (Run)fieldStart.NextSibling;
            var runText = nextSibling.Text;
            int lengthOfDocumentPropertyPrefix = DocumentPropertyPrefix.Length;

            return runText.Substring(lengthOfDocumentPropertyPrefix + 1).Trim();
        }
        /// <summary>
        /// Removes the Field from the document
        /// </summary>
        /// <param name="fieldStart">The field start node of the field to remove.</param>
        private static void RemoveField(FieldStart fieldStart)
        {
            Node currentNode = fieldStart;
            bool isRemoving = true;
            while (currentNode != null && isRemoving)
            {
                if (currentNode.NodeType == NodeType.FieldEnd)
                    isRemoving = false;

                Node nextNode = currentNode.NextPreOrder(currentNode.Document);
                currentNode.Remove();
                currentNode = nextNode;
            }
        }
示例#37
0
        private static string ParseInlineCode(FieldStart start, out Node lastNode)
        {
            var codeBuilder = new StringBuilder();

            lastNode = start;

            foreach (var sibling in start.GetFollowingSiblings().TakeWhile(n => !(n is FieldSeparator)))
            {
                var run = sibling as Run;
                if (run != null)
                    codeBuilder.Append(run.GetText());
                else
                    throw new Exception(string.Format("Found unexpected node of type '{0}' after \"{1}\".", sibling.GetType().Name, GetText(start, codeBuilder.ToString())));

                lastNode = sibling;
            }

            return codeBuilder.ToString();
        }
        public override VisitorAction VisitFieldStart(FieldStart fieldStart)
        {
            if (fieldStart.FieldType == FieldType.FieldDocProperty)
            {
                this.currentDocumentProperty = GetDocumentPropertyFromField(fieldStart);
                this.currentFieldTagName = GetXmlTagForDocumentProperty(this.currentDocumentProperty);
                this.structureBuilder.AppendLine(string.Concat("<", this.currentFieldTagName, "Start Name=\"", this.currentDocumentProperty, "\" />"));
                this.skipRun = true;
            }
            else if (fieldStart.FieldType == FieldType.FieldDocVariable)
            {
                this.currentDocumentVariable = GetDocumentVariableFromField(fieldStart);
                this.currentFieldTagName = "DocumentVariable";
                this.structureBuilder.AppendLine(string.Concat("<", this.currentFieldTagName, "Start Name=\"", this.currentDocumentVariable, "\" />"));
                this.skipRun = true;
            }
            else
            {
                this.structureBuilder.AppendLine("<Field>");
            }

            return VisitorAction.Continue;
        }
示例#39
0
            /// <summary>
            /// Called when a FieldStart node is encountered in the document.
            /// </summary>
            public override VisitorAction VisitFieldStart(FieldStart fieldStart)
            {
                // If this node is hidden, then remove it.
                if (isHidden(fieldStart))
                    fieldStart.Remove();

                return VisitorAction.Continue;
            }
示例#40
0
 /// <summary>
 /// Find the FieldEnd node that matches the field's start node.
 /// </summary>
 private static FieldEnd FindMatchingEnd(FieldStart start)
 {
     try
     {
         FieldEnd end;
         start.ParseInlineField(out end);
         return end;
     }
     catch
     {
         return null;
     }
 }
示例#41
0
        /// <summary>
        /// Determines if the given field start is the quote reference field and returns its field end if so.
        /// </summary>
        public static bool IsQuoteField(FieldStart start, out FieldEnd end)
        {
            if (start.FieldType != FieldType.FieldSet)
            {
                end = null;
                return false;
            }

            return start.ParseInlineField(out end).Trim() == "SET q \"\\\"\"";
        }
示例#42
0
 internal HyperlinkField(FieldStart start)
     : base(start)
 {
 }
        public override VisitorAction VisitFieldStart(FieldStart fieldStart)
        {
            if (fieldStart.FieldType == FieldType.FieldDocProperty)
            {
                this.currentDocumentProperty = GetDocumentPropertyFromField(fieldStart);
                this.currentFieldTagName = GetXmlTagForDocumentProperty(this.currentDocumentProperty);

                this.structureBuilder
                    .AppendFormat(
                        "<{0} {1} />",
                        this.currentFieldTagName + "Start",
                        FormatAttributes(new NamedValue("Name", HttpUtility.HtmlEncode(this.currentDocumentProperty))))
                    .AppendLine();

                this.skipRun = true;
            }
            else if (fieldStart.FieldType == FieldType.FieldDocVariable)
            {
                this.currentDocumentVariable = GetDocumentVariableFromField(fieldStart);
                this.currentFieldTagName = "DocumentVariable";

                this.structureBuilder
                    .AppendFormat(
                        "<{0} {1} />",
                        this.currentFieldTagName + "Start",
                        FormatAttributes(new NamedValue("Name", HttpUtility.HtmlEncode(this.currentDocumentVariable))))
                    .AppendLine();

                this.skipRun = true;
            }
            else
            {
                this.structureBuilder.AppendLine("<FieldStart />");
            }

            return VisitorAction.Continue;
        }
示例#44
0
 internal InlineField(FieldStart start)
 {
     Start = start;
 }
        //ExStart
        //ExFor:FieldStart
        //ExFor:FieldSeparator
        //ExFor:FieldEnd
        //ExId:AppendDocument_HelperFunctions
        //ExSummary:Provides some helper functions by the methods above
        /// <summary>
        /// Retrieves the field code from a field.
        /// </summary>
        /// <param name="fieldStart">The field start of the field which to gather the field code from</param>
        /// <returns></returns>
        private static string GetFieldCode(FieldStart fieldStart)
        {
            StringBuilder builder = new StringBuilder();

            for (Node node = fieldStart; node != null && node.NodeType != NodeType.FieldSeparator &&
                node.NodeType != NodeType.FieldEnd; node = node.NextPreOrder(node.Document))
            {
                // Use text only of Run nodes to avoid duplication.
                if (node.NodeType == NodeType.Run)
                    builder.Append(node.GetText());
            }
            return builder.ToString();
        }
示例#46
0
        /// <summary>
        /// Create the resources required for this instance.
        /// </summary>
        /// <param name="startNode"></param>
        public IfField(FieldStart startNode)
            : base(startNode)
        {
            // Initialize the object.
            this.falseExpression = new List <Node>();
            this.trueExpression  = new List <Node>();
            this.expression      = String.Empty;

            // The parser below will pull apart the various parts of the conditional statement.  The biggest issue is that the 'true' clause and the 'false'
            // clause contain a combination of Nodes which must be preserved exactly as they will become part of the document.  It is not enought to just extract
            // the text from these nodes, the fonts, paragraphs and styles and any other fields must be extracted as well.  Parsing nodes is difficult as the
            // various tokens can exist all in a single node, or be spread across several nodes.  These variables are used for parsing.  Note that parsinge starts
            // from the end of the statement and works towards the beginning.  This is because the 'true' and 'false' clauses are a fixed part of the syntax
            // and can be deterministically parsed using the quotes as tokens.  The rest of the statement -- the conditional expression -- is much more
            // difficult and requires a professional strength parser and analyzer.  The reason a RexEx function doesn't work here is because the values
            // extracted are in the form of CodeDOM Nodes and can't be tokenized.
            Int32 lastIndex  = default(Int32);
            Node  node       = this.FieldEnd.PreviousSibling;
            Run   run        = default(Run);
            Run   runClone   = default(Run);
            Int32 startIndex = -1;
            State state      = default(State);

            // The parsinge is constructed as a simple state machine.  There is no pushback or advanced expression evaluation performed in this section.  The
            // primary goal is to remove the nodes that will become the 'true' and 'false' expressions.  A full-blown expression evaluator will be called with
            // the part of the statement that remains after pulling out the clauses.
            while (state != State.Final)
            {
                switch (node.NodeType)
                {
                case NodeType.Run:

                    // Each of the run nodes can have a quote character which delineates the 'true' and 'false' clauses.  The 'startIndex' acts as a kind of
                    // cursor as the parser moves through each of the Run nodes.
                    run = node as Run;
                    if (startIndex == -1)
                    {
                        startIndex = run.Text.Length - 1;
                    }

                    // Once a Run node is recognized it is examined for tokens that delinate the clauses.  The state drives how each Run node is examined and
                    // determines what is trying to be extracted from each node.
                    switch (state)
                    {
                    case State.FieldResult:

                        // Just eat any Run nodes in the Field Result section of the field.  This moves the parser past the garbage -- the last evaluated data
                        // for this field -- and into the useful part of the field.
                        startIndex = -1;
                        node       = node.PreviousSibling;
                        break;

                    case State.FalseEndQuote:

                        // Look for the quote that finishes the 'False' clause.
                        lastIndex = run.Text.LastIndexOf('\"', startIndex);
                        if (lastIndex == -1)
                        {
                            // If the delimiter character can't be found then try the previous node.
                            startIndex = -1;
                        }
                        else
                        {
                            // If the delimiter is found then move the cursor into the body of the clause.
                            state      = State.FalseStatement;
                            startIndex = lastIndex - 1;
                        }

                        // move to the previous node when there is nothing left to parse in the current node until the delimiter is found.
                        if (startIndex == -1)
                        {
                            node = node.PreviousSibling;
                        }

                        break;

                    case State.FalseStatement:

                        // This will extract the body of the 'False' condition.  The next token that will cause a state change is the quote that opened this
                        // condition (remember we are parsing backwards).
                        lastIndex = run.Text.LastIndexOf('\"', startIndex);
                        if (lastIndex == -1)
                        {
                            // If there are no delimiters in the current run then clone it and copy the text up to the end quote (or the entire Run node if the
                            // end quote was in a previously parsed node).  There are times when the false clause is empty and an optimization removes any
                            // empty Run nodes.
                            String text = run.Text.Substring(0, startIndex + 1);
                            if (text != String.Empty)
                            {
                                runClone      = run.Clone(true) as Run;
                                runClone.Text = text;
                                this.falseExpression.Add(runClone);
                            }

                            // Since this node doesn't contain a delimiter, the state remains the same.  Continue parsing the next node for the start quote.
                            node       = node.PreviousSibling;
                            startIndex = -1;
                        }
                        else
                        {
                            // When an open quote is found we've come to the start of the false statement.  Copy any remaining text in the current Run node
                            // into the resulting clause.  The quotes will be removed but the rest of the text will be a literal copy of the text found in the
                            // document complete with all the formatting.
                            String text = run.Text.Substring(lastIndex + 1, startIndex - lastIndex);
                            if (runClone == null || runClone.Text != String.Empty)
                            {
                                runClone      = run.Clone(true) as Run;
                                runClone.Text = text;
                                this.falseExpression.Add(runClone);
                            }

                            // After the opening quote is found the parser will move to a state where it looks for the opening quote.  While this may seem
                            // unnecessary because we've already found the quote, it made the logic simpler than having to create a 'push back' concept for
                            // the tokens.
                            state = State.FalseStartQuote;
                        }

                        break;

                    case State.FalseStartQuote:

                        // This will search for the start quote of the 'False' clause.  Note that there is no check here for an empty Run node.  The only way
                        // for the parser to be in this state is if the previous state had found an open quote in the current Run node.
                        lastIndex = run.Text.LastIndexOf('\"', startIndex);
                        if (lastIndex != -1)
                        {
                            // If the start quote was the starting character of this Run node then the parsing will continue with the previous sibling when
                            // the next state is entered.  Otherwise, the cursor is moved in front of the opening quote as the parsing continues.
                            if (lastIndex == 0)
                            {
                                node       = node.PreviousSibling;
                                startIndex = -1;
                            }
                            else
                            {
                                startIndex = lastIndex - 1;
                            }

                            // Transition to a state where the parser searches for the opening quote of the 'True' condition.
                            state = State.TrueEndQuote;
                        }

                        break;

                    case State.TrueEndQuote:

                        // Look for the quote that finishes the 'True' clause.
                        lastIndex = run.Text.LastIndexOf('\"', startIndex);
                        if (lastIndex == -1)
                        {
                            // If the delimiter character can't be found then try the previous node.
                            startIndex = -1;
                        }
                        else
                        {
                            // If the delimiter is found then move the cursor into the body of the clause.
                            state      = State.TrueStatement;
                            startIndex = lastIndex - 1;
                        }

                        // move to the previous node when there is nothing left to parse in the current node until the delimiter is found.
                        if (startIndex == -1)
                        {
                            node = node.PreviousSibling;
                        }

                        break;

                    case State.TrueStatement:

                        // This will extract the body of the 'True' condition.  The next token that will cause a state change is the quote that opened this
                        // condition (remember we are parsing backwards).
                        lastIndex = run.Text.LastIndexOf('\"', startIndex);
                        if (lastIndex == -1)
                        {
                            // If there are no delimiters in the current run then clone it and copy the text up to the end quote (or the entire Run node if the
                            // end quote was in a previously parsed node).  There are times when the true clause is empty and an optimization removes any
                            // empty Run nodes.
                            String text = run.Text.Substring(0, startIndex + 1);
                            if (text != String.Empty)
                            {
                                runClone      = run.Clone(true) as Run;
                                runClone.Text = text;
                                this.trueExpression.Add(runClone);
                            }

                            // Since this node doesn't contain a delimiter, the state remains the same.  Continue parsing the next node for the start quote.
                            node       = node.PreviousSibling;
                            startIndex = -1;
                        }
                        else
                        {
                            // When an open quote is found we've come to the start of the true statement.  Copy any remaining text in the current Run node into
                            // the resulting clause.  The quotes will be removed but the rest of the text will be a literal copy of the text found in the
                            // document complete with all the formatting.
                            String text = run.Text.Substring(lastIndex + 1, startIndex - lastIndex);
                            if (runClone.Text != String.Empty)
                            {
                                runClone      = run.Clone(true) as Run;
                                runClone.Text = text;
                                this.trueExpression.Add(runClone);
                            }

                            // After the opening quote is found the parser will move to a state where it looks for the opening quote.  While this may seem
                            // unnecessary because we've already found the quote, it made the logic simpler than having to create a 'push back' concept for
                            // the tokens.
                            state = State.TrueStartQuote;
                        }

                        break;

                    case State.TrueStartQuote:

                        // This will search for the start quote of the 'True' clause.  Note that there is no check here for an empty Run node.  The only way
                        // for the parser to be in this state is if the previous state had found an open quote in the current Run node.
                        lastIndex = run.Text.LastIndexOf('\"', startIndex);
                        if (lastIndex != -1)
                        {
                            // If the start quote was the starting character of this Run node then the parsing will continue with the previous sibling when
                            // the next state is entered.  Otherwise, the cursor is moved in front of the opening quote as the parsing continues.
                            if (lastIndex == 0)
                            {
                                node       = node.PreviousSibling;
                                startIndex = -1;
                            }
                            else
                            {
                                startIndex = lastIndex - 1;
                            }

                            // Transition to a state where the parser searches for condition expression.
                            state = State.Expression;
                        }

                        break;

                    case State.Expression:

                        // Once the 'True' and 'False' clauses have been parsed, everthing between the start quote and the start of the field can be considered
                        // part of the expression.  There is no formatting that is required to evaluate the expression so there is no need to pull apart the
                        // Run nodes.
                        this.expression = run.Text.Substring(0, startIndex + 1) + expression;

                        // This moves the cursor up to the previous run node.  Remember the parsing runs backwards because it is more deterministic to pull out
                        // the 'True' and 'False' clauses from the end than to parse forward to determine where the condition ended.
                        startIndex = -1;
                        node       = node.PreviousSibling;
                        break;
                    }

                    break;

                case NodeType.FieldSeparator:

                    // The field seperator divides the field into the part you see in the document when working with fields, and the actual text that is
                    // displayed when you are not working with fields.  Anything after the field seperator is previously evaluated data which is of no interest
                    // to this parser.
                    node  = node.PreviousSibling;
                    state = State.FalseEndQuote;
                    break;

                case NodeType.FieldEnd:

                    // Remember that the parser works from the end of the field to the start.  Therefore, the end is just the beginning (of a field).
                    WordField wordField = this.FindByEndNode(node);

                    // Each field is handled according to the state of the parser.
                    switch (state)
                    {
                    case State.FalseStatement:

                        // A field found during the parsing of a false statement is added in its entirety to the literal collection.
                        while (node != null && node.NextSibling != wordField.FieldStart)
                        {
                            this.falseExpression.Insert(0, node.Clone(true));
                            node = node.PreviousSibling;
                        }

                        // Evaluate the previous node in the DOM.
                        node = wordField.FieldStart.PreviousSibling;

                        break;

                    case State.TrueStatement:

                        // A field found during the parsing of a true statement is added in its entirety to the literal collection.
                        while (node != null && node.NextSibling != wordField.FieldStart)
                        {
                            this.trueExpression.Insert(0, node.Clone(true));
                            node = node.PreviousSibling;
                        }

                        // Evaluate the previous node in the DOM.
                        node = wordField.FieldStart.PreviousSibling;

                        break;

                    case State.Expression:

                        // When a field is found during the evaluation of an expression, the name of the merge field is used as a general purpose parameter to
                        // the expression evaluator.
                        if (wordField is MergeField)
                        {
                            MergeField mergeField = wordField as MergeField;
                            this.expression = mergeField.Reference + expression;
                        }

                        // Evaluate the previous node in the DOM.
                        node = wordField.FieldStart.PreviousSibling;

                        break;

                    default:

                        // Ignore anything whiel processing the field results.
                        node = wordField.FieldStart.PreviousSibling;
                        break;
                    }

                    break;

                case NodeType.FieldStart:

                    // The parser works from the end of the field to the front because the expression can have many items in it but the 'True' and 'False'
                    // clauses are relatively easy to delinate.  When the cursor has come to the start of the field, then the parsing of this 'IF' statement is
                    // complete.  The last task is to remove the 'IF' keyword from the expression.
                    this.expression = expression.Substring(expression.IndexOf(IfField.ifText) + IfField.ifText.Length);
                    state           = State.Final;
                    break;
                }
            }
        }
示例#47
0
 /// <summary>
 /// Determines if the given field start is the quote reference field.
 /// </summary>
 public static bool IsQuoteField(FieldStart start)
 {
     FieldEnd end;
     return IsQuoteField(start, out end);
 }