Skip to content

Commit

Permalink
Merge pull request #52 from figloalds/master
Browse files Browse the repository at this point in the history
Adiciona uma  opção para ignorar a ordenação dos elementos ao deserializar xml com o FuncoesXML
  • Loading branch information
danilobreda authored Jan 16, 2025
2 parents dc9ecea + 9fcf476 commit 67c3417
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 5 deletions.
95 changes: 95 additions & 0 deletions DFe.Utils/ExtXmlSerializerFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;

namespace DFe.Utils {

public abstract class XmlOrderFreeSerializerFactory {
// Referência https://stackoverflow.com/a/33508815
readonly static XmlAttributeOverrides overrides = new XmlAttributeOverrides();
readonly static object locker = new object();
readonly static Dictionary<Type, XmlSerializer> serializers = new Dictionary<Type, XmlSerializer>();
static HashSet<string> overridesAdded = new HashSet<string>();

static void AddOverrideAttributes(Type type, XmlAttributeOverrides overrides) {

if (type == null || type == typeof(object) || type.IsPrimitive || type == typeof(string) || type == typeof(DateTime)) {
return;
}
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)) {
AddOverrideAttributes(type.GetGenericArguments()[0], overrides);
return;
}
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>)) {
AddOverrideAttributes(type.GetGenericArguments()[0], overrides);
return;
}

var mask = BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Public;
foreach (var member in type.GetProperties(mask).Cast<MemberInfo>().Union(type.GetFields(mask))) {
var otTag = $"{type.Name}_{member.Name}";
if (overridesAdded.Contains(otTag)) {
continue;
}
XmlAttributes overrideAttr = null;
foreach (var attr in member.GetCustomAttributes<XmlElementAttribute>()) {
overrideAttr = overrideAttr ?? new XmlAttributes();
var overrideElt = new XmlElementAttribute(attr.ElementName, attr.Type) { DataType = attr.DataType, ElementName = attr.ElementName, Form = attr.Form, Namespace = attr.Namespace, Type = attr.Type };
if(attr.IsNullable) {
// Isso aqui deve ter uma logica personalizada no setter, colocar ali em cima causa erro
overrideElt.IsNullable = true;
}
overrideAttr.XmlElements.Add(overrideElt);
if(attr.Type != null) {
AddOverrideAttributes(attr.Type, overrides);
}
}
foreach (var attr in member.GetCustomAttributes<XmlArrayAttribute>()) {
overrideAttr = overrideAttr ?? new XmlAttributes();
overrideAttr.XmlArray = new XmlArrayAttribute { ElementName = attr.ElementName, Form = attr.Form, IsNullable = attr.IsNullable, Namespace = attr.Namespace };
}
foreach (var attr in member.GetCustomAttributes<XmlArrayItemAttribute>()) {
overrideAttr = overrideAttr ?? new XmlAttributes();
overrideAttr.XmlArrayItems.Add(attr);
}
foreach (var attr in member.GetCustomAttributes<XmlAnyElementAttribute>()) {
overrideAttr = overrideAttr ?? new XmlAttributes();
overrideAttr.XmlAnyElements.Add(new XmlAnyElementAttribute { Name = attr.Name, Namespace = attr.Namespace });
}
if (overrideAttr != null) {
overridesAdded.Add(otTag);
overrides.Add(type, member.Name, overrideAttr);
}
var mType = (member is PropertyInfo pi ? pi.PropertyType : member is FieldInfo fi ? fi.FieldType : null);
AddOverrideAttributes(mType, overrides);
}
}

public static XmlSerializer GetSerializer(Type type) {
if (type == null)
throw new ArgumentNullException("type");
lock (locker) {
XmlSerializer serializer;
if (!serializers.TryGetValue(type, out serializer)) {
AddOverrideAttributes(type, overrides);
serializers[type] = serializer = new XmlSerializer(type, overrides);
}
return serializer;
}
}

}

public static class TypeExtensions {
public static IEnumerable<Type> BaseTypesAndSelf(this Type type) {
while (type != null) {
yield return type;
type = type.BaseType;
}
}
}
}
24 changes: 19 additions & 5 deletions DFe.Utils/FuncoesXml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,21 @@ public static string ClasseParaXmlString<T>(T objeto)
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="input"></param>
/// <param name="ignorarOrdenacaoElementos">true caso o XML possa conter elementos fora de ordem</param>
/// <returns></returns>
public static T XmlStringParaClasse<T>(string input) where T : class
public static T XmlStringParaClasse<T>(string input, bool ignorarOrdenacaoElementos = false) where T : class
{
var keyNomeClasseEmUso = typeof(T).FullName;
var ser = BuscarNoCache(keyNomeClasseEmUso, typeof(T));

XmlSerializer serializador;
if(ignorarOrdenacaoElementos) {
serializador = XmlOrderFreeSerializerFactory.GetSerializer(typeof(T));
} else {
serializador = BuscarNoCache(keyNomeClasseEmUso, typeof(T));
}

using (var sr = new StringReader(input))
return (T)ser.Deserialize(sr);
return (T)serializador.Deserialize(sr);
}

/// <summary>
Expand All @@ -61,15 +68,22 @@ public static T XmlStringParaClasse<T>(string input) where T : class
/// <typeparam name="T">Classe</typeparam>
/// <param name="arquivo">Arquivo XML</param>
/// <returns>Retorna a classe</returns>
public static T ArquivoXmlParaClasse<T>(string arquivo) where T : class
public static T ArquivoXmlParaClasse<T>(string arquivo, bool ignorarOrdenacaoElementos = false) where T : class
{
if (!File.Exists(arquivo))
{
throw new FileNotFoundException("Arquivo " + arquivo + " não encontrado!");
}

var keyNomeClasseEmUso = typeof(T).FullName;
var serializador = BuscarNoCache(keyNomeClasseEmUso, typeof(T));

XmlSerializer serializador;
if (ignorarOrdenacaoElementos) {
serializador = XmlOrderFreeSerializerFactory.GetSerializer(typeof(T));
} else {
serializador = BuscarNoCache(keyNomeClasseEmUso, typeof(T));
}

var stream = new FileStream(arquivo, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
try
{
Expand Down

0 comments on commit 67c3417

Please sign in to comment.