public void Process(XmlReader xmlReader, StringBuilder output, ElementProcessContext elementProcessContext) { // All newlines are returned by XmlReader as '\n' due to requirements in the XML Specification. // http://www.w3.org/TR/2008/REC-xml-20081126/#sec-line-ends // Change them back into the environment newline characters. output.Append(xmlReader.Value.Replace("\n", Environment.NewLine)); }
public void Process(XmlReader xmlReader, StringBuilder output, ElementProcessContext elementProcessContext) { elementProcessContext.UpdateParentElementProcessStatus(ContentTypes.Mixed); string currentIndentString = this.indentService.GetIndentString(xmlReader.Depth); string content = xmlReader.Value; if ((output.Length > 0) && !output.IsNewLine()) { output.Append(Environment.NewLine); } if (content.Contains("<") && content.Contains(">")) { output.Append(currentIndentString); output.Append("<!--"); if (content.Contains("\n")) { output.Append(String.Join(Environment.NewLine, content.GetLines().Select(_ => _.TrimEnd(' ')))); if (content.TrimEnd(' ').EndsWith("\n", StringComparison.Ordinal)) { output.Append(currentIndentString); } } else { output.Append(content); } output.Append("-->"); } else if (content.Contains("#region") || content.Contains("#endregion")) { output.Append(currentIndentString).Append("<!--").Append(content.Trim()).Append("-->"); } else if (content.Contains("\n")) { output.Append(currentIndentString).Append("<!--"); var contentIndentString = this.indentService.GetIndentString(xmlReader.Depth + 1); foreach (var line in content.Trim().GetLines()) { output.Append(Environment.NewLine).Append(contentIndentString).Append(line.Trim()); } output.Append(Environment.NewLine).Append(currentIndentString).Append("-->"); } else { output .Append(currentIndentString) .Append("<!--") .Append(' ', this.options.CommentSpaces) .Append(content.Trim()) .Append(' ', this.options.CommentSpaces) .Append("-->"); } }
public void Process(XmlReader xmlReader, StringBuilder output, ElementProcessContext elementProcessContext) { // If there is linefeed(s) between element and CDATA then treat CDATA as element and // indent accordingly, otherwise treat as single line text. if (output.IsNewLine()) { elementProcessContext.UpdateParentElementProcessStatus(ContentTypes.MultiLineTextOnly); if (!elementProcessContext.Current.IsPreservingSpace) { string currentIndentString = this.indentService.GetIndentString(xmlReader.Depth); output.Append(currentIndentString); } } else { elementProcessContext.UpdateParentElementProcessStatus(ContentTypes.SingleLineTextOnly); } // All newlines are returned by XmlReader as '\n' due to requirements in the XML Specification. // http://www.w3.org/TR/2008/REC-xml-20081126/#sec-line-ends // Change them back into the environment newline characters. output.Append("<![CDATA[") .Append(xmlReader.Value.Replace("\n", Environment.NewLine)) .Append("]]>"); }
public void Process(XmlReader xmlReader, StringBuilder output, ElementProcessContext elementProcessContext) { elementProcessContext.UpdateParentElementProcessStatus(ContentTypes.SingleLineTextOnly); var xmlEncodedContent = xmlReader.Value.ToXmlEncodedString(ignoreCarrier: true); if (elementProcessContext.Current.IsPreservingSpace) { output.Append(xmlEncodedContent.Replace("\n", Environment.NewLine)); } else { string currentIndentString = this.indentService.GetIndentString(xmlReader.Depth); IEnumerable <string> textLines = xmlEncodedContent.Trim() .Split('\n') .Where(_ => (_.Trim().Length > 0)) .ToList(); foreach (var line in textLines) { var trimmedLine = line.Trim(); if (trimmedLine.Length > 0) { output.Append(Environment.NewLine).Append(currentIndentString).Append(trimmedLine); } } } if (xmlEncodedContent.Any(_ => (_ == '\n'))) { elementProcessContext.UpdateParentElementProcessStatus(ContentTypes.MultiLineTextOnly); } }
public void Process(XmlReader xmlReader, StringBuilder output, ElementProcessContext elementProcessContext) { var hasNewline = xmlReader.Value.Contains('\n'); if (elementProcessContext.Current.IsSignificantWhiteSpace && hasNewline) { elementProcessContext.Current.IsSignificantWhiteSpace = false; } if (hasNewline && !elementProcessContext.Current.IsPreservingSpace) { // For WhiteSpaces contain linefeed, trim all spaces/tab, // since the intent of this whitespace node is to break line, // and preserve the line feeds output.Append(xmlReader.Value .Replace(" ", String.Empty) .Replace("\t", String.Empty) .Replace("\r", String.Empty) .Replace("\n", Environment.NewLine)); } else { // Preserve "pure" WhiteSpace between elements // e.g., // <TextBlock> // <Run>A</Run> <Run> // B // </Run> // </TextBlock> output.Append(xmlReader.Value.Replace("\n", Environment.NewLine)); } }
public void Process( XmlReader xmlReader, StringBuilder output, ElementProcessContext elementProcessContext) { if (elementProcessContext.Current.IsPreservingSpace) { output.Append("</").Append(xmlReader.Name).Append(">"); } else if (elementProcessContext.Current.IsSignificantWhiteSpace && !output.IsNewLine()) { output.Append("</").Append(xmlReader.Name).Append(">"); } else if ((elementProcessContext.Current.ContentType == ContentTypes.None) && this.options.RemoveEndingTagOfEmptyElement) { // Shrink the current element, if it has no content. // E.g., <Element> </Element> => <Element /> output = output.TrimEnd(' ', '\t', '\r', '\n'); int bracketIndex = output.LastIndexOf('>'); output.Insert(bracketIndex, '/'); if ((output[bracketIndex - 1] != '\t') && (output[bracketIndex - 1] != ' ') && this.options.SpaceBeforeClosingSlash) { output.Insert(bracketIndex, ' '); } } else if ((elementProcessContext.Current.ContentType == ContentTypes.SingleLineTextOnly) && !elementProcessContext.Current.IsMultlineStartTag) { int bracketIndex = output.LastIndexOf('>'); string text = output.Substring((bracketIndex + 1), (output.Length - bracketIndex - 1)).Trim(); output.Length = (bracketIndex + 1); output.Append(text).Append("</").Append(xmlReader.Name).Append(">"); } else { string currentIndentString = this.indentService.GetIndentString(xmlReader.Depth); if (!output.IsNewLine()) { output.Append(Environment.NewLine); } output.Append(currentIndentString).Append("</").Append(xmlReader.Name).Append(">"); } elementProcessContext.Pop(); }
public void Process(XmlReader xmlReader, StringBuilder output, ElementProcessContext elementProcessContext) { elementProcessContext.UpdateParentElementProcessStatus(ContentTypes.Mixed); string currentIndentString = this.indentService.GetIndentString(xmlReader.Depth); if (!output.IsNewLine()) { output.Append(Environment.NewLine); } output.Append($"{currentIndentString}<?{xmlReader.Name} {xmlReader.Value}?>"); }
public void Process(XmlReader xmlReader, StringBuilder output, ElementProcessContext elementProcessContext) { elementProcessContext.UpdateParentElementProcessStatus(ContentTypes.Mixed); var elementName = xmlReader.Name; elementProcessContext.Push( new ElementProcessStatus { Parent = elementProcessContext.Current, Name = elementName, ContentType = ContentTypes.None, IsMultlineStartTag = false, IsPreservingSpace = elementProcessContext.Current.IsPreservingSpace }); var currentIndentString = this.indentService.GetIndentString(xmlReader.Depth); var attributeIndetationString = this.GetAttributeIndetationString(xmlReader); // Calculate how element should be indented if (!elementProcessContext.Current.IsPreservingSpace) { // Preserve spacing if element is an inline type has a parent that supports inline types. if ((elementProcessContext.Current.Parent.Name != null) && this.inlineCollections.Any(elementProcessContext.Current.Parent.Name.Contains) && this.inlineTypes.Any(elementName.Contains)) { elementProcessContext.Current.Parent.IsSignificantWhiteSpace = true; if ((output.Length == 0) || output.IsNewLine()) { output.Append(currentIndentString); } } else { elementProcessContext.Current.Parent.IsSignificantWhiteSpace = false; if ((output.Length == 0) || output.IsNewLine()) { output.Append(currentIndentString); } else { output.Append(Environment.NewLine).Append(currentIndentString); } } } // Output the element itself. output.Append('<').Append(elementName); bool isEmptyElement = xmlReader.IsEmptyElement; if (xmlReader.HasAttributes) { bool isNoLineBreakElement = this.IsNoLineBreakElement(elementName); this.ProcessAttributes( xmlReader, output, elementProcessContext, isNoLineBreakElement, attributeIndetationString); } // Determine if to put ending bracket on new line. bool putEndingBracketOnNewLine = (this.options.PutEndingBracketOnNewLine && elementProcessContext.Current.IsMultlineStartTag); if (putEndingBracketOnNewLine) { // Indent ending bracket just like an attribute. output.Append(Environment.NewLine).Append(attributeIndetationString); } if (isEmptyElement) { if (!putEndingBracketOnNewLine && this.options.SpaceBeforeClosingSlash) { output.Append(' '); } output.Append("/>"); // Self closing element. Remember to pop element context. elementProcessContext.Pop(); } else { output.Append(">"); } }
private void ProcessAttributes( XmlReader xmlReader, StringBuilder output, ElementProcessContext elementProcessContext, bool isNoLineBreakElement, string attributeIndentationString) { var list = new List <AttributeInfo>(xmlReader.AttributeCount); var firstLineList = new List <AttributeInfo>(xmlReader.AttributeCount); while (xmlReader.MoveToNextAttribute()) { var attributeInfo = this.attributeInfoFactory.Create(xmlReader); list.Add(attributeInfo); // Maintain separate list of first line attributes. if (this.options.EnableAttributeReordering && this.IsFirstLineAttribute(attributeInfo.Name)) { firstLineList.Add(attributeInfo); } // Check for xml:space as defined in http://www.w3.org/TR/2008/REC-xml-20081126/#sec-white-space if (xmlReader.IsXmlSpaceAttribute()) { elementProcessContext.Current.IsPreservingSpace = (xmlReader.Value == "preserve"); } } if (this.options.EnableAttributeReordering) { // .NET performs insertion sort if collection partition size is fewer than 16 elements, but it uses // Heapsort or Quicksort under different conditions. This can lead to an unstable sort and randomized // attributbes while formatting. Even though insertion sort is less performant, XAML elements with more // than 16 attributes are not common, so the effect of forcing insertion sort is negligable in all but // the most extreme of cases. - https://msdn.microsoft.com/en-us/library/b0zbh7b6(v=vs.110).aspx list.InsertionSort(this.AttributeInfoComparison); firstLineList.InsertionSort(this.AttributeInfoComparison); } var noLineBreakInAttributes = (list.Count <= this.options.AttributesTolerance) || isNoLineBreakElement; var forceLineBreakInAttributes = false; // Root element? if (elementProcessContext.Count == 2) { switch (this.options.RootElementLineBreakRule) { case LineBreakRule.Default: break; case LineBreakRule.Always: noLineBreakInAttributes = false; forceLineBreakInAttributes = true; break; case LineBreakRule.Never: noLineBreakInAttributes = true; break; default: throw new NotImplementedException(); } } // No need to break attributes. if (noLineBreakInAttributes) { foreach (var attrInfo in list) { var ignoreEncode = IsIgnoreEncodeForAttributes(attrInfo.Name); output.Append(' ').Append(this.attributeInfoFormatter.ToSingleLineString(attrInfo, ignoreEncode)); } elementProcessContext.Current.IsMultlineStartTag = false; } else { // Need to break attributes. var attributeLines = new List <string>(); var currentLineBuffer = new StringBuilder(); int attributeCountInCurrentLineBuffer = 0; int xmlnsAliasesBypassLengthInCurrentLine = 0; AttributeInfo lastAttributeInfo = null; // Process first line attributes. string firstLine = String.Empty; foreach (var attrInfo in firstLineList) { var ignoreEncode = IsIgnoreEncodeForAttributes(attrInfo.Name); firstLine = $"{firstLine} {this.attributeInfoFormatter.ToSingleLineString(attrInfo, ignoreEncode)}"; } if (firstLine.Length > 0) { attributeLines.Add(firstLine); } foreach (AttributeInfo attrInfo in list) { // Skip attributes already added to first line. if (firstLineList.Contains(attrInfo)) { continue; } // Attributes with markup extension, always put on new line if (attrInfo.IsMarkupExtension && this.options.FormatMarkupExtension) { if (currentLineBuffer.Length > 0) { attributeLines.Add(currentLineBuffer.ToString()); currentLineBuffer.Length = 0; attributeCountInCurrentLineBuffer = 0; } attributeLines.Add( this.attributeInfoFormatter.ToMultiLineString(attrInfo, attributeIndentationString)); } else { var ignoreEncode = IsIgnoreEncodeForAttributes(attrInfo.Name); string pendingAppend = this.attributeInfoFormatter.ToSingleLineString(attrInfo, ignoreEncode); var actualPendingAppend = this.xmlEscapingService.RestoreXmlnsAliasesBypass(pendingAppend); xmlnsAliasesBypassLengthInCurrentLine += pendingAppend.Length - actualPendingAppend.Length; bool isAttributeCharLengthExceeded = (attributeCountInCurrentLineBuffer > 0) && (this.options.MaxAttributeCharactersPerLine > 0) && ((currentLineBuffer.Length + pendingAppend.Length - xmlnsAliasesBypassLengthInCurrentLine) > this.options.MaxAttributeCharactersPerLine); bool isAttributeCountExceeded = (this.options.MaxAttributesPerLine > 0) && ((attributeCountInCurrentLineBuffer + 1) > this.options.MaxAttributesPerLine); bool isAttributeRuleGroupChanged = this.options.PutAttributeOrderRuleGroupsOnSeparateLines && (lastAttributeInfo != null) && (lastAttributeInfo.OrderRule.Group != attrInfo.OrderRule.Group); if ((currentLineBuffer.Length > 0) && (forceLineBreakInAttributes || isAttributeCharLengthExceeded || isAttributeCountExceeded || isAttributeRuleGroupChanged)) { attributeLines.Add(currentLineBuffer.ToString()); currentLineBuffer.Length = 0; attributeCountInCurrentLineBuffer = 0; xmlnsAliasesBypassLengthInCurrentLine = 0; } currentLineBuffer.AppendFormat(CultureInfo.InvariantCulture, "{0} ", pendingAppend); attributeCountInCurrentLineBuffer++; xmlnsAliasesBypassLengthInCurrentLine += pendingAppend.Length - actualPendingAppend.Length; } lastAttributeInfo = attrInfo; } if (currentLineBuffer.Length > 0) { attributeLines.Add(currentLineBuffer.ToString()); } for (int i = 0; i < attributeLines.Count; i++) { // Put first attribute line on same line as element? if ((i == 0) && (this.options.KeepFirstAttributeOnSameLine || (firstLineList.Count > 0))) { output.Append(' ').Append(attributeLines[i].Trim()); } else { output.Append(Environment.NewLine) .Append(this.indentService.Normalize(attributeIndentationString + attributeLines[i].Trim())); } } elementProcessContext.Current.IsMultlineStartTag = true; } }
public void Process(XmlReader xmlReader, StringBuilder output, ElementProcessContext elementProcessContext) { output.Append("<?xml "); output.Append(xmlReader.Value.Trim()); output.Append(" ?>"); }