<PackageReference Include="Castle.Core" Version="3.3.2" />

XmlSubtreeWriter

public class XmlSubtreeWriter : XmlWriter
using System; using System.Threading; using System.Xml; namespace Castle.Components.DictionaryAdapter.Xml { public class XmlSubtreeWriter : XmlWriter { private readonly IXmlNode node; private XmlWriter rootWriter; private XmlWriter childWriter; private WriteState state; private int depth; private XmlWriter RootWriter => rootWriter ?? (rootWriter = node.WriteAttributes()); private XmlWriter ChildWriter => childWriter ?? (childWriter = node.WriteChildren()); private bool IsInRootAttribute => state == WriteState.Attribute; private bool IsInRoot => depth > 0; private bool IsInChild => depth > 1; public override WriteState WriteState { get { if (!IsInRoot || state != WriteState.Content) return state; return childWriter.WriteState; } } public XmlSubtreeWriter(IXmlNode node) { if (node == null) throw Error.ArgumentNull("node"); this.node = node; } protected override void Dispose(bool managed) { try { if (managed) { Reset(WriteState.Closed); DisposeWriter(ref rootWriter); DisposeWriter(ref childWriter); } } finally { base.Dispose(managed); } } private void DisposeWriter(ref XmlWriter writer) { Interlocked.Exchange(ref writer, null)?.Close(); } public override void WriteStartDocument(bool standalone) { WriteStartDocument(); } public override void WriteStartDocument() { RequireState(WriteState.Start); state = WriteState.Prolog; } public override void WriteDocType(string name, string pubid, string sysid, string subset) { RequireState(WriteState.Start, WriteState.Prolog); state = WriteState.Prolog; } public override void WriteStartElement(string prefix, string localName, string ns) { try { if (IsInRoot) { ChildWriter.WriteStartElement(prefix, localName, ns); state = WriteState.Content; } else { RequireState(WriteState.Start, WriteState.Prolog); node.Clear(); state = WriteState.Element; } depth++; } catch { Reset(WriteState.Error); throw; } } private void WriteEndElement(Action<XmlWriter> action) { try { if (IsInChild) { action(ChildWriter); state = WriteState.Content; } else { RequireState(WriteState.Element, WriteState.Content); state = WriteState.Prolog; } depth--; } catch { Reset(WriteState.Error); throw; } } public override void WriteEndElement() { WriteEndElement(delegate(XmlWriter w) { w.WriteEndElement(); }); } public override void WriteFullEndElement() { WriteEndElement(delegate(XmlWriter w) { w.WriteFullEndElement(); }); } private void WriteAttribute(Action<XmlWriter> action, WriteState entryState, WriteState exitState) { try { if (IsInChild) action(ChildWriter); else { RequireState(entryState); action(RootWriter); state = exitState; } } catch { Reset(WriteState.Error); throw; } } public override void WriteStartAttribute(string prefix, string localName, string ns) { WriteAttribute(delegate(XmlWriter w) { w.WriteStartAttribute(prefix, localName, ns); }, WriteState.Element, WriteState.Attribute); } public override void WriteEndAttribute() { WriteAttribute(delegate(XmlWriter w) { w.WriteEndAttribute(); }, WriteState.Attribute, WriteState.Element); } private void WriteElementOrAttributeContent(Action<XmlWriter> action) { try { if (IsInChild) action(ChildWriter); else if (IsInRootAttribute) { action(RootWriter); } else { RequireState(WriteState.Element, WriteState.Content); action(ChildWriter); state = WriteState.Content; } } catch { Reset(WriteState.Error); throw; } } public override void WriteString(string text) { WriteElementOrAttributeContent(delegate(XmlWriter w) { w.WriteString(text); }); } public override void WriteCharEntity(char ch) { WriteElementOrAttributeContent(delegate(XmlWriter w) { w.WriteCharEntity(ch); }); } public override void WriteSurrogateCharEntity(char lowChar, char highChar) { WriteElementOrAttributeContent(delegate(XmlWriter w) { w.WriteSurrogateCharEntity(lowChar, highChar); }); } public override void WriteEntityRef(string name) { WriteElementOrAttributeContent(delegate(XmlWriter w) { w.WriteEntityRef(name); }); } public override void WriteChars(char[] buffer, int index, int count) { WriteElementOrAttributeContent(delegate(XmlWriter w) { w.WriteChars(buffer, index, count); }); } public override void WriteBase64(byte[] buffer, int index, int count) { WriteElementOrAttributeContent(delegate(XmlWriter w) { w.WriteBase64(buffer, index, count); }); } public override void WriteRaw(string data) { WriteElementOrAttributeContent(delegate(XmlWriter w) { w.WriteRaw(data); }); } public override void WriteRaw(char[] buffer, int index, int count) { WriteElementOrAttributeContent(delegate(XmlWriter w) { w.WriteRaw(buffer, index, count); }); } private void WriteElementContent(Action<XmlWriter> action) { try { RequireState(WriteState.Element, WriteState.Content); action(ChildWriter); state = WriteState.Content; } catch { Reset(WriteState.Error); throw; } } public override void WriteCData(string text) { WriteElementContent(delegate(XmlWriter w) { w.WriteCData(text); }); } public override void WriteProcessingInstruction(string name, string text) { WriteElementContent(delegate(XmlWriter w) { w.WriteProcessingInstruction(name, text); }); } public override void WriteComment(string text) { WriteElementContent(delegate(XmlWriter w) { w.WriteComment(text); }); } public override void WriteWhitespace(string ws) { WriteElementContent(delegate(XmlWriter w) { w.WriteWhitespace(ws); }); } private void WithWriters(Action<XmlWriter> action, bool worksIfClosed = false, WriteState? resetTo = default(WriteState?)) { try { if (!worksIfClosed) RequireNotClosed(); if (rootWriter != null) action(rootWriter); if (childWriter != null) action(childWriter); if (resetTo.HasValue) Reset(resetTo.Value); } catch { Reset(WriteState.Error); throw; } } public override void Flush() { WithWriters(delegate(XmlWriter w) { w.Flush(); }, false, null); } public override void WriteEndDocument() { WithWriters(delegate(XmlWriter w) { w.WriteEndDocument(); }, false, WriteState.Start); } public override void Close() { Action<XmlWriter> action = delegate(XmlWriter w) { w.Close(); }; WriteState? resetTo = WriteState.Closed; WithWriters(action, true, resetTo); } public override string LookupPrefix(string ns) { try { string text; return (childWriter != null && (text = childWriter.LookupPrefix(ns)) != null) ? text : ((rootWriter != null && (text = rootWriter.LookupPrefix(ns)) != null) ? text : null); } catch { Reset(WriteState.Error); throw; } } private void RequireNotClosed() { if (state == WriteState.Closed || state == WriteState.Error) throw Error.InvalidOperation(); } private void RequireState(WriteState state) { if (this.state != state) throw Error.InvalidOperation(); } private void RequireState(WriteState state1, WriteState state2) { if (state != state1 && state != state2) throw Error.InvalidOperation(); } private void Reset(WriteState state) { depth = 0; this.state = state; } } }