From c00942f26148fb4b4a5b5103317aeb5c53f5e337 Mon Sep 17 00:00:00 2001 From: devsko Date: Thu, 9 Feb 2023 18:45:39 +0100 Subject: [PATCH] XmlWriter respects NewLineOnAttributes when writing xmlns (#81822) * XmlWriter respects NewLineOnAttributes when writing xmlns * formatting --- .../src/System/Xml/Core/XmlEncodedRawTextWriter.cs | 21 +++++++++++-- .../Xml/Core/XmlEncodedRawTextWriterAsync.cs | 22 ++++++++++++-- .../Xml/Core/XmlRawTextWriterGenerator.ttinclude | 21 +++++++++++-- .../Core/XmlRawTextWriterGeneratorAsync.ttinclude | 22 ++++++++++++-- .../src/System/Xml/Core/XmlUtf8RawTextWriter.cs | 21 +++++++++++-- .../System/Xml/Core/XmlUtf8RawTextWriterAsync.cs | 22 ++++++++++++-- .../tests/System.Private.Xml.Tests.csproj | 3 +- .../tests/XmlWriter/WriteWithXmlnsNewLine.cs | 35 ++++++++++++++++++++++ 8 files changed, 154 insertions(+), 13 deletions(-) create mode 100644 src/libraries/System.Private.Xml/tests/XmlWriter/WriteWithXmlnsNewLine.cs diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlEncodedRawTextWriter.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlEncodedRawTextWriter.cs index 0f69ef0..508a8fa 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlEncodedRawTextWriter.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlEncodedRawTextWriter.cs @@ -430,13 +430,18 @@ namespace System.Xml if (_trackTextContent && _inTextContent) { ChangeTextContentMark(false); } + if (_attrEndPos == _bufPos) + { + _bufChars[_bufPos++] = (char)' '; + } + if (prefix.Length == 0) { - RawText(" xmlns=\""); + RawText("xmlns=\""); } else { - RawText(" xmlns:"); + RawText("xmlns:"); RawText(prefix); _bufChars[_bufPos++] = (char)'='; _bufChars[_bufPos++] = (char)'"'; @@ -2037,6 +2042,18 @@ namespace System.Xml base.WriteStartAttribute(prefix, localName, ns); } + // Same as base class, plus possible indentation. + internal override void WriteStartNamespaceDeclaration(string prefix) + { + // Add indentation + if (_newLineOnAttributes) + { + WriteIndent(); + } + + base.WriteStartNamespaceDeclaration(prefix); + } + public override void WriteCData(string? text) { _mixedContent = true; diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlEncodedRawTextWriterAsync.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlEncodedRawTextWriterAsync.cs index f622c15..6ca97ed 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlEncodedRawTextWriterAsync.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlEncodedRawTextWriterAsync.cs @@ -318,13 +318,18 @@ namespace System.Xml if (_trackTextContent && _inTextContent) { ChangeTextContentMark(false); } + if (_attrEndPos == _bufPos) + { + _bufChars[_bufPos++] = (char)' '; + } + if (prefix.Length == 0) { - await RawTextAsync(" xmlns=\"").ConfigureAwait(false); + await RawTextAsync("xmlns=\"").ConfigureAwait(false); } else { - await RawTextAsync(" xmlns:").ConfigureAwait(false); + await RawTextAsync("xmlns:").ConfigureAwait(false); await RawTextAsync(prefix).ConfigureAwait(false); _bufChars[_bufPos++] = (char)'='; _bufChars[_bufPos++] = (char)'"'; @@ -1976,6 +1981,19 @@ namespace System.Xml await base.WriteStartAttributeAsync(prefix, localName, ns).ConfigureAwait(false); } + // Same as base class, plus possible indentation. + internal override async Task WriteStartNamespaceDeclarationAsync(string prefix) + { + CheckAsyncCall(); + // Add indentation + if (_newLineOnAttributes) + { + await WriteIndentAsync().ConfigureAwait(false); + } + + await base.WriteStartNamespaceDeclarationAsync(prefix).ConfigureAwait(false); + } + public override Task WriteCDataAsync(string? text) { CheckAsyncCall(); diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlRawTextWriterGenerator.ttinclude b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlRawTextWriterGenerator.ttinclude index e79b7ff..61d8504 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlRawTextWriterGenerator.ttinclude +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlRawTextWriterGenerator.ttinclude @@ -458,13 +458,18 @@ namespace System.Xml #><#= SetTextContentMark(3, false) #> + if (_attrEndPos == _bufPos) + { + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)' '; + } + if (prefix.Length == 0) { - RawText(" xmlns=\""); + RawText("xmlns=\""); } else { - RawText(" xmlns:"); + RawText("xmlns:"); RawText(prefix); <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'='; <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'"'; @@ -2090,6 +2095,18 @@ namespace System.Xml base.WriteStartAttribute(prefix, localName, ns); } + // Same as base class, plus possible indentation. + internal override void WriteStartNamespaceDeclaration(string prefix) + { + // Add indentation + if (_newLineOnAttributes) + { + WriteIndent(); + } + + base.WriteStartNamespaceDeclaration(prefix); + } + public override void WriteCData(string text) { _mixedContent = true; diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlRawTextWriterGeneratorAsync.ttinclude b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlRawTextWriterGeneratorAsync.ttinclude index f12e1e5..638ee0f 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlRawTextWriterGeneratorAsync.ttinclude +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlRawTextWriterGeneratorAsync.ttinclude @@ -321,13 +321,18 @@ namespace System.Xml #><#= SetTextContentMark(3, false) #> + if (_attrEndPos == _bufPos) + { + <#= BufferName #>[_bufPos++] = (<#= BufferType #>)' '; + } + if (prefix.Length == 0) { - await RawTextAsync(" xmlns=\"").ConfigureAwait(false); + await RawTextAsync("xmlns=\"").ConfigureAwait(false); } else { - await RawTextAsync(" xmlns:").ConfigureAwait(false); + await RawTextAsync("xmlns:").ConfigureAwait(false); await RawTextAsync(prefix).ConfigureAwait(false); <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'='; <#= BufferName #>[_bufPos++] = (<#= BufferType #>)'"'; @@ -1919,6 +1924,19 @@ namespace System.Xml await base.WriteStartAttributeAsync(prefix, localName, ns).ConfigureAwait(false); } + // Same as base class, plus possible indentation. + internal override async Task WriteStartNamespaceDeclarationAsync(string prefix) + { + CheckAsyncCall(); + // Add indentation + if (_newLineOnAttributes) + { + await WriteIndentAsync().ConfigureAwait(false); + } + + await base.WriteStartNamespaceDeclarationAsync(prefix).ConfigureAwait(false); + } + public override Task WriteCDataAsync(string text) { CheckAsyncCall(); diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlUtf8RawTextWriter.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlUtf8RawTextWriter.cs index b97fb5f..6f5ada6 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlUtf8RawTextWriter.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlUtf8RawTextWriter.cs @@ -363,13 +363,18 @@ namespace System.Xml { Debug.Assert(prefix != null); + if (_attrEndPos == _bufPos) + { + _bufBytes[_bufPos++] = (byte)' '; + } + if (prefix.Length == 0) { - RawText(" xmlns=\""); + RawText("xmlns=\""); } else { - RawText(" xmlns:"); + RawText("xmlns:"); RawText(prefix); _bufBytes[_bufPos++] = (byte)'='; _bufBytes[_bufPos++] = (byte)'"'; @@ -1894,6 +1899,18 @@ namespace System.Xml base.WriteStartAttribute(prefix, localName, ns); } + // Same as base class, plus possible indentation. + internal override void WriteStartNamespaceDeclaration(string prefix) + { + // Add indentation + if (_newLineOnAttributes) + { + WriteIndent(); + } + + base.WriteStartNamespaceDeclaration(prefix); + } + public override void WriteCData(string? text) { _mixedContent = true; diff --git a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlUtf8RawTextWriterAsync.cs b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlUtf8RawTextWriterAsync.cs index 84e3cc4..09d68c9 100644 --- a/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlUtf8RawTextWriterAsync.cs +++ b/src/libraries/System.Private.Xml/src/System/Xml/Core/XmlUtf8RawTextWriterAsync.cs @@ -282,13 +282,18 @@ namespace System.Xml CheckAsyncCall(); Debug.Assert(prefix != null); + if (_attrEndPos == _bufPos) + { + _bufBytes[_bufPos++] = (byte)' '; + } + if (prefix.Length == 0) { - await RawTextAsync(" xmlns=\"").ConfigureAwait(false); + await RawTextAsync("xmlns=\"").ConfigureAwait(false); } else { - await RawTextAsync(" xmlns:").ConfigureAwait(false); + await RawTextAsync("xmlns:").ConfigureAwait(false); await RawTextAsync(prefix).ConfigureAwait(false); _bufBytes[_bufPos++] = (byte)'='; _bufBytes[_bufPos++] = (byte)'"'; @@ -1841,6 +1846,19 @@ namespace System.Xml await base.WriteStartAttributeAsync(prefix, localName, ns).ConfigureAwait(false); } + // Same as base class, plus possible indentation. + internal override async Task WriteStartNamespaceDeclarationAsync(string prefix) + { + CheckAsyncCall(); + // Add indentation + if (_newLineOnAttributes) + { + await WriteIndentAsync().ConfigureAwait(false); + } + + await base.WriteStartNamespaceDeclarationAsync(prefix).ConfigureAwait(false); + } + public override Task WriteCDataAsync(string? text) { CheckAsyncCall(); diff --git a/src/libraries/System.Private.Xml/tests/System.Private.Xml.Tests.csproj b/src/libraries/System.Private.Xml/tests/System.Private.Xml.Tests.csproj index f076563..d349b82 100644 --- a/src/libraries/System.Private.Xml/tests/System.Private.Xml.Tests.csproj +++ b/src/libraries/System.Private.Xml/tests/System.Private.Xml.Tests.csproj @@ -254,7 +254,6 @@ - PreserveNewest @@ -326,6 +325,7 @@ + @@ -437,6 +437,7 @@ + diff --git a/src/libraries/System.Private.Xml/tests/XmlWriter/WriteWithXmlnsNewLine.cs b/src/libraries/System.Private.Xml/tests/XmlWriter/WriteWithXmlnsNewLine.cs new file mode 100644 index 0000000..cd18ebb --- /dev/null +++ b/src/libraries/System.Private.Xml/tests/XmlWriter/WriteWithXmlnsNewLine.cs @@ -0,0 +1,35 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace System.Xml.XmlWriterTests +{ + public class XmlWriterTests_XmlnsNewLine + { + [Fact] + public static void WriteWithXmlnsNewLine() + { + XmlDocument xml = new(); + xml.LoadXml(""); + + XmlWriterSettings settings = new(); + settings.NewLineOnAttributes = true; + settings.NewLineChars = "\n"; + settings.Indent = true; + settings.IndentChars = " "; + + StringBuilder output = new(); + using (XmlWriter writer = XmlWriter.Create(output, settings)) + { + xml.Save(writer); + } + + Assert.Equal("\n\n \n", output.ToString()); + } + } +} -- 2.7.4