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

Respuesta
1

<?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>

Respuesta
1

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

Añade tu respuesta

Haz clic para o

Más respuestas relacionadas