Uso de XSL para transformar la factura electronica XML

Contenido/contents:
Introducion
Cadena Original
Verificacion de sello
Impresion
Informe
Pagina anterior/Previous page

Introduccion
Cadena Original
Esta es mi primera prueba con XSLT por lo cual este archivo de transformacion esta muy extenso. Estoy seguro de que se pudiera siplificar no repitiendo lo mismo para cada atributo pero mientras no descubra la manera asi lo dejo.
5/Jun/2006 Esta ya es mi segunda version, gracias a David Ongay por detectar varios errores, esta version ya no requiera que exista Addenda para generar la cadena correcta, y ademas correji unos pequeñ errores de dedo.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
<xsl:stylesheet version = '1.0'
     xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
 
<xsl:output method = "text" /> 
 
<xsl:template match="/">|<xsl:apply-templates select="//Comprobante"/>||</xsl:template>
 
<xsl:template match="Comprobante">
      <xsl:if test="@version">|<xsl:value-of select="@version"/></xsl:if>
      <xsl:if test="@serie">|<xsl:value-of select="@serie"/></xsl:if>
      <xsl:if test="@folio">|<xsl:value-of select="@folio"/></xsl:if>
      <xsl:if test="@fecha">|<xsl:value-of select="@fecha"/></xsl:if>
      <xsl:if test="@noAprobacion">|<xsl:value-of select="@noAprobacion"/></xsl:if>
      <xsl:if test="@anoAprobacion">|<xsl:value-of select="@anoAprobacion"/></xsl:if>
      <xsl:if test="@tipoDeComprobante">|<xsl:value-of select="@tipoDeComprobante"/></xsl:if>
      <xsl:if test="@formaDePago">|<xsl:value-of select="@formaDePago"/></xsl:if>
      <xsl:if test="@condicionesDePago">|<xsl:value-of select="@condicionesDePago"/></xsl:if>
      <xsl:if test="@subTotal">|<xsl:value-of select="@subTotal"/></xsl:if>
      <xsl:if test="@descuento">|<xsl:value-of select="@descuento"/></xsl:if>
      <xsl:if test="@total">|<xsl:value-of select="@total"/></xsl:if>
      <xsl:apply-templates select="//Emisor"/>
      <xsl:apply-templates select="//DomicilioFiscal"/>
      <xsl:apply-templates select="//ExpedidoEn"/>
      <xsl:apply-templates select="//Receptor"/>
      <xsl:apply-templates select="//Domicilio"/>
      <xsl:apply-templates select="//Concepto"/>
      <xsl:apply-templates select="//Impuestos"/>
</xsl:template>
 
<xsl:template match="Emisor">
      <xsl:if test="@rfc">|<xsl:value-of select="@rfc"/></xsl:if>
      <xsl:if test="@nombre">|<xsl:value-of select="@nombre"/></xsl:if>
</xsl:template>
 
<xsl:template match="DomicilioFiscal">
      <xsl:if test="@calle">|<xsl:value-of select="@calle"/></xsl:if>
      <xsl:if test="@noExterior">|<xsl:value-of select="@noExterior"/></xsl:if>
      <xsl:if test="@noInterior">|<xsl:value-of select="@noInterior"/></xsl:if>
      <xsl:if test="@colonia">|<xsl:value-of select="@colonia"/></xsl:if>
      <xsl:if test="@localidad">|<xsl:value-of select="@localidad"/></xsl:if>
      <xsl:if test="@referencia">|<xsl:value-of select="@referencia"/></xsl:if>
      <xsl:if test="@municipio">|<xsl:value-of select="@municipio"/></xsl:if>
      <xsl:if test="@estado">|<xsl:value-of select="@estado"/></xsl:if>
      <xsl:if test="@pais">|<xsl:value-of select="@pais"/></xsl:if>
      <xsl:if test="@codigoPostal">|<xsl:value-of select="@codigoPostal"/></xsl:if>
</xsl:template>
 
<xsl:template match="ExpedidoEn">
      <xsl:if test="@calle">|<xsl:value-of select="@calle"/></xsl:if>
      <xsl:if test="@noExterior">|<xsl:value-of select="@noExterior"/></xsl:if>
      <xsl:if test="@noInterior">|<xsl:value-of select="@noInterior"/></xsl:if>
      <xsl:if test="@colonia">|<xsl:value-of select="@colonia"/></xsl:if>
      <xsl:if test="@localidad">|<xsl:value-of select="@localidad"/></xsl:if>
      <xsl:if test="@refrencia">|<xsl:value-of select="@referencia"/></xsl:if>
      <xsl:if test="@municipio">|<xsl:value-of select="@municipio"/></xsl:if>
      <xsl:if test="@estado">|<xsl:value-of select="@estado"/></xsl:if>
      <xsl:if test="@pais">|<xsl:value-of select="@pais"/></xsl:if>
      <xsl:if test="@codigoPostal">|<xsl:value-of select="@codigoPostal"/></xsl:if>
</xsl:template>
 
<xsl:template match="Receptor">
      <xsl:if test="@rfc">|<xsl:value-of select="@rfc"/></xsl:if>
      <xsl:if test="@nombre">|<xsl:value-of select="@nombre"/></xsl:if>
</xsl:template>
 
<xsl:template match="Domicilio">
      <xsl:if test="@calle">|<xsl:value-of select="@calle"/></xsl:if>
      <xsl:if test="@noExterior">|<xsl:value-of select="@noExterior"/></xsl:if>
      <xsl:if test="@noInterior">|<xsl:value-of select="@noInterior"/></xsl:if>
      <xsl:if test="@colonia">|<xsl:value-of select="@colonia"/></xsl:if>
      <xsl:if test="@localidad">|<xsl:value-of select="@localidad"/></xsl:if>
      <xsl:if test="@refrencia">|<xsl:value-of select="@referencia"/></xsl:if>
      <xsl:if test="@municipio">|<xsl:value-of select="@municipio"/></xsl:if>
      <xsl:if test="@estado">|<xsl:value-of select="@estado"/></xsl:if>
      <xsl:if test="@pais">|<xsl:value-of select="@pais"/></xsl:if>
      <xsl:if test="@codigoPostal">|<xsl:value-of select="@codigoPostal"/></xsl:if>
</xsl:template>
 
<xsl:template match="Concepto">
      <xsl:if test="@cantidad">|<xsl:value-of select="@cantidad"/></xsl:if>
      <xsl:if test="@unidad">|<xsl:value-of select="@unidad"/></xsl:if>
      <xsl:if test="@noIdentificacion">|<xsl:value-of select="@noIdentificacion"/></xsl:if>
      <xsl:if test="@descripcion">|<xsl:value-of select="@descripcion"/></xsl:if>
      <xsl:if test="@valorUnitario">|<xsl:value-of select="@valorUnitario"/></xsl:if>
      <xsl:if test="@importe">|<xsl:value-of select="@importe"/></xsl:if>
      <xsl:apply-templates select="InformacionAduanera"/>
</xsl:template>
 
<xsl:template match="Impuestos">
      <xsl:apply-templates select="//Retencion"/>
      <xsl:if test="@totalImpuestosRetenidos">|<xsl:value-of select="@totalImpuestosRetenidos"/></xsl:if>
      <xsl:apply-templates select="//Traslado"/>
      <xsl:if test="@totalImpuestosTrasladados">|<xsl:value-of select="@totalImpuestosTrasladados"/></xsl:if>
  </xsl:template>
 
<xsl:template match="InformacionAduanera">
      <xsl:if test="@numero">|<xsl:value-of select="@numero"/></xsl:if>
      <xsl:if test="@fecha">|<xsl:value-of select="@fecha"/></xsl:if>
      <xsl:if test="@aduana">|<xsl:value-of select="@aduana"/></xsl:if>
</xsl:template>
 
<xsl:template match="Retencion">
      <xsl:if test="@impuesto">|<xsl:value-of select="@impuesto"/></xsl:if>
      <xsl:if test="@importe">|<xsl:value-of select="@importe"/></xsl:if>
</xsl:template>
 
<xsl:template match="Traslado">
      <xsl:if test="@impuesto">|<xsl:value-of select="@impuesto"/></xsl:if>
      <xsl:if test="@tasa">|<xsl:value-of select="@tasa"/></xsl:if>
      <xsl:if test="@importe">|<xsl:value-of select="@importe"/></xsl:if>
</xsl:template>
 
</xsl:stylesheet>
Vamor a aplicar las reglas de transformacion anteriores al siguiente archivo XML.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
<?xml version="1.0"
    encoding="UTF-8"?>
 
<Comprobante xmlns="http://www.sat.gob.mx/cfd/2"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.sat.gob.mx/cfd/2  http://www.sat.gob.mx/sitio_internet/cfd/2/cfdv2.xsd"
    version="2.0"
    serie="FAXA"
    folio="051661"
    fecha="2006-11-20T08:50:48"
    sello="33HZqWoHi7u4gWkcnipTEiCz7UFOPGQ1NYqHmOyTGxpiJE8dyEBew8QS4f99zYz8QqXFvP0IEkWVCaKPBKm/6tClIdK/jJFZGxlcP/QCKfnBnMF/ktzukLLxHhwfK+StNpEkx90riDTITVv+wcmRy+kGrxlTB7N6gr1sK+tHBBI="
    noAprobacion="2951"
    anoAprobacion="2006"
    tipoDeComprobante="ingreso"
    formaDePago="EL PAGO DE ESTA FACTURA (CONTRAPRESTACION) SE EFECTUARA EN UNA SOLA EXHIBICION, SI POR ALGUNA RAZON NO FUERA ASI, EMITIREMOS LOS COMPROBANTES DE LAS PARCIALIDADES RESPECTIVAS"
    noCertificado="00001000000000823747"
    subTotal="43824.69"
    total="50398.39">
<Emisor rfc="FJC780315E91"
    nombre="FABRICA DE JABON, LA CORONA, S.A. DE C.V.">
<DomicilioFiscal calle="CARLOS B. ZETINA"
    noExterior="80"
    colonia="INDUSTRIAL XALOSTOC"
    municipio="ECATEPEC"
    estado="MEXICO"
    pais="MEXICO"
    codigoPostal="55348"/>
<ExpedidoEn calle="CARLOS B.ZETINA NO.80"
    municipio="XALOSTOC, EDO. DE MEXICO"
    estado="EDO. DE MEXICO"
    pais="MEXICO"
    codigoPostal="55348"/>
</Emisor>
<Receptor rfc="NWM9709244W4"
    nombre="NUEVA WAL-MART DE MEXICO SRL DE CV">
<Domicilio calle="KM.40.5 CARRT. MEXICO-QUERETARO"
    colonia="."
    municipio="CUAUTITLAN IZCALLI       MEX."
    estado="MEXICO"
    pais="MEXICO"/>
</Receptor>
<Conceptos>
<Concepto cantidad="22"
    descripcion="TEPEYAC 25P 400 G C/ENV"
    valorUnitario="110.97"
    importe="2441.34"/>
<Concepto cantidad="11"
    descripcion="ZOTE AZUL 25P 400 G."
    valorUnitario="110.97"
    importe="1220.67"/>
<Concepto cantidad="22"
    descripcion="ZOTE BCO. 25P 400 G"
    valorUnitario="110.97"
    importe="2441.34"/>
<Concepto cantidad="7"
    descripcion="ZOTE BCO. 50P 200 G"
    valorUnitario="110.97"
    importe="776.79"/>
<Concepto cantidad="44"
    descripcion="ZOTE ROSA 25P 400 G"
    valorUnitario="110.97"
    importe="4882.68"/>
<Concepto cantidad="6"
    descripcion="ZOTE ROSA 50P 200 G"
    valorUnitario="110.97"
    importe="665.82"/>
<Concepto cantidad="12"
    descripcion="ROMA 4P 5 KGS"
    valorUnitario="218.34"
    importe="2620.08"/>
<Concepto cantidad="24"
    descripcion="ROMA 10P 2 KGS"
    valorUnitario="219.74"
    importe="5273.64"/>
<Concepto cantidad="120"
    descripcion="ROMA 10P 1 KG"
    valorUnitario="111.29"
    importe="13354.2"/>
<Concepto cantidad="12"
    descripcion="FOCA 10P 2 KGS"
    valorUnitario="233.87"
    importe="2806.38"/>
<Concepto cantidad="10"
    descripcion="BLANCA NIEVES 10P 2 KGS"
    valorUnitario="201.47"
    importe="2014.65"/>
<Concepto cantidad="40"
    descripcion="BLANCA NIEVES 10P 1 KG"
    valorUnitario="102.15"
    importe="4086.0"/>
<Concepto cantidad="5"
    descripcion="BRILOZA 10P 1 KG"
    valorUnitario="102.15"
    importe="510.75"/>
<Concepto cantidad="6"
    descripcion="FOCA 12B 1LT"
    valorUnitario="121.73"
    importe="730.35"/>
</Conceptos>
<Impuestos>
<Traslados>
<Traslado impuesto="IVA"
    tasa="15.0"
    importe="6573.7"/>
</Traslados>
</Impuestos>
<Addenda>
<edi>
UNA:+.?'UNB+UNOB:1+JABON-CORONA:ZZ+925485MX00:8+061211:1150+2372'UNG+INVOIC+JABON-CORONA:ZZ+925485MX00:8+061211:1150+2372+UN+D:01B:AMC002'UNH+2372+INVOIC:D:01B:UN:AMC002'BGM+380+051661+9'DTM+137:20061120085048:204'FTX+ZZZ+++(CINCUENTA MIL TRESCIENTOS NOVENTA Y OCHO PESOS 39/100 M.N.)'RFF+ON:1800131675'DTM+171:20061119:102'RFF+BT:FAXA'RFF+ATZ:12345678'NAD+BY+7507003100001::9++NUEVA WAL MART DE MEXICO S DE RL DE:CV+NEXTENGO NO 78:SANTA CRUZ ACAYUCAN+AZCAPOTZALCO+DF+02770'RFF+GN:NWM9709244W4'NAD+SU+7504000065005::9++FABRICA DE JABON LA CORONA,SA DE CV+CARLOS B ZETINA NO 80+FRACC IND XALOSTOC+MC+55348'RFF+GN:FJC780315E91'RFF+IA:172042130'NAD+II+7504000065005::9++FABRICA DE JABON LA CORONA,SA DE CV+CARLOS B.ZETINA NO.80:COL INDUSTRIAL XALOSTOC+XALOSTOC, EDO. DE MEXICO+MC+55348'NAD+ST+7507003176426::9++AURRERA NO.379:NUEVA WAL-MART DE MEXICO SRL DE CV+KM.40.5 CARRT. MEXICO-QUERETARO:.+CUAUTITLAN IZCALLI+MC+54830'CUX+2:MXN:4++1'PAT+1++5:3:D:30'PCD+12:0'LIN+1++7501026006340 :SRV::9'PIA+1+121:SA'IMD+F++:::TEPEYAC 25P 400 G C/ENV'QTY+47:22:CA'QTY+59:25:EA'MOA+203:2441.34'PRI+AAA:110.97::::CA'TAX+7+VAT+++:::15.0'MOA+124:366.2'LIN+2++7501026005404 :SRV::9'PIA+1+523:SA'IMD+F++:::ZOTE AZUL 25P 400 G.'QTY+47:11:CA'QTY+59:25:EA'MOA+203:1220.67'PRI+AAA:110.97::::CA'TAX+7+VAT+++:::15.0'MOA+124:183.1'LIN+3++7501026005374 :SRV::9'PIA+1+530:SA'IMD+F++:::ZOTE BCO. 25P 400 G'QTY+47:22:CA'QTY+59:25:EA'MOA+203:2441.34'PRI+AAA:110.97::::CA'TAX+7+VAT+++:::15.0'MOA+124:366.2'LIN+4++7501026005381 :SRV::9'PIA+1+539:SA'IMD+F++:::ZOTE BCO. 50P 200 G'QTY+47:7:CA'QTY+59:50:EA'MOA+203:776.79'PRI+AAA:110.97::::CA'TAX+7+VAT+++:::15.0'MOA+124:116.52'LIN+5++7501026005671 :SRV::9'PIA+1+560:SA'IMD+F++:::ZOTE ROSA 25P 400 G'QTY+47:44:CA'QTY+59:25:EA'MOA+203:4882.68'PRI+AAA:110.97::::CA'TAX+7+VAT+++:::15.0'MOA+124:732.4'LIN+6++7501026005688 :SRV::9'PIA+1+573:SA'IMD+F++:::ZOTE ROSA 50P 200 G'QTY+47:6:CA'QTY+59:50:EA'MOA+203:665.82'PRI+AAA:110.97::::CA'TAX+7+VAT+++:::15.0'MOA+124:99.87'LIN+7++7501026004483 :SRV::9'PIA+1+40444:SA'IMD+F++:::ROMA 4P 5 KGS'QTY+47:12:CA'QTY+59:4:EA'MOA+203:2620.08'PRI+AAA:218.34::::CA'TAX+7+VAT+++:::15.0'MOA+124:393.01'LIN+8++7501026004537 :SRV::9'PIA+1+40445:SA'IMD+F++:::ROMA 10P 2 KGS'QTY+47:24:CA'QTY+59:10:EA'MOA+203:5273.64'PRI+AAA:219.735::::CA'TAX+7+VAT+++:::15.0'MOA+124:791.05'LIN+9++7501026004605 :SRV::9'PIA+1+40446:SA'IMD+F++:::ROMA 10P 1 KG'QTY+47:120:CA'QTY+59:10:EA'MOA+203:13354.2'PRI+AAA:111.285::::CA'TAX+7+VAT+++:::15.0'MOA+124:2003.13'LIN+10++7501026026539 :SRV::9'PIA+1+42671:SA'IMD+F++:::FOCA 10P 2 KGS'QTY+47:12:CA'QTY+59:10:EA'MOA+203:2806.38'PRI+AAA:233.865::::CA'TAX+7+VAT+++:::15.0'MOA+124:420.96'LIN+11++7501026027529 :SRV::9'PIA+1+42744:SA'IMD+F++:::BLANCA NIEVES 10P 2 KGS'QTY+47:10:CA'QTY+59:10:EA'MOA+203:2014.65'PRI+AAA:201.465::::CA'TAX+7+VAT+++:::15.0'MOA+124:302.2'LIN+12++7501026027536 :SRV::9'PIA+1+42765:SA'IMD+F++:::BLANCA NIEVES 10P 1 KG'QTY+47:40:CA'QTY+59:10:EA'MOA+203:4086.0'PRI+AAA:102.15::::CA'TAX+7+VAT+++:::15.0'MOA+124:612.9'LIN+13++7501026027727 :SRV::9'PIA+1+43064:SA'IMD+F++:::BRILOZA 10P 1 KG'QTY+47:5:CA'QTY+59:10:EA'MOA+203:510.75'PRI+AAA:102.15::::CA'TAX+7+VAT+++:::15.0'MOA+124:76.61'LIN+14++7501026028007 :SRV::9'PIA+1+52624:SA'IMD+F++:::FOCA 12B 1LT'QTY+47:6:CA'QTY+59:12:EA'MOA+203:730.35'PRI+AAA:121.725::::CA'TAX+7+VAT+++:::15.0'MOA+124:109.55'UNS+S'CNT+11:341'CNT+2:14'MOA+9:50398.39'MOA+79:43824.69'MOA+125:43824.69'TAX+7+VAT+++:::15.0'MOA+124:6573.7'UNT+153+2372'UNE+4+2372'UNZ+1+2372'</edi>
</Addenda>
</Comprobante>
Para aplicar las reglas usamos el comando xsltproc dando como primer argumento el archivo con las reglas de transofrmacion XSL y como segundo el nombre del archivo con la factura XML.
[web@web sat]$ xsltproc cadena_original.xsl fact.xml
||2.0|FAXA|051661|2006-11-20T08:50:48|2951|2006|ingreso|EL PAGO DE ESTA FACTURA (CONTRAPRESTACION) SE EFECTUARA EN UNA SOLA EXHIBICION, SI POR ALGUNA RAZON NO FUERA ASI, EMITIREMOS LOS COMPROBANTES DE LAS PARCIALIDADES RESPECTIVAS|43824.69|50398.39|FJC780315E91|FABRICA DE JABON, LA CORONA, S.A. DE C.V.|CARLOS B. ZETINA|80|INDUSTRIAL XALOSTOC|ECATEPEC|MEXICO|MEXICO|55348|CARLOS B.ZETINA NO.80|XALOSTOC, EDO. DE MEXICO|EDO. DE MEXICO|MEXICO|55348|NWM9709244W4|NUEVA WAL-MART DE MEXICO SRL DE CV|KM.40.5 CARRT. MEXICO-QUERETARO|.|CUAUTITLAN IZCALLI       MEX.|MEXICO|MEXICO|22|TEPEYAC 25P 400 G C/ENV|110.97|2441.34|11|ZOTE AZUL 25P 400 G.|110.97|1220.67|22|ZOTE BCO. 25P 400 G|110.97|2441.34|7|ZOTE BCO. 50P 200 G|110.97|776.79|44|ZOTE ROSA 25P 400 G|110.97|4882.68|6|ZOTE ROSA 50P 200 G|110.97|665.82|12|ROMA 4P 5 KGS|218.34|2620.08|24|ROMA 10P 2 KGS|219.74|5273.64|120|ROMA 10P 1 KG|111.29|13354.2|12|FOCA 10P 2 KGS|233.87|2806.38|10|BLANCA NIEVES 10P 2 KGS|201.47|2014.65|40|BLANCA NIEVES 10P 1 KG|102.15|4086.0|5|BRILOZA 10P 1 KG|102.15|510.75|6|FOCA 12B 1LT|121.73|730.35|IVA|15.0|6573.7||
Ya con esa cadena original podemos aplicar las reglas para calcular el sello. El primer paso es calcular el hash md5.
[web@web sat]$ xsltproc cadena_original.xsl fact.xml | md5sum | cut -f1 -d \ 
6b927330e1d0b977c0846910f0559e07
Este hash ya se puede sellar con el certificado (que ya tengo convertido en formato PEM) y ademas codificarlo en formato base64 porque el sello lo deja en binario.
Openssl tiene la facilidad de calcular el md5 y de sellarlo en un mismo paso, por lo cual ya no hace falta calcular el md5 en un paso previo.
[web@web sat]$ xsltproc cadena_original.xsl fact.xml | openssl dgst -md5 -sign AAA010101AAA.key.pem | openssl enc -base64 -A
33HZqWoHi7u4gWkcnipTEiCz7UFOPGQ1NYqHmOyTGxpiJE8dyEBew8QS4f99zYz8QqXFvP0IEkWVCaKPBKm/6tClIdK/jJFZGxlcP/QCKfnBnMF/ktzukLLxHhwfK+StNpEkx90riDTITVv+wcmRy+kGrxlTB7N6gr1sK+tHBBI=
Si son observadores veran que el sello recien calculado es el mismo que esta almacenado en el atributo "sello" del XML.
Verificacion del sello
Ahora voy a simular lo que hay que hacer para validar que el sello es correcto, es decir, es el sello correspondiente a la factura firmada por el certificado correspondiente.
Este es una pequen˜a hoja de conversion para extraer el campo del sello.
1
2
3
4
5
6
7
8
9
10
<xsl:stylesheet version = '1.0'
     xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
 
<xsl:output method = "text" /> 
 
<xsl:template match="Comprobante">
      <xsl:value-of select="@sello"/>
</xsl:template>
 
</xsl:stylesheet>
Para aplicar las reglas usamos el comando xsltproc dando como primer argumento el archivo con las reglas de transofrmacion XSL y como segundo el nombre del archivo con la factura XML.
[web@web sat]$ xsltproc sello.xsl fact.xml
Rp6QIcD0fJIpLRCUqatx7RM7haGH8kdyiW7cwb7h7R0234uK55M5u8S1tjYYYc7PnL6QjDvyRnTB8DFcvKcHIHO9VQIfinv4rM2S8krh0uK4FjemYNcmjvfYdzcqduj9v1YBj6FvNMatwOg/6ns9j+9WscQ/L5Q1yyB4Bd0p240=
Ahora este campo del sello obtenido del archivo XML lo de-codificamos del codigo base64 y lo dejamos nuevamente como el sello en binario y lo dejamos en un archivo temporal.
[web@web sat]$ xsltproc /home/httpd/sat/sello.xsl fact.xml | openssl enc -base64 -d -A -out sello
Ahora volvemos a 'firmar' pero con la llave publica y verificamos que el sello obtenido coincida con el enviado.
[web@web sat]$ xsltproc cadena_original.xsl fact.xml | openssl dgst -md5 -verify AAA010101AAA.cer.pem -signature sello
Verified OK
Generacion de archivo para impresion
Con el siguiente arhivo de transformacion genero un archivo HTML para consultar en un formato 'agradable al usuario' el contenido de la factura XML.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
<xsl:stylesheet version = '1.0'
     xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
 
<xsl:output method = "html" /> 
 
<xsl:template match="/Comprobante">
   <html>
   <head>
   <link rel="STYLESHEET" media="screen" type="text/css" href="factura.css"/>
   <title>Factura Electronica <xsl:value-of select="@serie"/><xsl:value-of select="@folio"/></title>
   </head>
   <body>
   <table width="100%" border="1">
      <tr><td colspan="2" align="right">
          <table border="1">
               <tr><th class="h1">Serie</th><td class="h1"><xsl:value-of select="@serie"/></td></tr>
               <tr><th class="h1">Folio</th><td class="h1"><xsl:value-of select="@folio"/></td></tr>
               <tr><th class="h1">Fecha</th><td class="h1"><xsl:value-of select="@fecha"/></td></tr>
               <tr><th class="h1">Aprobacion</th><td class="h1"><xsl:value-of select="@noAprobacion"/></td></tr>
           </table>
           </td>
           </tr>
      <tr><td width="50%">
           <table width="100%" border="1"><tr><th colspan="2" class="h1">Emisor</th></tr>
             <tr><th>RFC</th><td><xsl:value-of select="Emisor/@rfc"/></td></tr>
             <tr><th>Nombre</th><td><xsl:value-of select="Emisor/@nombre"/></td></tr>
             <tr><th colspan="2" class="h2">Domiclio</th></tr>
             <tr><td colspan="2"><xsl:value-of select="Emisor/DomicilioFiscal/@calle"/> # <xsl:value-of select="Emisor/DomicilioFiscal/@noExterior"/> - <xsl:value-of select="Emisor/DomicilioFiscal/@noEInterior"/></td></tr>
             <tr><td colspan="2"><xsl:value-of select="Emisor/DomicilioFiscal/@colonia"/></td></tr>
             <tr><td colspan="2"><xsl:value-of select="Emisor/DomicilioFiscal/@localidad"/></td></tr>
             <tr><td colspan="2"><xsl:value-of select="Emisor/DomicilioFiscal/@referencia"/></td></tr>
             <tr><td colspan="2"><xsl:value-of select="Emisor/DomicilioFiscal/@municipio"/>
                 <xsl:if test="Emisor/DomicilioFiscal/@codigoPostal"> CODIGO POSTAL <xsl:value-of select="Emisor/DomicilioFiscal/@codigoPostal"/></xsl:if>
                 </td></tr>
             <tr><td colspan="2"><xsl:value-of select="Emisor/DomicilioFiscal/@estado"/></td></tr>
             <tr><td colspan="2"><xsl:value-of select="Emisor/DomicilioFiscal/@pais"/></td></tr>
             </table>
          </td>
          <td>
          <table width="100%" border="1"><tr><th colspan="2" class="h1">Receptor</th></tr>
             <tr><th>RFC</th><td><xsl:value-of select="Receptor/@rfc"/></td></tr>
             <tr><th>Nombre</th><td><xsl:value-of select="Receptor/@nombre"/></td></tr>
             <tr><th colspan="2" class="h2">Domicilio</th></tr>
             <tr><td colspan="2"><xsl:value-of select="Receptor/Domicilio/@calle"/> # <xsl:value-of select="Receptor/Domicilio/@noExterior"/> - <xsl:value-of select="Receptor/Domicilio/@noEInterior"/></td></tr>
             <tr><td colspan="2"><xsl:value-of select="Receptor/Domicilio/@colonia"/></td></tr>
             <tr><td colspan="2"><xsl:value-of select="Receptor/Domicilio/@localidad"/></td></tr>
             <tr><td colspan="2"><xsl:value-of select="Receptor/Domicilio/@referencia"/></td></tr>
             <tr><td colspan="2"><xsl:value-of select="Receptor/Domicilio/@municipio"/>
                 <xsl:if test="Receptor/Domicilio/@codigoPostal"> CODIGO POSTAL <xsl:value-of select="Receptor/Domicilio/@codigoPostal"/></xsl:if>
                 </td></tr>
             <tr><td colspan="2"><xsl:value-of select="Receptor/Domicilio/@estado"/></td></tr>
             <tr><td colspan="2"><xsl:value-of select="Receptor/Domicilio/@pais"/></td></tr>
           </table>
           </td>
         </tr>
         <tr><table width="100%" border="1">
             <tr><th>Cantidad</th>
                 <th>Descripcion</th>
                 <th>Precio</th>
                 <th>Importe</th>
             </tr>
             <xsl:for-each select="Conceptos/Concepto">
                 <tr><td align="center"><xsl:value-of select="@cantidad"/></td>
                     <td><xsl:value-of select="@descripcion"/></td>
                     <td align="right"><xsl:value-of select="@valorUnitario"/></td>
                     <td align="right"><xsl:value-of select="@importe"/></td>
                 </tr>
             </xsl:for-each>
             <tr><td colspan="3"/>
                 <td><xsl:value-of select="Impuestos/Traslado/@impuesto"/></td>
                 <td><xsl:value-of select="IMpuestos/Traslados/@importe"/></td>
             </tr>
            </table>
         </tr>
        </table>
        <hr/>
        <table width="100%" border="1">
            <tr><th>Numero de serie del Certificado</th></tr>
            <tr><td><xsl:value-of select="@noCertificado"/></td></tr>
            <tr><th>Cadena Original</th></tr>
            <tr><td><xsl:value-of select="Addenda/@cadenaOriginal"/></td></tr>
            <tr><th>Sello Digital</th></tr>
            <tr><td><small><small><xsl:value-of select="@sello"/></small></small></td></tr>
        </table>
        <center>
        Este documento es una impresion de un comprobante fiscal digital
        </center>
    </body>
    </html>
</xsl:template>
 
 
</xsl:stylesheet>
/div>
Invocamos la regla de transformacion para generar el archivo HTML de salida y ya lo podemos consultar o mandar a imprimir.
xsltproc impresion.xml fact.xml > fact.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="STYLESHEET" media="screen" type="text/css" href="factura.css">
<title>Factura Electronica FAXA051661</title>
</head>
<body>
<table width="100%" border="1">
<tr><td colspan="2" align="right"><table border="1">
<tr>
<th class="h1">Serie</th>
<td class="h1">FAXA</td>
</tr>
<tr>
<th class="h1">Folio</th>
<td class="h1">051661</td>
</tr>
<tr>
<th class="h1">Fecha</th>
<td class="h1">2006-11-20T08:50:48</td>
</tr>
<tr>
<th class="h1">Aprobacion</th>
<td class="h1">2951</td>
</tr>
</table></td></tr>
<tr>
<td width="50%"><table width="100%" border="1">
<tr><th colspan="2" class="h1">Emisor</th></tr>
<tr>
<th>RFC</th>
<td>FJC780315E91</td>
</tr>
<tr>
<th>Nombre</th>
<td>FABRICA DE JABON, LA CORONA, S.A. DE C.V.</td>
</tr>
<tr><th colspan="2" class="h2">Domiclio</th></tr>
<tr><td colspan="2">CARLOS B. ZETINA # 80 - </td></tr>
<tr><td colspan="2">INDUSTRIAL XALOSTOC</td></tr>
<tr><td colspan="2"></td></tr>
<tr><td colspan="2"></td></tr>
<tr><td colspan="2">ECATEPEC CODIGO POSTAL 55348</td></tr>
<tr><td colspan="2">MEXICO</td></tr>
<tr><td colspan="2">MEXICO</td></tr>
</table></td>
<td><table width="100%" border="1">
<tr><th colspan="2" class="h1">Receptor</th></tr>
<tr>
<th>RFC</th>
<td>NWM9709244W4</td>
</tr>
<tr>
<th>Nombre</th>
<td>NUEVA WAL-MART DE MEXICO SRL DE CV</td>
</tr>
<tr><th colspan="2" class="h2">Domicilio</th></tr>
<tr><td colspan="2">KM.40.5 CARRT. MEXICO-QUERETARO #  - </td></tr>
<tr><td colspan="2">.</td></tr>
<tr><td colspan="2"></td></tr>
<tr><td colspan="2"></td></tr>
<tr><td colspan="2">CUAUTITLAN IZCALLI       MEX.</td></tr>
<tr><td colspan="2">MEXICO</td></tr>
<tr><td colspan="2">MEXICO</td></tr>
</table></td>
</tr>
<tr><table width="100%" border="1">
<tr>
<th>Cantidad</th>
<th>Descripcion</th>
<th>Precio</th>
<th>Importe</th>
</tr>
<tr>
<td align="center">22</td>
<td>TEPEYAC 25P 400 G C/ENV</td>
<td align="right">110.97</td>
<td align="right">2441.34</td>
</tr>
<tr>
<td align="center">11</td>
<td>ZOTE AZUL 25P 400 G.</td>
<td align="right">110.97</td>
<td align="right">1220.67</td>
</tr>
<tr>
<td align="center">22</td>
<td>ZOTE BCO. 25P 400 G</td>
<td align="right">110.97</td>
<td align="right">2441.34</td>
</tr>
<tr>
<td align="center">7</td>
<td>ZOTE BCO. 50P 200 G</td>
<td align="right">110.97</td>
<td align="right">776.79</td>
</tr>
<tr>
<td align="center">44</td>
<td>ZOTE ROSA 25P 400 G</td>
<td align="right">110.97</td>
<td align="right">4882.68</td>
</tr>
<tr>
<td align="center">6</td>
<td>ZOTE ROSA 50P 200 G</td>
<td align="right">110.97</td>
<td align="right">665.82</td>
</tr>
<tr>
<td align="center">12</td>
<td>ROMA 4P 5 KGS</td>
<td align="right">218.34</td>
<td align="right">2620.08</td>
</tr>
<tr>
<td align="center">24</td>
<td>ROMA 10P 2 KGS</td>
<td align="right">219.74</td>
<td align="right">5273.64</td>
</tr>
<tr>
<td align="center">120</td>
<td>ROMA 10P 1 KG</td>
<td align="right">111.29</td>
<td align="right">13354.2</td>
</tr>
<tr>
<td align="center">12</td>
<td>FOCA 10P 2 KGS</td>
<td align="right">233.87</td>
<td align="right">2806.38</td>
</tr>
<tr>
<td align="center">10</td>
<td>BLANCA NIEVES 10P 2 KGS</td>
<td align="right">201.47</td>
<td align="right">2014.65</td>
</tr>
<tr>
<td align="center">40</td>
<td>BLANCA NIEVES 10P 1 KG</td>
<td align="right">102.15</td>
<td align="right">4086.0</td>
</tr>
<tr>
<td align="center">5</td>
<td>BRILOZA 10P 1 KG</td>
<td align="right">102.15</td>
<td align="right">510.75</td>
</tr>
<tr>
<td align="center">6</td>
<td>FOCA 12B 1LT</td>
<td align="right">121.73</td>
<td align="right">730.35</td>
</tr>
<tr>
<td colspan="3"></td>
<td></td>
<td></td>
</tr>
</table></tr>
</table>
<hr>
<table width="100%" border="1">
<tr><th>Numero de serie del Certificado</th></tr>
<tr><td>00001000000000823747</td></tr>
<tr><th>Cadena Original</th></tr>
<tr><td></td></tr>
<tr><th>Sello Digital</th></tr>
<tr><td><small><small>33HZqWoHi7u4gWkcnipTEiCz7UFOPGQ1NYqHmOyTGxpiJE8dyEBew8QS4f99zYz8QqXFvP0IEkWVCaKPBKm/6tClIdK/jJFZGxlcP/QCKfnBnMF/ktzukLLxHhwfK+StNpEkx90riDTITVv+wcmRy+kGrxlTB7N6gr1sK+tHBBI=</small></small></td></tr>
</table>
<center>
        Este documento es una impresion de un comprobante fiscal digital
        </center>
</body>
</html>
/div>
Si desea ver como se ve archivo de consulta de la factura electronica, dele click aqui
Generacion de archivo para informe mensual de folios