public void ExecuteXDocumentVariation(XNode[] toAdd, XNode contextNode) { IEnumerable<XNode> toAddList = toAdd.OfType<XNode>(); XDocument xDoc = new XDocument(contextNode); XDocument xDocOriginal = new XDocument(xDoc); using (UndoManager undo = new UndoManager(xDoc)) { undo.Group(); using (EventsHelper docHelper = new EventsHelper(xDoc)) { using (EventsHelper nodeHelper = new EventsHelper(contextNode)) { contextNode.AddBeforeSelf(toAdd); Assert.True(toAddList.SequenceEqual(contextNode.NodesBeforeSelf(), XNode.EqualityComparer), "Nodes not added correctly!"); nodeHelper.Verify(0); } docHelper.Verify(XObjectChange.Add, toAdd); } undo.Undo(); Assert.True(XNode.DeepEquals(xDoc, xDocOriginal), "Undo did not work!"); } }
public void ExecuteXElementVariation(XNode[] toAdd, XNode contextNode) { IEnumerable<XNode> toAddList = toAdd.OfType<XNode>(); XElement xElem = new XElement("root", contextNode); XElement xElemOriginal = new XElement(xElem); using (UndoManager undo = new UndoManager(xElem)) { undo.Group(); using (EventsHelper elemHelper = new EventsHelper(xElem)) { using (EventsHelper nodeHelper = new EventsHelper(contextNode)) { contextNode.AddBeforeSelf(toAdd); Assert.True(toAddList.SequenceEqual(contextNode.NodesBeforeSelf(), XNode.EqualityComparer), "Nodes not added correctly!"); nodeHelper.Verify(0); } elemHelper.Verify(XObjectChange.Add, toAdd); } undo.Undo(); Assert.True(xElem.Nodes().SequenceEqual(xElemOriginal.Nodes(), XNode.EqualityComparer), "Undo did not work!"); Assert.True(xElem.Attributes().EqualsAllAttributes(xElemOriginal.Attributes(), Helpers.MyAttributeComparer), "Undo did not work!"); } }
/// <summary> /// Handles insignificant white spaces. /// There are 4 white spaces characters: carriage return '\r', linefeed '\n', tab '\t', and spacebar (' '). /// This handles xml:space = "preserve" that protects any text in an element or its /// descendants except inside any child with xml:space="default". /// </summary> /// <param name="this">This document.</param> /// <param name="actualTextProcessor"> /// Optional transformer for texts that are not entirely white spaces and for which white spaces /// are not preserved. The function is called with the current start line and the <see cref="StringBuilder"/> /// that can be changed: the function must return true if the content of the StringBuilder must be considered. /// </param> /// <returns>This document.</returns> public static XDocument Beautify(this XDocument @this, Func <string, StringBuilder, bool> actualTextProcessor = null) { bool?GetPreserve(XElement e) { var p = (string)e.Attribute(_xmlSpace); return(p == null ? (bool?)null : p == "preserve"); } string indent = " "; void Process(XElement e, bool preserve, string outerStartLine, int depth) { string startLine = outerStartLine + indent; if (preserve) { foreach (var child in e.Elements()) { Process(child, preserve, startLine, depth + 1); } return; } bool hasContent = false; var currentXText = new List <XText>(); var currentText = new StringBuilder(); XNode c = e.FirstNode; while (c != null) { if (c is XText t) { currentXText.Add(t); currentText.Append(t.Value); } else { hasContent = true; Debug.Assert(c is XElement || c is XComment || c is XCData || c is XProcessingInstruction); // Handling current collected XText, possibly replacing them with a unique XText. if (currentXText.Count == 0) { c.AddBeforeSelf(new XText(startLine)); } else { HandleCollectedXText(actualTextProcessor, startLine, currentXText, currentText, false); } if (c is XElement cE) { Process(cE, GetPreserve(cE) ?? preserve, startLine, depth + 1); } currentXText.Clear(); currentText.Clear(); } c = c.NextNode; } if (currentXText.Count == 0) { if (hasContent) { e.LastNode.AddAfterSelf(new XText(outerStartLine)); } } else { HandleCollectedXText(actualTextProcessor, outerStartLine, currentXText, currentText, !hasContent); } } Process(@this.Root, false, Environment.NewLine, 0); return(@this); }
/// <summary> /// Ensures the whitespace separation for the first child element added to a node. /// </summary> /// <param name="element"></param> private void EnsureFirstNodeWhitespaceSeparation(XNode element) { #if DEBUG if (element.Parent != null) { Debug.Assert(element.Parent.Elements().Count() == 1, "Unexpected count of elements!"); } else { // if first.Parent is null, then this is the root element in a document Debug.Assert(element.Document.Root == element, "element had null parent, but is not the root element of the document"); } #endif var precedingNewLine = new XText(Environment.NewLine + new string(' ', GetIndentLevel() * 2)); var trailingNewLine = new XText(Environment.NewLine + new string(' ', Parent.GetIndentLevel() * 2)); element.AddBeforeSelf(precedingNewLine); element.AddAfterSelf(trailingNewLine); }
/// <summary> /// Ensures the whitespace separation between two nodes. Appropriate whitespace is added before the given node /// </summary> /// <param name="first"></param> private XText EnsureWhitespaceBeforeNode(XNode node) { Debug.Assert( node.Parent != null && node.Parent.Elements().Count() > 0, "Call EnsureFirstNodeWhitespaceSeparation when the added element is the first node"); var newLine = new XText(Environment.NewLine + new string(' ', GetIndentLevel() * 2)); node.AddBeforeSelf(newLine); return newLine; }