Leer nodos XML Factura Electronica

Hola tyros!, hoy quiero compartirles la forma que utilizo para leer los nodos de un XML; específicamente el XML de la factura electrónica 3.3 del SAT México.

Para este ejemplo vamos a leer varios datos del XML, como son


  • Folio
  • Serie
  • Sub Total
  • Total

Luego leeremos, también, el nodo "Impuestos" con todo su contenido.

En este ejemplo asumiremos que el XML contiene todos los elementos que estamos buscando, en caso de que tu XML no los contenga, haz las adaptaciones necesarias para evitar errores relacionados con datos nulos.

Comencemos cargando el XML:

XmlDocument doc = new XmlDocument();
doc.Load(xml);//Leer el XML


Luego, requerimos agregar un manejador de "namespaces", esto nos permitirá acceder a los nodos con el prefijo "cfdi"

//agregamos un Namespace, que usaremos para buscar que el nodo no exista:
XmlNamespaceManager nsm = new XmlNamespaceManager(doc.NameTable);
nsm.AddNamespace("cfdi", "http://www.sat.gob.mx/cfd/3");


El siguiente paso es acceder al nodo "Comprobante", para poder obtener los valores de sus atributos


//Accedemos a nodo "Comprobante"
XmlNode nodeComprobante = doc.SelectSingleNode("//cfdi:Comprobante", nsm);


A continuacion, obtenemos los valores que necesitamos:

//Obtener Folio, Serie, SubTotal y Total
string varFolio = nodeComprobante.Attributes["Folio"].Value;
string varSerie = nodeComprobante.Attributes["Serie"].Value;
string varSubTotal = nodeComprobante.Attributes["SubTotal"].Value;
string varTotal = nodeComprobante.Attributes["Total"].Value;
Response.Write(String.Format("Serie: {0}, Folio: {1}, SubTotal: {2}, Total: {3}", varSerie, varFolio, varSubTotal, varTotal));


Ahora vamos a obtener el nodo "Impuestos" con todo su contenido incluido. Para hacemos lo siguiente:


//Obtener impuestos
XmlNode nodeImpuestos = nodeComprobante.SelectSingleNode("cfdi:Impuestos", nsm);


Ahora obtenemos los totales de los impuestos:

//Obtenemos TotalImpuestosRetenidos y TotalImpuestosTrasladados
string varTotalImpuestosRetenidos = nodeImpuestos.Attributes["TotalImpuestosRetenidos"].Value;
string varTotalImpuestosTrasladados = nodeImpuestos.Attributes["TotalImpuestosTrasladados"].Value;


Para la siguiente parte utilizaremos bucles/ciclos para leer la información.

Veamos la parte de las retenciones y los traslados:

//Obtener impuestos retenidos
Response.Write("Retenciones: <br />");
XmlNode nodeImpuestosRetenciones = nodeImpuestos.SelectSingleNode("cfdi:Retenciones", nsm);
    foreach (XmlNode node in nodeImpuestosRetenciones.SelectNodes("cfdi:Retencion", nsm)) {
    Response.Write(String.Format("Impuesto: {0}, Importe: {1} <br />",
                                    node.Attributes["Impuesto"].Value,
                                    node.Attributes["Importe"].Value));
}

//Obtener impuestos trasladados
Response.Write("Traslados: <br />");
XmlNode nodeImpuestosTraslados = nodeImpuestos.SelectSingleNode("cfdi:Traslados", nsm);
foreach (XmlNode node in nodeImpuestosTraslados.SelectNodes("cfdi:Traslado", nsm))
{
    Response.Write(String.Format("Impuesto: {0}, Importe: {1} <br />",
                                    node.Attributes["Impuesto"].Value,
                                    node.Attributes["Importe"].Value));
}


Esto seria todo, por si las dudas, aquí les dejo el código completo:

//Factura
XmlDocument doc = new XmlDocument();
doc.Load(xml);//Leer el XML

//agregamos un Namespace, que usaremos para buscar que el nodo no exista:
XmlNamespaceManager nsm = new XmlNamespaceManager(doc.NameTable);
nsm.AddNamespace("cfdi", "http://www.sat.gob.mx/cfd/3");

//Accedemos a nodo "Comprobante"
XmlNode nodeComprobante = doc.SelectSingleNode("//cfdi:Comprobante", nsm);

//Obtener Folio, Serie, SubTotal y Total
string varFolio = nodeComprobante.Attributes["Folio"].Value;
string varSerie = nodeComprobante.Attributes["Serie"].Value;
string varSubTotal = nodeComprobante.Attributes["SubTotal"].Value;
string varTotal = nodeComprobante.Attributes["Total"].Value;
Response.Write(String.Format("Serie: {0}, Folio: {1}, SubTotal: {2}, Total: {3}", varSerie, varFolio, varSubTotal, varTotal));

//Obtener impuestos
XmlNode nodeImpuestos = nodeComprobante.SelectSingleNode("cfdi:Impuestos", nsm);
//Obtenemos TotalImpuestosRetenidos y TotalImpuestosTrasladados
string varTotalImpuestosRetenidos = nodeImpuestos.Attributes["TotalImpuestosRetenidos"].Value;
string varTotalImpuestosTrasladados = nodeImpuestos.Attributes["TotalImpuestosTrasladados"].Value;

//Obtener impuestos retenidos
Response.Write("Retenciones: <br />");
XmlNode nodeImpuestosRetenciones = nodeImpuestos.SelectSingleNode("cfdi:Retenciones", nsm);
    foreach (XmlNode node in nodeImpuestosRetenciones.SelectNodes("cfdi:Retencion", nsm)) {
    Response.Write(String.Format("Impuesto: {0}, Importe: {1} <br />",
                                    node.Attributes["Impuesto"].Value,
                                    node.Attributes["Importe"].Value));
}

//Obtener impuestos trasladados
Response.Write("Traslados: <br />");
XmlNode nodeImpuestosTraslados = nodeImpuestos.SelectSingleNode("cfdi:Traslados", nsm);
foreach (XmlNode node in nodeImpuestosTraslados.SelectNodes("cfdi:Traslado", nsm))
{
    Response.Write(String.Format("Impuesto: {0}, Importe: {1} <br />",
                                    node.Attributes["Impuesto"].Value,
                                    node.Attributes["Importe"].Value));
}


Espero que les sea de utilidad. Saludos!

10 comentarios:

  1. Excelente el aporte directo y al grano como debe ser!!!

    ResponderEliminar
  2. Hola! Me gustó tu codigo pero soy nuevo con la creación de proyectos y como poder ejecutarlo, me ayudas?

    ResponderEliminar
  3. Excelente aporte, solo tengo una duda, hay alguna forma de Deserializar la factura en una clase?

    ResponderEliminar
    Respuestas
    1. Si claro, te paso una playlist sobre como hacerlo https://www.youtube.com/playlist?list=PLWYKfSbdsjJiQwcGNZmICkes0iJHN_7XJ

      Eliminar
  4. Gracias, me sirvio mucho

    ResponderEliminar
  5. no te falta destruir la variable?

    ResponderEliminar
  6. Gracias por la ayuda, me ayudo mucho tu post.

    ResponderEliminar
  7. me ayudo el aporte, también sirve para la v 3.2?

    ResponderEliminar