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 :bucleUUID
En 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