sharplib/ser/XmlSer_Write.cs
2025-11-16 16:13:45 -08:00

200 lines
4.8 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.Xml;
namespace ser;
// --- Primitive Handler ---
public partial class PrimitiveHandler : ser.ITypeHandler
{
public void WriteXml( XmlSer xml, XmlWriter writer, object? obj, string name, Type memberType, bool forceType )
{
if( obj == null )
{
writer.WriteStartElement( name );
writer.WriteAttributeString( "v", "null" );
writer.WriteEndElement();
return;
}
bool writeElements = xml._cfg.POD == POD.Elements || forceType || !( writer is XmlTextWriter );
if( !writeElements && writer is XmlTextWriter tw )
writeElements = tw.WriteState != WriteState.Element;
if( writeElements )
writer.WriteStartElement( name );
if( forceType || xml._cfg.POD == POD.Elements )
{
if( forceType )
writer.WriteAttributeString( "_.t", obj.GetType().FullName );
writer.WriteAttributeString( "v", obj.ToString() );
}
else
{
writer.WriteAttributeString( name, obj.ToString() );
}
if( writeElements )
writer.WriteEndElement();
}
}
// --- Proxy Handler ---
public partial class ProxyHandler : ITypeHandler
{
public void WriteXml( XmlSer xml, XmlWriter writer, object? obj, string name, Type memberType, bool forceType )
{
if( obj == null )
{ xml.GetHandler( typeof( object ) ).WriteXml( xml, writer, null, name, memberType, forceType ); return; }
var ti = xml._meta.Get( obj.GetType() );
if( !ti.ProxyDef.HasValue )
{ log.error( "Proxy write called without proxy def!" ); return; }
writer.WriteStartElement( name );
var proxyStr = ti.ProxyDef.Value.fnSer( obj );
// TODO: Allow arbitrary writing here
writer.WriteAttributeString( "proxy", proxyStr );
writer.WriteEndElement();
}
}
// --- ISerializable Handler ---
public partial class ISerializableHandler : ITypeHandler
{
public void WriteXml( XmlSer xml, XmlWriter writer, object? obj, string name, Type memberType, bool forceType )
{
if( obj == null )
{ /* Write null */ return; }
if( !( obj is ISerializable serObj ) )
{ /* Error */ return; }
writer.WriteStartElement( name );
xml.WriteTypeAttr( writer, memberType, obj.GetType() );
if( xml.HandleGraphWrite( writer, obj, out bool first ) )
{
if( first )
{
var serInfo = new SerializationInfo( obj.GetType(), new FormatterConverter() );
var context = new StreamingContext( StreamingContextStates.All );
serObj.GetObjectData( serInfo, context );
foreach( var member in serInfo )
{
xml.WriteNode( writer, member.Value, refl.TypeToIdentifier( member.Name ), member.ObjectType, true ); // Force type for ISer
}
}
}
writer.WriteEndElement();
}
}
// --- Collection Handler ---
public partial class CollectionHandler : ITypeHandler
{
public void WriteXml( XmlSer xml, XmlWriter writer, object? obj, string name, Type memberType, bool forceType )
{
if( obj == null )
{ /* Write null */ return; }
if( !( obj is IEnumerable collection ) )
{ /* Error */ return; }
writer.WriteStartElement( name );
xml.WriteTypeAttr( writer, memberType, obj.GetType() );
if( xml.HandleGraphWrite( writer, obj, out bool first ) )
{
if( first )
{
Type elemType = GetElementType( obj.GetType() );
int i = 0;
foreach( var item in collection )
{
xml.WriteNode( writer, item, $"i{i++}", elemType, false );
}
}
}
writer.WriteEndElement();
}
}
// --- Object Handler (Default/Complex) ---
public partial class ObjectHandler : ITypeHandler
{
public void WriteXml( XmlSer xml, XmlWriter writer, object? obj, string name, Type memberType, bool forceType )
{
if( obj == null )
{ /* Write null */ return; }
writer.WriteStartElement( name );
xml.WriteTypeAttr( writer, memberType, obj.GetType() );
var ti = xml._meta.Get( obj.GetType() );
if( xml.HandleGraphWrite( writer, obj, out bool first ) )
{
if( first )
{
foreach( var memberMeta in ti.Members )
{
if( !memberMeta.IsPodAttribute ) continue;
var value = memberMeta.GetValue( obj );
if( value != null )
{
try
{
writer.WriteAttributeString( memberMeta.XmlName, value.ToString() );
}
catch( Exception ex )
{
log.exception( ex, $"Writing Att {memberMeta.XmlName} = [{value}]" );
}
}
}
foreach( var memberMeta in ti.Members )
{
if( memberMeta.IsPodAttribute ) continue;
var value = memberMeta.GetValue( obj );
if( value != null )
{
try
{
xml.WriteNode( writer, value, memberMeta.XmlName, memberMeta.Type, false );
}
catch( Exception ex )
{
log.exception( ex, $"Writing Node {memberMeta.XmlName} = [{value}]" );
}
}
}
}
}
writer.WriteEndElement();
}
}