using System.Collections.Generic;
using System.Xml.Serialization;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO.Compression;
public static partial class XmlExtensions
public static void WriteAttribute(this XmlWriter writer, string localName, IEnumerable<(char [] Buffer, int Length)> valueSegments) =>
WriteAttribute(writer, null, localName, null, valueSegments);
public static void WriteAttribute(this XmlWriter writer, string localName, string namespaceUri, IEnumerable<(char [] Buffer, int Length)> valueSegments) =>
WriteAttribute(writer, null, localName, namespaceUri, valueSegments);
public static void WriteAttribute(this XmlWriter writer, string prefix, string localName, string namespaceUri, IEnumerable<(char [] Buffer, int Length)> valueSegments)
writer.WriteStartAttribute(prefix, localName, namespaceUri);
char [] surrogateBuffer = null;
foreach (var segment in valueSegments)
if (surrogateBuffer != null && surrogateBuffer[0] != '\0')
surrogateBuffer[1] = segment.Buffer[start++];
writer.WriteChars(surrogateBuffer, 0, 2);
surrogateBuffer[0] = surrogateBuffer[1] = '\0';
int count = segment.Length - start;
if (count > 0 && char.IsHighSurrogate(segment.Buffer[segment.Length-1]))
(surrogateBuffer = surrogateBuffer ?? new char[2])[0] = segment.Buffer[segment.Length-1];
writer.WriteChars(segment.Buffer, start, count);
writer.WriteEndAttribute();
if (surrogateBuffer != null && surrogateBuffer[0] != '\0')
throw new XmlException(string.Format("Unterminated surrogate pair {0}", surrogateBuffer[0]));
public static class ByteExtensions
public static void ByteToHexBitFiddle(ReadOnlySpan<byte> bytes, Span<char> c)
if (c.Length < 2* bytes.Length)
throw new ArgumentException("c.Length < 2* bytes.Length");
for (int i = 0; i < bytes.Length; i++) {
c[i * 2] = (char)(55 + b + (((b-10)>>31)&-7));
c[i * 2 + 1] = (char)(55 + b + (((b-10)>>31)&-7));
public static IEnumerable<(char [] segment, int length)> GetHexCharSegments(ReadOnlyMemory<byte> bytes, int chunkSize = 1000)
var buffer = new char[2*chunkSize];
var length = bytes.Length;
while (pos < length - chunkSize)
ByteExtensions.ByteToHexBitFiddle(bytes.Span.Slice(pos, chunkSize), buffer);
yield return (buffer, buffer.Length);
ByteExtensions.ByteToHexBitFiddle(bytes.Span.Slice(pos), buffer);
yield return (buffer, 2*(length - pos));
public class ElementEventArgs : EventArgs
public XName Element { get; init; }
public Stack<XName> ElementStack { get; init; }
public class NotifyingXmlWriter : XmlWriterProxy
readonly Stack<XName> elements = new Stack<XName>();
public NotifyingXmlWriter(XmlWriter baseWriter) : base(baseWriter) { }
public event EventHandler<ElementEventArgs> OnElementStarted;
public event EventHandler<ElementEventArgs> OnElementEnded;
public override void WriteStartElement(string prefix, string localName, string ns)
base.WriteStartElement(prefix, localName, ns);
var name = XName.Get(localName, ns);
OnElementStarted?.Invoke(this, new ElementEventArgs { Element = name, ElementStack = elements });
public override void WriteEndElement()
var name = elements.Pop();
OnElementEnded?.Invoke(this, new ElementEventArgs { Element = name, ElementStack = elements });
public class XmlWriterProxy : XmlWriter
readonly XmlWriter baseWriter;
public XmlWriterProxy(XmlWriter baseWriter) => this.baseWriter = baseWriter ?? throw new ArgumentNullException();
protected virtual bool IsSuspended { get { return false; } }
public override void Close() => baseWriter.Close();
public override void Flush() => baseWriter.Flush();
public override string LookupPrefix(string ns) => baseWriter.LookupPrefix(ns);
public override void WriteBase64(byte[] buffer, int index, int count)
baseWriter.WriteBase64(buffer, index, count);
public override void WriteCData(string text)
baseWriter.WriteCData(text);
public override void WriteCharEntity(char ch)
baseWriter.WriteCharEntity(ch);
public override void WriteChars(char[] buffer, int index, int count)
baseWriter.WriteChars(buffer, index, count);
public override void WriteComment(string text)
baseWriter.WriteComment(text);
public override void WriteDocType(string name, string pubid, string sysid, string subset)
baseWriter.WriteDocType(name, pubid, sysid, subset);
public override void WriteEndAttribute()
baseWriter.WriteEndAttribute();
public override void WriteEndDocument()
baseWriter.WriteEndDocument();
public override void WriteEndElement()
baseWriter.WriteEndElement();
public override void WriteEntityRef(string name)
baseWriter.WriteEntityRef(name);
public override void WriteFullEndElement()
baseWriter.WriteFullEndElement();
public override void WriteProcessingInstruction(string name, string text)
baseWriter.WriteProcessingInstruction(name, text);
public override void WriteRaw(string data)
baseWriter.WriteRaw(data);
public override void WriteRaw(char[] buffer, int index, int count)
baseWriter.WriteRaw(buffer, index, count);
public override void WriteStartAttribute(string prefix, string localName, string ns)
baseWriter.WriteStartAttribute(prefix, localName, ns);
public override void WriteStartDocument(bool standalone) => baseWriter.WriteStartDocument(standalone);
public override void WriteStartDocument() => baseWriter.WriteStartDocument();
public override void WriteStartElement(string prefix, string localName, string ns)
baseWriter.WriteStartElement(prefix, localName, ns);
public override WriteState WriteState => baseWriter.WriteState;
public override void WriteString(string text)
baseWriter.WriteString(text);
public override void WriteSurrogateCharEntity(char lowChar, char highChar)
baseWriter.WriteSurrogateCharEntity(lowChar, highChar);
public override void WriteWhitespace(string ws)
baseWriter.WriteWhitespace(ws);
public static void Test()
public static void Test(int n)
public static void Test(string prefix, int n)
var doc = XDocument.Parse(GetXml());
var stringBuilder = new StringBuilder();
stringBuilder.Append(prefix);
for (int i = 0; i < n; i++)
stringBuilder.Append("𩸽");
using var textWriter = new StringWriter();
using (var xmlWriter = XmlWriter.Create(textWriter))
xmlWriter.WriteStartElement("Test");
xmlWriter.WriteAttribute("AttrbuteName", stringBuilder.GetSegments());
xmlWriter.WriteEndElement();
var xml = textWriter.ToString();
Assert.IsFalse(xml.Contains("�"));
Assert.IsTrue(xml.Contains("AttrbuteName=\"" + stringBuilder.ToString() + "\""));
static void TestXDocument(int n)
Content = Enumerable.Range(0, n).Select(i => unchecked((byte)i)).ToArray(),
var xdocument = XDocument.Parse(GetXml());
string fileName = @"Question68941254.xml";
XNamespace targetNamespace = "";
XName targetName = targetNamespace + "TheNode";
using (var textWriter = new StreamWriter(fileName))
using (var innerXmlWriter = XmlWriter.Create(textWriter, new XmlWriterSettings { Indent = true }))
using (var xmlWriter = new NotifyingXmlWriter(innerXmlWriter))
xmlWriter.OnElementStarted += (o, e) =>
if (e.Element == targetName)
((XmlWriter)o).WriteAttribute("TheAttribute", ByteExtensions.GetHexCharSegments(value.RawArtifact.Content.AsMemory(), 1024));
xdocument.WriteTo(xmlWriter);
Console.WriteLine(File.ReadAllText(fileName));
static string GetXml() =>
<SomeOtherNode>some value</SomeOtherNode>
<TheNode someOtherAttribute=""101""><foo></foo>the node value</TheNode>
<AnotherNode>another value</AnotherNode>
public static partial class StringBuilderExtensions
public static IEnumerable<(char [] segment, int length)> GetSegments(this StringBuilder sb, int bufferSize = 1024)
var buffer = new char[bufferSize];
for (int i = 0; i < sb.Length; i += buffer.Length)
int length = Math.Min(buffer.Length, sb.Length - i);
sb.CopyTo(i, buffer, length);
yield return (buffer, length);
public static void Main()
Console.WriteLine("Environment version: {0} ({1})", System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription , GetNetCoreVersion());
Console.WriteLine("Failed with unhandled exception: ");
public static string GetNetCoreVersion()
var assembly = typeof(System.Runtime.GCSettings).GetTypeInfo().Assembly;
var assemblyPath = assembly.Location.Split(new[] { '/', '\\' }, StringSplitOptions.RemoveEmptyEntries);
int netCoreAppIndex = Array.IndexOf(assemblyPath, "Microsoft.NETCore.App");
if (netCoreAppIndex > 0 && netCoreAppIndex < assemblyPath.Length - 2)
return assemblyPath[netCoreAppIndex + 1];
If you check the [reference source for `XAttribute`](https:
This doesn't precisely answer your question, but if you were to write your XML with `XmlWriter` you could write the attribute value in chunks using `XmlWriter.WriteChars()`. See https://dotnetfiddle.net/InBShg for a demo.
If you are modifying an existing XML file, you might consider a streaming transformation along the lines of [Combining the XmlReader and XmlWriter classes for simple streaming transformations](https:
public static void ByteToHexBitFiddle(byte [] bytes, int byteStart, int count, char [] array, int charStart)
for (int i = byteStart, byteEnd = byteStart + count; i < byteEnd; i++, charStart += 2)
ByteToHexBitFiddle(bytes[i], array, charStart);
public static void ByteToHexBitFiddle(byte theByte, char [] array, int start)
var c = array.AsSpan().Slice(start, 2);
c[0] = (char)(55 + b + (((b-10)>>31)&-7));
c[1] = (char)(55 + b + (((b-10)>>31)&-7));