using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml.Linq; namespace Novacode { internal class Text { private int startIndex; private int endIndex; private string text; internal XElement xml; /// /// Gets the start index of this Text (text length before this text) /// public int StartIndex { get { return startIndex; } } /// /// Gets the end index of this Text (text length before this text + this texts length) /// public int EndIndex { get { return endIndex; } } /// /// The text value of this text element /// public string Value { get { return text; } } internal Text(int startIndex, XElement e) { this.startIndex = startIndex; this.xml = e; switch (e.Name.LocalName) { case "t": { goto case "delText"; } case "delText": { endIndex = startIndex + e.Value.Length; text = e.Value; break; } case "br": { text = "\n"; endIndex = startIndex + 1; break; } case "tab": { text = "\t"; endIndex = startIndex + 1; break; } default: { break; } } } internal static XElement[] SplitText(Text t, int index) { if (index < t.startIndex || index > t.EndIndex) throw new ArgumentOutOfRangeException("index"); XElement splitLeft = null, splitRight = null; if (t.xml.Name.LocalName == "t" || t.xml.Name.LocalName == "delText") { // The origional text element, now containing only the text before the index point. splitLeft = new XElement(t.xml.Name, t.xml.Attributes(), t.xml.Value.Substring(0, index - t.startIndex)); if (splitLeft.Value.Length == 0) splitLeft = null; else PreserveSpace(splitLeft); // The origional text element, now containing only the text after the index point. splitRight = new XElement(t.xml.Name, t.xml.Attributes(), t.xml.Value.Substring(index - t.startIndex, t.xml.Value.Length - (index - t.startIndex))); if (splitRight.Value.Length == 0) splitRight = null; else PreserveSpace(splitRight); } else { if (index == t.StartIndex) splitLeft = t.xml; else splitRight = t.xml; } return ( new XElement[] { splitLeft, splitRight } ); } /// /// If a text element or delText element, starts or ends with a space, /// it must have the attribute space, otherwise it must not have it. /// /// The (t or delText) element check public static void PreserveSpace(XElement e) { // PreserveSpace should only be used on (t or delText) elements if (!e.Name.Equals(DocX.w + "t") && !e.Name.Equals(DocX.w + "delText")) throw new ArgumentException("SplitText can only split elements of type t or delText", "e"); // Check if this w:t contains a space atribute XAttribute space = e.Attributes().Where(a => a.Name.Equals(XNamespace.Xml + "space")).SingleOrDefault(); // This w:t's text begins or ends with whitespace if (e.Value.StartsWith(" ") || e.Value.EndsWith(" ")) { // If this w:t contains no space attribute, add one. if (space == null) e.Add(new XAttribute(XNamespace.Xml + "space", "preserve")); } // This w:t's text does not begin or end with a space else { // If this w:r contains a space attribute, remove it. if (space != null) space.Remove(); } } } }