Skip to content

Instantly share code, notes, and snippets.

@goedecke
Created November 24, 2016 15:40
Show Gist options
  • Save goedecke/03e9c7c178ff947b1e9d9eaea4bbe369 to your computer and use it in GitHub Desktop.
Save goedecke/03e9c7c178ff947b1e9d9eaea4bbe369 to your computer and use it in GitHub Desktop.
Extraer información de CFDI XML facil con simplexml
<?php
$xml = simplexml_load_file('test.xml');
$ns = $xml->getNamespaces(true);
$xml->registerXPathNamespace('c', $ns['cfdi']);
$xml->registerXPathNamespace('t', $ns['tfd']);
//EMPIEZO A LEER LA INFORMACION DEL CFDI E IMPRIMIRLA
foreach ($xml->xpath('//cfdi:Comprobante') as $cfdiComprobante){
echo $cfdiComprobante['version'];
echo "<br />";
echo $cfdiComprobante['fecha'];
echo "<br />";
echo $cfdiComprobante['sello'];
echo "<br />";
echo $cfdiComprobante['total'];
echo "<br />";
echo $cfdiComprobante['subTotal'];
echo "<br />";
echo $cfdiComprobante['certificado'];
echo "<br />";
echo $cfdiComprobante['formaDePago'];
echo "<br />";
echo $cfdiComprobante['noCertificado'];
echo "<br />";
echo $cfdiComprobante['tipoDeComprobante'];
echo "<br />";
}
foreach ($xml->xpath('//cfdi:Comprobante//cfdi:Emisor') as $Emisor){
echo $Emisor['rfc'];
echo "<br />";
echo $Emisor['nombre'];
echo "<br />";
}
foreach ($xml->xpath('//cfdi:Comprobante//cfdi:Emisor//cfdi:DomicilioFiscal') as $DomicilioFiscal){
echo $DomicilioFiscal['pais'];
echo "<br />";
echo $DomicilioFiscal['calle'];
echo "<br />";
echo $DomicilioFiscal['estado'];
echo "<br />";
echo $DomicilioFiscal['colonia'];
echo "<br />";
echo $DomicilioFiscal['municipio'];
echo "<br />";
echo $DomicilioFiscal['noExterior'];
echo "<br />";
echo $DomicilioFiscal['codigoPostal'];
echo "<br />";
}
foreach ($xml->xpath('//cfdi:Comprobante//cfdi:Emisor//cfdi:ExpedidoEn') as $ExpedidoEn){
echo $ExpedidoEn['pais'];
echo "<br />";
echo $ExpedidoEn['calle'];
echo "<br />";
echo $ExpedidoEn['estado'];
echo "<br />";
echo $ExpedidoEn['colonia'];
echo "<br />";
echo $ExpedidoEn['noExterior'];
echo "<br />";
echo $ExpedidoEn['codigoPostal'];
echo "<br />";
}
foreach ($xml->xpath('//cfdi:Comprobante//cfdi:Receptor') as $Receptor){
echo $Receptor['rfc'];
echo "<br />";
echo $Receptor['nombre'];
echo "<br />";
}
foreach ($xml->xpath('//cfdi:Comprobante//cfdi:Receptor//cfdi:Domicilio') as $ReceptorDomicilio){
echo $ReceptorDomicilio['pais'];
echo "<br />";
echo $ReceptorDomicilio['calle'];
echo "<br />";
echo $ReceptorDomicilio['estado'];
echo "<br />";
echo $ReceptorDomicilio['colonia'];
echo "<br />";
echo $ReceptorDomicilio['municipio'];
echo "<br />";
echo $ReceptorDomicilio['noExterior'];
echo "<br />";
echo $ReceptorDomicilio['noInterior'];
echo "<br />";
echo $ReceptorDomicilio['codigoPostal'];
echo "<br />";
}
foreach ($xml->xpath('//cfdi:Comprobante//cfdi:Conceptos//cfdi:Concepto') as $Concepto){
echo "<br />";
echo $Concepto['unidad'];
echo "<br />";
echo $Concepto['importe'];
echo "<br />";
echo $Concepto['cantidad'];
echo "<br />";
echo $Concepto['descripcion'];
echo "<br />";
echo $Concepto['valorUnitario'];
echo "<br />";
echo "<br />";
}
foreach ($xml->xpath('//cfdi:Comprobante//cfdi:Impuestos//cfdi:Traslados//cfdi:Traslado') as $Traslado){
echo $Traslado['tasa'];
echo "<br />";
echo $Traslado['importe'];
echo "<br />";
echo $Traslado['impuesto'];
echo "<br />";
echo "<br />";
}
//ESTA ULTIMA PARTE ES LA QUE GENERABA EL ERROR
foreach ($xml->xpath('//t:TimbreFiscalDigital') as $tfd) {
echo $tfd['selloCFD'];
echo "<br />";
echo $tfd['FechaTimbrado'];
echo "<br />";
echo $tfd['UUID'];
echo "<br />";
echo $tfd['noCertificadoSAT'];
echo "<br />";
echo $tfd['version'];
echo "<br />";
echo $tfd['selloSAT'];
}
?>
@andresaquino
Copy link

Se corrigió con un cast a array
Código anterior:
$attributes = array_merge(
$attributes,
current($XMLNode->attributes())
);
Código nuevo:
$attributes = array_merge(
$attributes,
(array)current($XMLNode->attributes())
);

Gracias nuevamente por la aportación..

Vale, haré el cambio.. la realidad es que no lo pasé por stan para hacer un análisis del código (amén de las pruebas unitarias/funcionales), gracias por la retro.

@draco3099
Copy link

para los que necesiten leer dentro de Complementos en facturas P

           // verifica que sea P y obtiene el monto
            if($tipocomprobante == 'P') {
              foreach ($xml->xpath('//cfdi:Comprobante//cfdi:Complemento//pago10:Pagos//pago10:Pago') as $Pago10){
                $montop = $Pago10['Monto'];
                //drupal_set_message('monto: '.$montop, 'status', FALSE);
                $node->field_factura_pago10_monto['und'][0]['value'] = $montop;
                }

              } 

EDIT: este codigo esta mas limpio

                    `                             // verifica que sea P y obtiene el monto
                           if($tipocomprobante == 'P') {
                             $xml->registerXPathNamespace('p', $ns['pago10']);

                            // set monto pago 10
                          foreach ($xml->xpath('//p:Pago') as $pago10) {
                            $montop = $pago10['Monto'];
                            $node->field_factura_pago10_monto['und'][0]['value'] = $montop;
                            }

                            // set id ducumentp rel
                            $documentosRel = $xml->xpath('//p:DoctoRelacionado');
                            foreach ($documentosRel as $key) {
                              $node->field_pago_10_doctorel_id_dcto['und'][0]['value'] = $key['IdDocumento'];
                            }

                          } // fin comprobante P`

para los que necesiten leer dentro de Complementos en facturas P

           // verifica que sea P y obtiene el monto
            if($tipocomprobante == 'P') {
              foreach ($xml->xpath('//cfdi:Comprobante//cfdi:Complemento//pago10:Pagos//pago10:Pago') as $Pago10){
                $montop = $Pago10['Monto'];
                //drupal_set_message('monto: '.$montop, 'status', FALSE);
                $node->field_factura_pago10_monto['und'][0]['value'] = $montop;
                }

              } 

EDIT: este codigo esta mas limpio

                    `                             // verifica que sea P y obtiene el monto
                           if($tipocomprobante == 'P') {
                             $xml->registerXPathNamespace('p', $ns['pago10']);

                            // set monto pago 10
                          foreach ($xml->xpath('//p:Pago') as $pago10) {
                            $montop = $pago10['Monto'];
                            $node->field_factura_pago10_monto['und'][0]['value'] = $montop;
                            }

                            // set id ducumentp rel
                            $documentosRel = $xml->xpath('//p:DoctoRelacionado');
                            foreach ($documentosRel as $key) {
                              $node->field_pago_10_doctorel_id_dcto['und'][0]['value'] = $key['IdDocumento'];
                            }

                          } // fin comprobante P`

Hola. Estoy recibiendo varios complementos que tienen dos o más pagos y cada pago a su vez tiene sus Documentos relacionados. ¿Cómo puedo leer el complemento de manera que pueda ver qué Documentos relacionados están amparados con cada Pago o monto? Por ejemplo:

cfdi:Complemento
<pago10:Pagos Version="1.0">
<pago10:Pago FechaPago="2019-06-21T12:07:57" FormaDePagoP="03" MonedaP="MXN" Monto="150000.00 ">
<pago10:DoctoRelacionado IdDocumento="UUID1" Serie="PC" Folio="230156" MonedaDR="MXN" MetodoDePagoDR="PPD" NumParcialidad="1 " ImpSaldoAnt="75000.00 " ImpPagado="75000.00 " ImpSaldoInsoluto="0.00 "/>
<pago10:DoctoRelacionado IdDocumento="UUID2" Serie="PC" Folio="230160" MonedaDR="MXN" MetodoDePagoDR="PPD" NumParcialidad="1 " ImpSaldoAnt="75000.00 " ImpPagado="750000.00 " ImpSaldoInsoluto="0.00 "/>
</pago10:Pago>
<pago10:Pago FechaPago="2019-06-21T14:35:25" FormaDePagoP="03" MonedaP="MXN" Monto="100000.00 ">
<pago10:DoctoRelacionado IdDocumento="UUID3" Serie="PC" Folio="230181" MonedaDR="MXN" MetodoDePagoDR="PPD" NumParcialidad="1 " ImpSaldoAnt="20000.00 " ImpPagado="20000.00 " ImpSaldoInsoluto="0.00 "/>
<pago10:DoctoRelacionado IdDocumento="UUID4" Serie="PC" Folio="230236" MonedaDR="MXN" MetodoDePagoDR="PPD" NumParcialidad="1 " ImpSaldoAnt="30000.00 " ImpPagado="30000.00 " ImpSaldoInsoluto="0.00 "/>
<pago10:DoctoRelacionado IdDocumento="UUID5" Serie="PC" Folio="230238" MonedaDR="MXN" MetodoDePagoDR="PPD" NumParcialidad="1 " ImpSaldoAnt="50000.00 " ImpPagado="50000.00 " ImpSaldoInsoluto="0.00 "/>
</pago10:Pago>
</pago10:Pagos>

De esto quisiera obtener algo como
Pago 1 - Monto 150000 - UUID1 - UUID2
Pago 2 - Monto 100000 - UUID3 - UUID4 - UUID5

¿Es posible hacerlo con ese orden?
Porque lo que consigo es
Pago 1 - Monto
Pago 2- Monto

UUID1
UUID2
UUID3
UUID4
UUID5

@omarlv86
Copy link

Buenas tardes, estaba accediendo a las facturas pero hoy me genero este error y no encuentro el porque surge, si alguien pudiera dar un poco de ayuda lo agradeceria.

This page contains the following errors:
error on line 28 at column 182: xmlns:schemaLocation: 'http://www.sat.gob.mx/registrofiscal http://www.sat.gob.mx/sitio_internet/cfd/cfdiregistrofiscal/cfdiregistrofiscal.xsd' is not a valid URI
Below is a rendering of the page up to the first error.

@andresaquino
Copy link

Buenas tardes, estaba accediendo a las facturas pero hoy me genero este error y no encuentro el porque surge, si alguien pudiera dar un poco de ayuda lo agradeceria.

This page contains the following errors:
error on line 28 at column 182: xmlns:schemaLocation: 'http://www.sat.gob.mx/registrofiscal http://www.sat.gob.mx/sitio_internet/cfd/cfdiregistrofiscal/cfdiregistrofiscal.xsd' is not a valid URI
Below is a rendering of the page up to the first error.

¿tienes más información al respecto?
¿dónde se presenta el error, factura de ejemplo...?

@andresaquino
Copy link

para los que necesiten leer dentro de Complementos en facturas P

           // verifica que sea P y obtiene el monto
            if($tipocomprobante == 'P') {
              foreach ($xml->xpath('//cfdi:Comprobante//cfdi:Complemento//pago10:Pagos//pago10:Pago') as $Pago10){
                $montop = $Pago10['Monto'];
                //drupal_set_message('monto: '.$montop, 'status', FALSE);
                $node->field_factura_pago10_monto['und'][0]['value'] = $montop;
                }

              } 

EDIT: este codigo esta mas limpio

                    `                             // verifica que sea P y obtiene el monto
                           if($tipocomprobante == 'P') {
                             $xml->registerXPathNamespace('p', $ns['pago10']);

                            // set monto pago 10
                          foreach ($xml->xpath('//p:Pago') as $pago10) {
                            $montop = $pago10['Monto'];
                            $node->field_factura_pago10_monto['und'][0]['value'] = $montop;
                            }

                            // set id ducumentp rel
                            $documentosRel = $xml->xpath('//p:DoctoRelacionado');
                            foreach ($documentosRel as $key) {
                              $node->field_pago_10_doctorel_id_dcto['und'][0]['value'] = $key['IdDocumento'];
                            }

                          } // fin comprobante P`

para los que necesiten leer dentro de Complementos en facturas P

           // verifica que sea P y obtiene el monto
            if($tipocomprobante == 'P') {
              foreach ($xml->xpath('//cfdi:Comprobante//cfdi:Complemento//pago10:Pagos//pago10:Pago') as $Pago10){
                $montop = $Pago10['Monto'];
                //drupal_set_message('monto: '.$montop, 'status', FALSE);
                $node->field_factura_pago10_monto['und'][0]['value'] = $montop;
                }

              } 

EDIT: este codigo esta mas limpio

                    `                             // verifica que sea P y obtiene el monto
                           if($tipocomprobante == 'P') {
                             $xml->registerXPathNamespace('p', $ns['pago10']);

                            // set monto pago 10
                          foreach ($xml->xpath('//p:Pago') as $pago10) {
                            $montop = $pago10['Monto'];
                            $node->field_factura_pago10_monto['und'][0]['value'] = $montop;
                            }

                            // set id ducumentp rel
                            $documentosRel = $xml->xpath('//p:DoctoRelacionado');
                            foreach ($documentosRel as $key) {
                              $node->field_pago_10_doctorel_id_dcto['und'][0]['value'] = $key['IdDocumento'];
                            }

                          } // fin comprobante P`

Hola. Estoy recibiendo varios complementos que tienen dos o más pagos y cada pago a su vez tiene sus Documentos relacionados. ¿Cómo puedo leer el complemento de manera que pueda ver qué Documentos relacionados están amparados con cada Pago o monto? Por ejemplo:

cfdi:Complemento <pago10:Pagos Version="1.0"> <pago10:Pago FechaPago="2019-06-21T12:07:57" FormaDePagoP="03" MonedaP="MXN" Monto="150000.00 "> <pago10:DoctoRelacionado IdDocumento="UUID1" Serie="PC" Folio="230156" MonedaDR="MXN" MetodoDePagoDR="PPD" NumParcialidad="1 " ImpSaldoAnt="75000.00 " ImpPagado="75000.00 " ImpSaldoInsoluto="0.00 "/> <pago10:DoctoRelacionado IdDocumento="UUID2" Serie="PC" Folio="230160" MonedaDR="MXN" MetodoDePagoDR="PPD" NumParcialidad="1 " ImpSaldoAnt="75000.00 " ImpPagado="750000.00 " ImpSaldoInsoluto="0.00 "/> </pago10:Pago> <pago10:Pago FechaPago="2019-06-21T14:35:25" FormaDePagoP="03" MonedaP="MXN" Monto="100000.00 "> <pago10:DoctoRelacionado IdDocumento="UUID3" Serie="PC" Folio="230181" MonedaDR="MXN" MetodoDePagoDR="PPD" NumParcialidad="1 " ImpSaldoAnt="20000.00 " ImpPagado="20000.00 " ImpSaldoInsoluto="0.00 "/> <pago10:DoctoRelacionado IdDocumento="UUID4" Serie="PC" Folio="230236" MonedaDR="MXN" MetodoDePagoDR="PPD" NumParcialidad="1 " ImpSaldoAnt="30000.00 " ImpPagado="30000.00 " ImpSaldoInsoluto="0.00 "/> <pago10:DoctoRelacionado IdDocumento="UUID5" Serie="PC" Folio="230238" MonedaDR="MXN" MetodoDePagoDR="PPD" NumParcialidad="1 " ImpSaldoAnt="50000.00 " ImpPagado="50000.00 " ImpSaldoInsoluto="0.00 "/> </pago10:Pago> </pago10:Pagos>

De esto quisiera obtener algo como
Pago 1 - Monto 150000 - UUID1 - UUID2
Pago 2 - Monto 100000 - UUID3 - UUID4 - UUID5

¿Es posible hacerlo con ese orden?
Porque lo que consigo es
Pago 1 - Monto
Pago 2- Monto

UUID1
UUID2
UUID3
UUID4
UUID5

Quizás algo así?

foreach ($xml->xpath('//p:Pago') as $pago10) {
    $montop = $pago10['Monto'];
    $node->field_factura_pago10_monto['und'][0]['value'] = $montop;

    // set id ducumentp rel
    $documentosRel = $xml->xpath('//p:DoctoRelacionado');
    foreach ($documentosRel as $key) {
        $node->field_pago_10_doctorel_id_dcto['und'][0]['value'] = $key['IdDocumento'];
    }
}

@goedecke
Copy link
Author

Buenas tardes, estaba accediendo a las facturas pero hoy me genero este error y no encuentro el porque surge, si alguien pudiera dar un poco de ayuda lo agradeceria.

This page contains the following errors:
error on line 28 at column 182: xmlns:schemaLocation: 'http://www.sat.gob.mx/registrofiscal http://www.sat.gob.mx/sitio_internet/cfd/cfdiregistrofiscal/cfdiregistrofiscal.xsd' is not a valid URI
Below is a rendering of the page up to the first error.

Hola viejo tu error es muy simple, tienes dos url en el codigo
'http://www.sat.gob.mx/registrofiscal
y
http://www.sat.gob.mx/sitio_internet/cfd/cfdiregistrofiscal/cfdiregistrofiscal.xsd

Elimina http://www.sat.gob.mx/registrofiscal y con eso debe de funcionar

@omarlv86
Copy link

Buenas tardes, estaba accediendo a las facturas pero hoy me genero este error y no encuentro el porque surge, si alguien pudiera dar un poco de ayuda lo agradeceria.
This page contains the following errors:
error on line 28 at column 182: xmlns:schemaLocation: 'http://www.sat.gob.mx/registrofiscal http://www.sat.gob.mx/sitio_internet/cfd/cfdiregistrofiscal/cfdiregistrofiscal.xsd' is not a valid URI
Below is a rendering of the page up to the first error.

Hola viejo tu error es muy simple, tienes dos url en el codigo
'http://www.sat.gob.mx/registrofiscal
y
http://www.sat.gob.mx/sitio_internet/cfd/cfdiregistrofiscal/cfdiregistrofiscal.xsd

Elimina http://www.sat.gob.mx/registrofiscal y con eso debe de funcionar

Hola hermano, acabo de realizar tu procedimiento y efectivamente eliminando esa linea se puede visualizar la factura, muchas gracias, sabes si hay alguna manera de leer la factura y poder eliminar esa url de manera programada? de ante mano muchas gracias

@chuyoman3000
Copy link

Buenas, tengo un problemita a la hora de tratar de agregar otro xpath un ejemplo seria este $xml->registerXPathNamespace('n', $ns['nomina12']);
No me detecta lo que vendria siendo la key de nomina12 apesar de que este aparezca en los xml, estoy empezando en esto y se me hace algo confuso, un saludo y muchas gracias

@rinconlb
Copy link

rinconlb commented Dec 2, 2021

Es posible leer varios archivos desde un input ? eso ya lo hice solamente con un archivo , necesito extraer información de cada uno de ellos para poder hacer un varios análisis de los ingresos y egresos supongo que es con un foreach o sera mejor subir los archivos a una carpeta y leerlos todos ?

@Genebi
Copy link

Genebi commented Jun 4, 2022

Me fue útil para solucionar un problema en especifico con un nodo en la versión 4.0, muchas gracias.

@andresaquino
Copy link

Me fue útil para solucionar un problema en especifico con un nodo en la versión 4.0, muchas gracias.

ejemplo..., cómo fue tu escenario?

@9014k
Copy link

9014k commented Aug 26, 2022

foreach ($xml->xpath('//cfdi:Comprobante//cfdi:Impuestos//cfdi:Traslados//cfdi:Traslado') as $traslados) {
$t.= (string)$traslados['TipoFactor'] .'-' .(string)$traslados['TasaOCuota'].(string)$traslados['Importe'].'
';
}
Estoy tratando de leer los traslados dentro de impuestos pero tambien me trae los traslados de los conceptos a pesar de que especifico el xpath...

@RichyCapy
Copy link

Buenas! alguna actualizacion para que acepte la version 4 o mayor?

@pedrazacarlos007
Copy link

Esto me funciono para extraer el UUID del xml con la version 4.0

$uuid = (string) $xml->xpath('//tfd:TimbreFiscalDigital/@uuid')[0];

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment