diff --git a/DocX/Container.cs b/DocX/Container.cs index 65da1f0..f23a574 100644 --- a/DocX/Container.cs +++ b/DocX/Container.cs @@ -80,45 +80,6 @@ public virtual List Paragraphs } - - public virtual List
Sections - { - get - { - var allParas = Paragraphs; - - var parasInASection = new List(); - var sections = new List
(); - - foreach (var para in allParas) - { - - var sectionInPara = para.Xml.Descendants().FirstOrDefault(s => s.Name.LocalName == "sectPr"); - - if (sectionInPara == null) - { - parasInASection.Add(para); - } - else - { - parasInASection.Add(para); - var section = new Section(Document, sectionInPara) { SectionParagraphs = parasInASection }; - sections.Add(section); - parasInASection = new List(); - } - - } - - XElement body = Xml.Element(XName.Get("body", DocX.w.NamespaceName)); - XElement baseSectionXml = body.Element(XName.Get("sectPr", DocX.w.NamespaceName)); - var baseSection = new Section(Document, baseSectionXml) { SectionParagraphs = parasInASection }; - sections.Add(baseSection); - - return sections; - } - } - - private void GetListItemType(Paragraph p) { var ilvlNode = p.ParagraphNumberProperties.Descendants().FirstOrDefault(el => el.Name.LocalName == "ilvl"); @@ -596,15 +557,7 @@ private ListItemType GetListItemType(string styleName) return listItemType; } - - - public virtual void InsertSection() - { - - InsertSection(false); - } - - public virtual void InsertSection(bool trackChanges) + public virtual void InsertSection(bool trackChanges = false) { var newParagraphSection = new XElement ( diff --git a/DocX/DocX.cs b/DocX/DocX.cs index 2b9c010..ecf97a7 100644 --- a/DocX/DocX.cs +++ b/DocX/DocX.cs @@ -629,34 +629,21 @@ public List
GetSections() { var allParas = Paragraphs; - - var parasInASection = new List(); var sections = new List
(); foreach (var para in allParas) { var sectionInPara = para.Xml.Descendants().FirstOrDefault(s => s.Name.LocalName == "sectPr"); - - if (sectionInPara == null) + if (sectionInPara != null) { - parasInASection.Add(para); + sections.Add(new Section(Document, sectionInPara)); } - else - { - parasInASection.Add(para); - var section = new Section(Document, sectionInPara) { SectionParagraphs = parasInASection }; - sections.Add(section); - parasInASection = new List(); - } - } XElement body = mainDoc.Root.Element(XName.Get("body", DocX.w.NamespaceName)); XElement baseSectionXml = body.Element(XName.Get("sectPr", DocX.w.NamespaceName)); - var baseSection = new Section(Document, baseSectionXml) { SectionParagraphs = parasInASection }; - sections.Add(baseSection); - + sections.Add(new Section(Document, baseSectionXml)); return sections; } diff --git a/DocX/Section.cs b/DocX/Section.cs index 9769972..c3c0300 100644 --- a/DocX/Section.cs +++ b/DocX/Section.cs @@ -1,18 +1,126 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.IO.Packaging; +using System.Linq; using System.Xml.Linq; namespace Novacode { - public class Section : Container - { + /// + /// Please read the specifications at + /// http://msdn.microsoft.com/en-us/library/documentformat.openxml.wordprocessing.sectionproperties.aspx + /// + public class Section : Container + { - public SectionBreakType SectionBreakType; + public SectionBreakType SectionBreakType; - internal Section(DocX document, XElement xml) : base(document, xml) - { + internal Section(DocX document, XElement xml) + : base(document, xml) + { + } + + // Section doesn't contain any paragraphs in the xml, so we override the base property + public override List Paragraphs + { + get + { + if (Xml.Parent == null) + { + throw new ApplicationException("Sections must be either be under a paragraph or the body!"); + } + + var output = new List(); + var index = 0; // Is required by the recursion + // Based on the specifications: + // For all sections except the final section, the sectPr element is stored as a child element + // of the last paragraph in the section. For the final section, this information is stored as + // the last child element of the body element + // This + + var elementsBeforeSection = GetElementsBeforeSection(); + // Get last previous section + var lastSectionBefore = elementsBeforeSection.InDocumentOrder().LastOrDefault(el => el.Descendants().Any(s => s.Name.LocalName == "sectPr")); + if (lastSectionBefore != null) // We have to exclude all the previous elements + { + var elementComparer = new XElementEqualityComparer(); + elementsBeforeSection = elementsBeforeSection.Except(lastSectionBefore.ElementsBeforeSelf(), elementComparer); + // And the previous section element + elementsBeforeSection = elementsBeforeSection.Except(new XElement[] { lastSectionBefore }, elementComparer); + } + foreach (var xElement in elementsBeforeSection) + { + GetParagraphsRecursive(xElement, ref index, ref output); + } + return output; + } + } + + private IEnumerable GetElementsBeforeSection() + { + IEnumerable elementsBeforeSection = null; + + // If this is a section somewhere inside the document + if (Xml.Parent.Name.LocalName == "pPr") // Get the nodes on the same level as the father + { + elementsBeforeSection = Xml.Parent.Parent.ElementsBeforeSelf(); + } + else if (Xml.Parent.Name.LocalName == "body") // This is the final section so we get all children in same level + { + elementsBeforeSection = Xml.ElementsBeforeSelf(); + } + else + { + throw new ApplicationException("Sections should be located inside a pPr or body"); + } + return elementsBeforeSection; + } + + /// + /// Clear all paragraphs in section + /// + /// Keep track of changes + public void Clear(bool trackChanges = false) + { + var paragraphs = Paragraphs; + foreach (var paragraph in paragraphs) + { + paragraph.Remove(trackChanges); + } + } + + + // Sections don't have paragraphs. + public override Paragraph InsertParagraph(string text, bool trackChanges, Formatting formatting) + { + XElement newParagraph = new XElement + ( + XName.Get("p", DocX.w.NamespaceName), new XElement(XName.Get("pPr", DocX.w.NamespaceName)), HelperFunctions.FormatInput(text, formatting.Xml) + ); + + if (trackChanges) + newParagraph = HelperFunctions.CreateEdit(EditType.ins, DateTime.Now, newParagraph); + + //So we have to add it just before the section brake + GetElementsBeforeSection().Last().AddAfterSelf(newParagraph); + + var paragraphAdded = Paragraphs.Last(); + + return paragraphAdded; + } } - public List SectionParagraphs { get; set; } - } + public class XElementEqualityComparer : IEqualityComparer + { + + public bool Equals(XElement x, XElement y) + { + return XElement.DeepEquals(x, y); + } + + public int GetHashCode(XElement obj) + { + return obj.GetHashCode(); + } + } } \ No newline at end of file