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 0f69ef093c0f8..508a8fa50abbe 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 @@ internal override void WriteStartNamespaceDeclaration(string prefix) 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 @@ public override void WriteStartAttribute(string? prefix, string localName, strin 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 f622c159d9f97..6ca97ede3105e 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 @@ internal override async Task WriteStartNamespaceDeclarationAsync(string prefix) 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 @@ protected internal override async Task WriteStartAttributeAsync(string? prefix, 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 e79b7ff1f00c2..61d85043919b0 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 f12e1e53cb77f..638ee0f401e67 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 b97fb5f2742dd..6f5ada6cab1f9 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 @@ internal override void WriteStartNamespaceDeclaration(string prefix) { 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 @@ public override void WriteStartAttribute(string? prefix, string localName, strin 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 84e3cc4fa7bcd..09d68c92ecb9a 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 @@ internal override async Task WriteStartNamespaceDeclarationAsync(string prefix) 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 @@ protected internal override async Task WriteStartAttributeAsync(string? prefix, 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 f0765630d8d63..d349b820a32b8 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 0000000000000..cd18ebb741164 --- /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()); + } + } +}