FieldStart Class

Represents a start of a Word field in a document.
Inheritance Hierarchy

Namespace:  Aspose.Words.Fields
Assembly:  Aspose.Words (in Aspose.Words.dll) Version: 20.3
Syntax
public class FieldStart : FieldChar

The FieldStart type exposes the following members.

Properties
  NameDescription
Public propertyCode exampleDocument
Gets the document to which this node belongs.
(Inherited from Node.)
Public propertyCode exampleFieldType
Returns the type of the field.
(Inherited from FieldChar.)
Public propertyCode exampleFont
Provides access to the font formatting of this object.
(Inherited from Inline.)
Public propertyCode exampleIsComposite
Returns true if this node can contain other nodes.
(Inherited from Node.)
Public propertyCode exampleIsDeleteRevision
Returns true if this object was deleted in Microsoft Word while change tracking was enabled.
(Inherited from Inline.)
Public propertyCode exampleIsDirty
Gets or sets whether the current result of the field is no longer correct (stale) due to other modifications made to the document.
(Inherited from FieldChar.)
Public propertyCode exampleIsFormatRevision
Returns true if formatting of the object was changed in Microsoft Word while change tracking was enabled.
(Inherited from Inline.)
Public propertyCode exampleIsInsertRevision
Returns true if this object was inserted in Microsoft Word while change tracking was enabled.
(Inherited from Inline.)
Public propertyCode exampleIsLocked
Gets or sets whether the parent field is locked (should not recalculate its result).
(Inherited from FieldChar.)
Public propertyCode exampleIsMoveFromRevision
Returns true if this object was moved (deleted) in Microsoft Word while change tracking was enabled.
(Inherited from Inline.)
Public propertyCode exampleIsMoveToRevision
Returns true if this object was moved (inserted) in Microsoft Word while change tracking was enabled.
(Inherited from Inline.)
Public propertyCode exampleNextSibling
Gets the node immediately following this node.
(Inherited from Node.)
Public propertyCode exampleNodeType
Returns FieldStart.
(Overrides SpecialCharNodeType.)
Public propertyCode exampleParentNode
Gets the immediate parent of this node.
(Inherited from Node.)
Public propertyCode exampleParentParagraph
Retrieves the parent Paragraph of this node.
(Inherited from Inline.)
Public propertyCode examplePreviousSibling
Gets the node immediately preceding this node.
(Inherited from Node.)
Public propertyCode exampleRange
Returns a Range object that represents the portion of a document that is contained in this node.
(Inherited from Node.)
Methods
  NameDescription
Public methodCode exampleAccept
Accepts a visitor.
(Overrides SpecialCharAccept(DocumentVisitor).)
Public methodCode exampleClone (Inherited from Node.)
Public methodEquals (Inherited from Object.)
Public methodCode exampleGetAncestor(Type)
Gets the first ancestor of the specified object type.
(Inherited from Node.)
Public methodCode exampleGetAncestor(NodeType)
Gets the first ancestor of the specified NodeType.
(Inherited from Node.)
Public methodCode exampleGetField
Returns a field for the field char.
(Inherited from FieldChar.)
Public methodGetHashCode (Inherited from Object.)
Public methodGetText
Gets the special character that this node represents.
(Inherited from SpecialChar.)
Public methodGetType (Inherited from Object.)
Public methodCode exampleNextPreOrder
Gets next node according to the pre-order tree traversal algorithm.
(Inherited from Node.)
Public methodCode examplePreviousPreOrder
Gets the previous node according to the pre-order tree traversal algorithm.
(Inherited from Node.)
Public methodCode exampleRemove
Removes itself from the parent.
(Inherited from Node.)
Public methodToString (Inherited from Object.)
Public methodCode exampleToString(SaveFormat)
Exports the content of the node into a string in the specified format.
(Inherited from Node.)
Public methodCode exampleToString(SaveOptions)
Exports the content of the node into a string using the specified save options.
(Inherited from Node.)
Remarks

FieldStart is an inline-level node and represented by the FieldStartChar control character in the document.

FieldStart can only be a child of Paragraph.

A complete field in a Microsoft Word document is a complex structure consisting of a field start character, field code, field separator character, field result and field end character. Some fields only have field start, field code and field end.

To easily insert a new field into a document, use the InsertField(String) method.

Examples
Shows how to work with a document's field collection.
public void FieldCollection()
{
    // Create a new document and insert some fields
    Document doc = new Document();
    DocumentBuilder builder = new DocumentBuilder(doc);

    builder.InsertField(" DATE \\@ \"dddd, d MMMM yyyy\" ");
    builder.InsertField(" TIME ");
    builder.InsertField(" REVNUM ");
    builder.InsertField(" AUTHOR  \"John Doe\" ");
    builder.InsertField(" SUBJECT \"My Subject\" ");
    builder.InsertField(" QUOTE \"Hello world!\" ");
    doc.UpdateFields();

    // Get the collection that contains all the fields in a document
    FieldCollection fields = doc.Range.Fields;
    Assert.AreEqual(6, fields.Count);

    // Iterate over the field collection and print contents and type of every field using a custom visitor implementation
    FieldVisitor fieldVisitor = new FieldVisitor();

    using (IEnumerator<Field> fieldEnumerator = fields.GetEnumerator())
    {
        while (fieldEnumerator.MoveNext())
        {
            if (fieldEnumerator.Current != null)
            {
                fieldEnumerator.Current.Start.Accept(fieldVisitor);
                fieldEnumerator.Current.Separator?.Accept(fieldVisitor);
                fieldEnumerator.Current.End.Accept(fieldVisitor);
            }
            else
            {
                Console.WriteLine("There are no fields in the document.");
            }
        }
    }

    Console.WriteLine(fieldVisitor.GetText());

    // Get a field to remove itself
    fields[0].Remove();
    Assert.AreEqual(5, fields.Count);

    // Remove a field by reference
    Field lastField = fields[3];
    fields.Remove(lastField);
    Assert.AreEqual(4, fields.Count);

    // Remove a field by index
    fields.RemoveAt(2);
    Assert.AreEqual(3, fields.Count);

    // Remove all fields from the document
    fields.Clear();
    Assert.AreEqual(0, fields.Count);
}

/// <summary>
/// Document visitor implementation that prints field info.
/// </summary>
public class FieldVisitor : DocumentVisitor
{
    public FieldVisitor()
    {
        mBuilder = new StringBuilder();
    }

    /// <summary>
    /// Gets the plain text of the document that was accumulated by the visitor.
    /// </summary>
    public string GetText()
    {
        return mBuilder.ToString();
    }

    /// <summary>
    /// Called when a FieldStart node is encountered in the document.
    /// </summary>
    public override VisitorAction VisitFieldStart(FieldStart fieldStart)
    {
        mBuilder.AppendLine("Found field: " + fieldStart.FieldType);
        mBuilder.AppendLine("\tField code: " + fieldStart.GetField().GetFieldCode());
        mBuilder.AppendLine("\tDisplayed as: " + fieldStart.GetField().Result);

        return VisitorAction.Continue;
    }

    /// <summary>
    /// Called when a FieldSeparator node is encountered in the document.
    /// </summary>
    public override VisitorAction VisitFieldSeparator(FieldSeparator fieldSeparator)
    {
        mBuilder.AppendLine("\tFound separator: " + fieldSeparator.GetText());

        return VisitorAction.Continue;
    }

    /// <summary>
    /// Called when a FieldEnd node is encountered in the document.
    /// </summary>
    public override VisitorAction VisitFieldEnd(FieldEnd fieldEnd)
    {
        mBuilder.AppendLine("End of field: " + fieldEnd.FieldType);

        return VisitorAction.Continue;
    }

    private readonly StringBuilder mBuilder;
}
Examples
Finds all hyperlinks in a Word document and changes their URL and display name.
using System;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Aspose.Words;
using Aspose.Words.Fields;
using NUnit.Framework;

namespace ApiExamples
{
    /// <summary>
    /// Shows how to replace hyperlinks in a Word document.
    /// </summary>
    public class ExReplaceHyperlinks : ApiExampleBase
    {
        /// <summary>
        /// Finds all hyperlinks in a Word document and changes their URL and display name.
        /// </summary>
        public void Fields()
        {
            // Specify your document name here
            Document doc = new Document(MyDir + "Hyperlinks.docx");

            // Hyperlinks in a Word documents are fields, select all field start nodes so we can find the hyperlinks
            NodeList fieldStarts = doc.SelectNodes("//FieldStart");
            foreach (FieldStart fieldStart in fieldStarts.OfType<FieldStart>())
            {
                if (fieldStart.FieldType.Equals(FieldType.FieldHyperlink))
                {
                    // The field is a hyperlink field, use the "facade" class to help to deal with the field
                    Hyperlink hyperlink = new Hyperlink(fieldStart);

                    // Some hyperlinks can be local (links to bookmarks inside the document), ignore these
                    if (hyperlink.IsLocal)
                        continue;

                    // The Hyperlink class allows to set the target URL and the display name 
                    // of the link easily by setting the properties
                    hyperlink.Target = NewUrl;
                    hyperlink.Name = NewName;
                }
            }

            doc.Save(ArtifactsDir + "ReplaceHyperlinks.Fields.docx");
        }

        private const string NewUrl = @"http://www.aspose.com";
        private const string NewName = "Aspose - The .NET & Java Component Publisher";
    }

    /// <summary>
    /// This "facade" class makes it easier to work with a hyperlink field in a Word document. 
    /// 
    /// A hyperlink is represented by a HYPERLINK field in a Word document. A field in Aspose.Words 
    /// consists of several nodes and it might be difficult to work with all those nodes directly. 
    /// Note this is a simple implementation and will work only if the hyperlink code and name 
    /// each consist of one Run only.
    /// 
    /// [FieldStart][Run - field code][FieldSeparator][Run - field result][FieldEnd]
    /// 
    /// The field code contains a String in one of these formats:
    /// HYPERLINK "url"
    /// HYPERLINK \l "bookmark name"
    /// 
    /// The field result contains text that is displayed to the user.
    /// </summary>
    internal class Hyperlink
    {
        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;
        }

        /// <summary>
        /// Gets or sets the display name of the hyperlink.
        /// </summary>
        internal string Name
        {
            get { return GetTextSameParent(mFieldSeparator, mFieldEnd); }
            set
            {
                // Hyperlink display name is stored in the field result which is a Run 
                // node between field separator and field end
                Run fieldResult = (Run) mFieldSeparator.NextSibling;
                fieldResult.Text = value;

                // But sometimes the field result can consist of more than one run, delete these runs
                RemoveSameParent(fieldResult.NextSibling, mFieldEnd);
            }
        }

        /// <summary>
        /// Gets or sets the target url or bookmark name of the hyperlink.
        /// </summary>
        internal string Target
        {
            get
            {
                return mTarget;
            }
            set
            {
                mTarget = value;
                UpdateFieldCode();
            }
        }

        /// <summary>
        /// True if the hyperlinks target is a bookmark inside the document. False if the hyperlink is a url.
        /// </summary>
        internal bool IsLocal
        {
            get { return mIsLocal; }
            set
            {
                mIsLocal = value;
                UpdateFieldCode();
            }
        }

        private void UpdateFieldCode()
        {
            // Field code is stored in a Run node between field start and field separator
            Run fieldCode = (Run) mFieldStart.NextSibling;
            fieldCode.Text = string.Format("HYPERLINK {0}\"{1}\"", ((mIsLocal) ? "\\l " : ""), mTarget);

            // But sometimes the field code can consist of more than one run, delete these runs
            RemoveSameParent(fieldCode.NextSibling, mFieldSeparator);
        }

        /// <summary>
        /// Goes through siblings starting from the start node until it finds a node of the specified type or null.
        /// </summary>
        private static Node FindNextSibling(Node startNode, NodeType nodeType)
        {
            for (Node node = startNode; node != null; node = node.NextSibling)
            {
                if (node.NodeType.Equals(nodeType))
                    return node;
            }

            return null;
        }

        /// <summary>
        /// Retrieves text from start up to but not including the end node.
        /// </summary>
        private static string GetTextSameParent(Node startNode, Node endNode)
        {
            if ((endNode != null) && (startNode.ParentNode != endNode.ParentNode))
                throw new ArgumentException("Start and end nodes are expected to have the same parent.");

            StringBuilder builder = new StringBuilder();
            for (Node child = startNode; !child.Equals(endNode); child = child.NextSibling)
                builder.Append(child.GetText());

            return builder.ToString();
        }

        /// <summary>
        /// Removes nodes from start up to but not including the end node.
        /// Start and end are assumed to have the same parent.
        /// </summary>
        private static void RemoveSameParent(Node startNode, Node endNode)
        {
            if (endNode != null && startNode.ParentNode != endNode.ParentNode)
                throw new ArgumentException("Start and end nodes are expected to have the same parent.");

            Node curChild = startNode;
            while ((curChild != null) && (curChild != endNode))
            {
                Node nextChild = curChild.NextSibling;
                curChild.Remove();
                curChild = nextChild;
            }
        }

        private readonly Node mFieldStart;
        private readonly Node mFieldSeparator;
        private readonly Node mFieldEnd;
        private bool mIsLocal;
        private string mTarget;

        private static readonly Regex gRegex = new Regex(
            "\\S+" + // one or more non spaces HYPERLINK or other word in other languages
            "\\s+" + // one or more spaces
            "(?:\"\"\\s+)?" + // non capturing optional "" and one or more spaces, found in one of the customers files.
            "(\\\\l\\s+)?" + // optional \l flag followed by one or more spaces
            "\"" + // one apostrophe    
            "([^\"]+)" + // one or more chars except apostrophe (hyperlink target)
            "\"" // one closing apostrophe
        );
    }
}
See Also