using System.Collections.Generic;
using System.Xml.Serialization;
using System.Diagnostics;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Text.RegularExpressions;
using System.Globalization;
using System.ComponentModel.DataAnnotations;
using System.Collections;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
[XmlRoot("Comprobante", Namespace = "http://cfdi")]
public class Comprobante : IValidatableObject
[XmlArray("Conceptos"), XmlArrayItem(typeof(Concepto), ElementName = "Concepto")]
public List<Concepto> Conceptos { get; set; }
public Addenda Addenda { get; set; }
public XmlNode[] Nodes { get; set; }
[XmlType("Concepto", Namespace = "http://cfdi")]
public interface IValidatableObject
public static void Test()
foreach (var xml in GetXml())
var comprobante = xml.LoadFromXml<Comprobante>();
var xml2 = comprobante.GetXml(xml.ExtractRootNamespaces());
Console.WriteLine("\nRe-serialized XML: ");
Assert.IsTrue(XNode.DeepEquals(XElement.Parse(xml), XElement.Parse(xml2)));
Console.WriteLine("Original and re-serialized XML are equivalent.");
Console.WriteLine("\nDone tests.");
@"<cfdi:Comprobante xmlns:cfdi=""http://cfdi"">
<bfa2:AddendaBuzonFiscal version=""2.0"" xmlns:bfa2=""http://www.buzonfiscal.com/ns/addenda/bf/2""><bfa2:TipoDocumento nombreCorto=""FAC"" descripcion=""Factura""/><bfa2:CFD totalConLetra=""CINCUENTA Y DOS MIL QUINIENTOS OCHENTA Y NUEVE PESOS 64/100 M.N."" observaciones=""OBSERVACIONES""/><bfa2:Extra atributo=""ClaveTransportista"" valor=""00328""/><bfa2:Extra atributo=""NoRelacionPemex"" valor=""1-2""/>
<bfa2:Extra atributo=""NoConvenio"" valor=""5""/>
</bfa2:AddendaBuzonFiscal>
<Encabezado NumOrden="""" NumFacturaOriginal="""" FechaDePedido=""""/>
<Envio Calle="""" NoExterior="""" Colonia="""" Localidad="""" Municipio="""" Estado="""" Pais="""" CodigoPostal="""" NombreEnviar=""""/><Detalle OrdenCompraLinea=""10"" GRNumber=""GRN""/><Detalle OrdenCompraLinea=""10"" GRNumber=""GRN""/><Detalle OrdenCompraLinea=""10"" GRNumber=""GRN""/>
@"<cfdi:Comprobante xmlns:cfdi=""http://cfdi"">
<cfdi:Addenda>Hello this is some simple text for Addenda</cfdi:Addenda>
@"<cfdi:Comprobante xmlns:cfdi=""http://cfdi"">
<cfdi:Addenda>This is some mixed content<Foo>This is nested mixed content</Foo>This is the end of the mixed content.</cfdi:Addenda>
public class AssertionFailedException : System.Exception
public AssertionFailedException() : base() { }
public AssertionFailedException(string s) : base(s) { }
public static class Assert
public static void IsTrue(bool value)
public static void IsTrue(bool value, string message)
throw new AssertionFailedException(message ?? "failed");
public static partial class XmlSerializationHelper
public static T LoadFromXml<T>(this string xmlString, XmlSerializer serial = null)
serial = serial ?? new XmlSerializer(typeof(T));
using (var reader = new StringReader(xmlString))
return (T)serial.Deserialize(reader);
public static string GetXml<T>(this T obj, bool omitStandardNamespaces)
return obj.GetXml(null, omitStandardNamespaces);
public static string GetXml<T>(this T obj, XmlSerializer serializer = null)
return obj.GetXml(serializer, false);
public static string GetXml<T>(this T obj, XmlSerializerNamespaces ns)
return GetXml(obj, new XmlSerializer(obj.GetType()), ns);
public static string GetXml<T>(this T obj, XmlSerializer serializer, bool omitStandardNamespaces)
XmlSerializerNamespaces ns = null;
if (omitStandardNamespaces)
ns = new XmlSerializerNamespaces();
return obj.GetXml(serializer, ns);
public static string GetXml<T>(this T obj, XmlSerializer serializer, XmlSerializerNamespaces ns)
using (var textWriter = new StringWriter())
var settings = new XmlWriterSettings() { Indent = true };
using (var xmlWriter = XmlWriter.Create(textWriter, settings))
(serializer ?? new XmlSerializer(obj.GetType())).Serialize(xmlWriter, obj, ns);
return textWriter.ToString();
public static partial class XmlSerializationHelper
public static XmlSerializerNamespaces ExtractRootNamespaces(this string xml)
var ns = new XmlSerializerNamespaces();
using (var reader = XmlReader.Create(new StringReader(xml)))
if (reader.NodeType == XmlNodeType.Element)
while (reader.MoveToNextAttribute())
if (reader.Name == "xmlns")
ns.Add("", reader.Value);
else if (reader.Name.StartsWith("xmlns:"))
ns.Add(reader.Name.Substring("xmlns:".Length), reader.Value);
public static void Main()
Console.WriteLine("Roslyn 2.0 Compiler; Environment version: " + Environment.Version);
Console.WriteLine("Uncaught exception: ");