Como extraer la fecha, el nombre del emisor y el UUID de un archivo .xml y renombrarlo con estos datos?
He visto que has ayudado a varias personas en este foro acerca de la extración de datos dentro de un .xml, lo he querido adaptar pero la verdad mis conocimientos de batch son nulos.
Mi intencion es extraer la fecha, el nombre del emisor y el UUID dentro del archivo
Por ejemplo, el proveedor manda estos archivos nombrados:
KB503640.xml
KB503640.pdf
Y la intención seria que quedaran así:
2021-01-18 EMISOR SA DE CV CC04E100-4E32-48D8-BFBD-039B5E766B8D.XML
2021-01-18 EMISOR SA DE CV CC04E100-4E32-48D8-BFBD-039B5E766B8D.PDF
Datos a extraer
Cfdi:Comprobante - "Fecha"
Cfdi:Emisor - "Nombre"
Cfdi:Complemento-tfd:TimbreFiscalDigital- "UUID"
¿Me podrás ayudar mi estimado?
2 Respuestas
<?xml version="1.0" encoding="UTF-8"?>
<cfdi:Comprobante xmlns:cfdi="http://www.sat.gob.mx/cfd/3" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" Certificado="MIIGAzCCA+ugAwIBAgIUMDAwMDEwMDAwMDA1MDYwMDk0MDMwDQYJKoZIhvcNAQELBQAwggGEMSAwHgYDVQQDDBdBVVRPUklEQUQgQ0VSVElGSUNBRE9SQTEuMCwGA1UECgwlU0VSVklDSU8gREUgQ71cym38k4O9h10wqgik/WPRIgLZ4PHInuRlLjWd6lNiEMU8OeqwI4RqQHyGOXoFXYWTH2zFD9sDIn6ZvSKDvV5cC3A==" Fecha="2021-01-18T13:42:32" Folio="3693" FormaPago="28" LugarExpedicion="66600" MetodoPago="PUE" Moneda="MXN" NoCertificado="00001000000506009403" Sello="ezDhJFMPtG680JR3vIpt6cxRm1TZFdMqItpjYFgqeGMwmNzELzbFO2kdBY1zUnT1rZCaMIDW6RC7GnYReQk5GUFkPccVifWvblinsiQMisREq7+BgeFGjM+3fG20ct5G2qjJPUq+nCK6P4xGQwAQPZTdQx4bIiM2YE68R3drj/0ZFceuLmDNvHXIC46Hz2pSxDf1nKxcT4ySvfwMwJ0HWi04DSoKbrh4LEbo2gPG4eI7jWkTnzsaV2h7BMS/PHIW4xDqCe+MNptOWSelp0lJlA8CKMO2FkgRDFCb2rQHHppo7FnfBh/qtqfNImwhbBprAgzpFBXYpDtdelklFusGTA==" Serie="WSTL" SubTotal="432.68" TipoCambio="1" TipoDeComprobante="I" Total="500.00" Version="3.3" xsi:schemaLocation="http://www.sat.gob.mx/cfd/3 http://www.sat.gob.mx/sitio_internet/cfd/3/cfdv33.xsd">
<cfdi:Emisor Nombre="EMISOR, S.A. DE C.V." RegimenFiscal="601" Rfc="EMI090907K23" />
<cfdi:Receptor Nombre="RECEPTOR SA DE CV" Rfc="REC2125201DQ" UsoCFDI="G03" />
<cfdi:Conceptos>
<cfdi:Concepto Cantidad="26.3300" ClaveProdServ="15101514" ClaveUnidad="LTR" Descripcion="BP REGULAR 87 OCTANOS" Importe="432.68" NoIdentificacion="PL/3919/EXP/ES/2015-12892080" Unidad="Litro" ValorUnitario="16.432958">
<cfdi:Impuestos>
<cfdi:Traslados>
<cfdi:Traslado Base="420.75" Importe="67.32" Impuesto="002" TasaOCuota="0.160000" TipoFactor="Tasa" />
</cfdi:Traslados>
</cfdi:Impuestos>
</cfdi:Concepto>
</cfdi:Conceptos>
<cfdi:Impuestos TotalImpuestosTrasladados="67.32">
<cfdi:Traslados>
<cfdi:Traslado Importe="67.32" Impuesto="002" TasaOCuota="0.160000" TipoFactor="Tasa" />
</cfdi:Traslados>
</cfdi:Impuestos>
<cfdi:Complemento>
<tfd:TimbreFiscalDigital FechaTimbrado="2021-01-18T13:42:33" NoCertificadoSAT="00001000000504204971" RfcProvCertif="PPD101129EA3" SelloCFD="ezDhJFMPtG680JR3vIpt6cxRm1TZFdMqItpjYFgqeGMwmNzELzbFO2kdBY1zUnT1rZCaMIDW6RC7GnYReQk5GUFkPccVifWvblinsiQMisREq7+BgeFGjM+3fG20ct5G2qjJPUq+nCK6P4xGQwAQPZTdQx4bIiM2YE68R3drj/0ZFceuLmDNvHXIC46Hz2pSxDf1nKxcT4ySvfwMwJ0HWi04DSoKbrh4LEbo2gPG4eI7jWkTnzsaV2h7BMS/PHIW4xDqCe+MNptOWSelp0lJlA8CKMO2FkgRDFCb2rQHHppo7FnfBh/qtqfNImwhbBprAgzpFBXYpDtdelklFusGTA==" SelloSAT="A6RLuV83HQ8Eb7ILEre0m9ANsSHw4BchyzoWiMvq5RRPGKBo3a242uu2Gbh96TvNfgEs0IR8j/LMAb5xuItTNeyVrNXTCXQHs05XAKVijgt5Ara1aGMzqCvndHFud1lnmtfhthUJiD8I5vti/hUisUZvBIx6mFLRoMaRn4pewjvp7PFHgc75ttHmbQC86Gz6Xbt/jCsrHR9eG6IpI3TtQEzlioO4+ja7UoWULaV/Z9ctYm5nATqdoqaKw5tEoBN0fJ+thncJ1xWxFpVxWaWkHNKaAtdI4NhW47JQMKTda992HK9sJfCRvwVrwXp7eXx9PhUHD2jL1Lv8SgmNwjslTQ==" UUID="CC04E100-4E32-48D8-BFBD-039B5E766B8D" Version="1.1" xsi:schemaLocation="http://www.sat.gob.mx/TimbreFiscalDigital http://www.sat.gob.mx/sitio_internet/cfd/TimbreFiscalDigital/TimbreFiscalDigitalv11.xsd" xmlns:tfd="http://www.sat.gob.mx/TimbreFiscalDigital" />
</cfdi:Complemento>
</cfdi:Comprobante>
- Compartir respuesta
Antes de ponerme con esto me gustaría que me aclarases algunas cosas:
1. Los archivos vienen por parejas XML/PDF por lo que basta con que trate los XML para obtener la información del nuevo nombre (leer PDFs desde un BAT podría no dar resultados). El renombrado (o copia, si no quieres perder los archivos originales) se haría para ambos tipos de archivo
2. Los tres campos de información que nos interesan vienen entre comillas dobles dentro del propio archivo XML, y precedidos de los literales indicados tal como los has escrito (incluidos los ":", "-" y espacios o ausencia de espacios).
3. El orden de aparición de esos campos es el que indicas. Esto no es imprescindible pero puede ayudar saber que siempre va a ser ese el orden
4. En el ejemplo que has puesto los campos en cuestión son:
Fecha: 2021-01-18
Nombre: EMISOR SA DE CV
UUID: CC04E100-4E32-48D8-BFBD-039B5E766B8D
5. Creo que ayudaría que copiaras un XML, o al menos la parte que contiene esta información, en esta página. Te sugiero que uses la herramienta "snippet" (icono <> de la pequeña barra de herramientas de la página, tercero desde la derecha) para copiar esa información de forma más legible.
Perdón, acabo de ver que ya habías aportado esa información en otra entrada del mismo hilo. La he visto después de mandar la respuesta. Creo que con eso ya puedo intentar hacer algo. Pero tendrá que ser mañana, probablemente.
Gracias por contestar mi estimado, ayer estuve buscando y encontré en github la solución para este problema https://github.com/rctorr/FacturaElectronica , bajé el código hecho en python y no funcionaba de primera mano, pero haciendo algunos ajustes logré que me renombrara mis archivos de manera masiva y como yo quería, ahora solo tengo el problema de que el nombre del archivo me gustaria que estuviera todo en mayusculas, anexo código:
import sys
import os
import glob
from optparse import OptionParser
from xml.dom import minidom
class XmlCFD(object):
#Esta clase se encarga de realizar todas las operaciones relacionadas
#con la manipulación del archivo xml de facturación electrónica
nomFileXml = ''
def __init__(self, nomFileXml):
#Initialize instance.
self.nomFileXml = nomFileXml
self.atributos = dict()
def getAtributos(self):
#Regresa los atributos necesario para formar el nombre del archivo.
if os.path.isfile(self.nomFileXml):
xmlDoc = minidom.parse(self.nomFileXml)
nodes = xmlDoc.childNodes
comprobante = nodes[0]
compAtrib = dict(comprobante.attributes.items())
# Se trunca la parte de la hora de emisión
self.atributos['Fecha'] = compAtrib['Fecha'][:10]
version = compAtrib['Version']
if version == "3.3" or version == "3.2": # CFDI
fecha = comprobante.getElementsByTagName('cfdi:Comprobante')
nombre = comprobante.getElementsByTagName('cfdi:Emisor')
complemento = comprobante.getElementsByTagName('cfdi:Complemento')
# Se obtiene el elementos correspondiente al timbre emitido por el PAC
timbre = comprobante.getElementsByTagName('tfd:TimbreFiscalDigital')
# Se obtiene el nombre del emisor
self.atributos['Nombre'] = nombre[0].getAttribute('Nombre')
# Se obtiene el valor del atributo UUID
self.atributos['UUID'] = timbre[0].getAttribute('UUID')
else:
print
print ("El archivo xml no es una versión válida de cfdi.")
print
return self.atributos
def rename(self, options):
#Renombra el archivo xml de la forma:
#Fecha_RFCemisor_serie_folio_subtotal_iva_total.xml
#Regresa el nuevo nombre del archivo
self.getAtributos()
nomFileXmlNew = os.path.dirname(self.nomFileXml)
# Se separa la extension del nombre del archivo
nomFileOld = os.path.splitext(self.nomFileXml)
#Nombres de los archivos con extension pdf y xml
nomFilePdfOld = nomFileOld[0]+'.pdf'
nomFileXmlOld = nomFileOld[0]+'.xml'
nomFileXmlNew += os.sep if len(nomFileXmlNew) > 0 else ""
if options.Fecha: # Se adiciona sólo si la opción -f está incluida
nomFileXmlNew += ''+self.atributos['Fecha']
if options.Nombre: # Se adiciona sólo si la opción -n está incluida
nomFileXmlNew += '_'+self.atributos['Nombre']
if options.UUID: # Se adiciona sólo si la opción -U se ha usado
nomFileXmlNew += '_'+self.atributos['UUID']
#Los nuevos nombres de archivos para pdf y xml
lineCSV = nomFileXmlNew
nomFilePdfNew = nomFileXmlNew+'.pdf'
nomFileXmlNew += '.xml'
# Si el XML final ya existe, no se renombra
if not os.path.isfile(nomFileXmlNew):
os.rename(nomFileXmlOld, nomFileXmlNew)
# Se valida que exista un archivo pdf llamado igual que el xml.
# Si el PDF final ya existe, no se renombra.
if not os.path.isfile(nomFilePdfNew):
if os.path.isfile(nomFilePdfOld):
os.rename(nomFilePdfOld, nomFilePdfNew)
if options.verbose:
print (self.nomFileXml+" => "+nomFileXmlNew)
def main(argv):
usage = "%prog [opciones] archivocfd.xml|*.xml"
add_help_option = False
parser = OptionParser(usage=usage, add_help_option=add_help_option)
parser.add_option("-f", "--Fecha", action="store_true",
help=u"Agrega el campo fecha")
parser.add_option("-n", "--Nombre", action="store_true",
help=u"Adiciona el nombre del emisor")
parser.add_option("-U", "--UUID", action="store_true",
help=u"Adiciona el UUID del timbre fiscal digital")
parser.add_option("-v", "--verbose", action="store_true",
help=u"Va mostrando la lista de los archivos modificados")
parser.add_option("-h", "--help", action="help",
help=u"muestra este mensaje de ayuda y termina")
(options, args) = parser.parse_args()
if len(args) == 0:
parser.print_help()
sys.exit(0)
# Se obtiene la lista de archivos
if len(args) == 1 and "*" not in args[0]:
files = args
elif len(args) == 1 and "*" in args[0]:
files = glob.glob(args[0])
else:
files = args
# if options.archivoSalida and os.path.isfile(options.archivoSalida):
# os.remove(options.archivoSalida)
for item in files:
nomFileXml = item
if not os.path.isfile(nomFileXml):
print ("El archivo "+nomFileXml+" no existe.")
else:
xmlcfd = XmlCFD(nomFileXml)
xmlcfd.rename(options)
#xmlcfd.createCSV()
if __name__ == "__main__":
main(sys.argv[1:])Cabe aclarar que no tengo conocimientos de programación pero lo modifiqué con pura lógica y agregué las varian¿bles que necesitaba. estoy seguro que tiene sentencias que no se necesitan para mi propósito pero al final me dió resultado.
Gracias nuevamente por tu atención
Me alegro de que lo hayas resuelto. No conozco Python pero no me cabe duda de que es más razonable hacer el tratamiento de los XML en un lenguaje orientado a objetos y más actual. En cuanto a que el nombre te salga en minúsculas solo se me ocurre que cambies en Python a minúsculas y a lo mejor en ese caso te sale en mayúsculas visto desde MSDOS/Windows. Es que MSDOS no distingue.
Aunque ya hayas resuelto tu problema, me quedé con las ganas de hacer un BAT para resolverlo y esto es lo que he pensado:
:: Para renombrar los archivos xml de una carpeta con el valor de campos internos
:: Parece que los caracteres ">" de las líneas del archivo dan problemas por eso los limpio en LINEA
@echo off
Setlocal EnableDelayedExpansion
set carpeta=d:\carpeta prueba
pushd %carpeta%
for /f %%z in ('dir /b *.xml') do (
for /f "delims=" %%a in ('find /i "Emisor Nombre=" ^< "%%z"') do (
set linea=%%a
set linea=!linea:^>=!
call :tratanom !linea!
)
for /f "delims=" %%a in ('find /i "Fecha=" ^< "%%z"') do (
set linea=%%a
set linea=!linea:^>=!
call :tratafecha !linea!
)
for /f "delims=" %%a in ('find /i "UUID=" ^< "%%z"') do (
set linea=%%a
set linea=!linea:^>=!
call :trataUUID "%%z" !linea!
)
)
Popd
goto :eof
:Tratanom
:Buclenom
if "%~1"=="Nombre" (
set nuevo=%~2
goto :eof
)
shift
goto :buclenom
:tratafecha
:buclefecha
if "%~1"=="Fecha" (
set fecha=%~2
set fecha=!fecha:~0,10!
set nuevo=!fecha! !nuevo!
goto :eof
)
shift
goto :buclefecha
:trataUUID
set nomarch=%~n1
:bucleUUID
if "%~1"=="UUID" (
set nuevo=!nuevo! %~2
echo ren %nomarch%.xml "!nuevo!.xml"
echo ren %nomarch%.pdf "!nuevo!.pdf"
goto :eof
)
Shift
goto :bucleUUIDEn la variable CARPETA habría que poner el PATH de la carpeta de los archivos a tratar y los ECHO de la rutina trataUUID son para ver el comando REN que se ejecutaría a efectos de control. Si es correcto basta con eliminar la "palabra" ECHO para que se ejecute el comando de renombrado. No se controla que ya se haya hecho el renombrado en una fase anterior, se me ocurre que se podría poner algo como KB*.xml en el DIR del primer FOR
- Compartir respuesta