Para exportar las pieas en formato STEP hay que pinchar la pieza con el botón derecho y darle a exportar.
Y nos aparece esta pantalla donde elegimos el formato STEP que es uno de los que mas se utilizan para el mecanizado CNC.
Para exportar las pieas en formato STEP hay que pinchar la pieza con el botón derecho y darle a exportar.
Y nos aparece esta pantalla donde elegimos el formato STEP que es uno de los que mas se utilizan para el mecanizado CNC.
Para crear una pieza especular hay que seleccionar la herramienta "Mirror" la pieza y un plano que hará de espejo.
Si la pieza toca o es atravesada por el plano espejo, entonces nos solapa la pieza. Para ello es conveniente que el plano espejo no intersecte con la pieza.
En este caso hemos elegido la herramienta espejo ("Mirror") , se ha seleccionado la pieza "Part1" y en la vista isométrica se ha elegido el plano "Right" tal como se muestra en la figura, y con eso se crea una nueva pieza "Part3" que es la imagen especular de "Part1". Para ver mejor la cosa se ha seleccionado la vista isométrica
Para crear desplazamientos y copias de piezas 3D utilizamos la herramienta "Transform". Debemos elegir la pieza a mover (o copiar) y las coordenadas a desplazarnos. En el cubo de la derecha podemos ver la orientación de los ejes y por tanto saber si desplazamos en e eje "Y" en nuestro caso y un desplazamiento positivo en ese eje. También es importante si queremos copiar o simplemente desplazar.
Para crear el hueco de una pieza sobre otra, la pieza que da forma al hueco es la herramienta "tool".
Veamos como hacemos un hueco sobre el toro. Para ello primeramente hay que desplazar las piezas involucradas y dejarlas en la posición deseada.
Como ya sabemos crear piezas 3D por revolución y estrusión, vamos a quitarle un trozo cúbico al toro. Para ello creamos un cuadrado en sketch y lo extruimos formando un cubo y lo desplazamos a la posición desada para hacer el hueco en el toro.
Para ello es mas fácil hacer el sketch y no ocultar el toro. Y luego hacer una extrusión, tal como se muestra en la figura
Ahora se cambia de vista, por ejemplo a una isométrica para tener una mejor visión de lo que se hace un transform (desplazamiento) deseado
Ahora ya hemos tenemos las piezas en la posición deseada. Ahora vamos a la herramienta booleana y damos como herramienta "tool" al cubo y como objetivo "target" el toro y le decimos que conserve la herramienta. Ojo, en este caso modifica el toro, si nos hiciera falta posteriormente el toro sin agujeros, se tendrá que copiar antes de hacer esta transformación
Y queda tras ocultar la pieza2 (Part2) que es el cubo y mostrar solo la pieza1 (Part1) que es el toro con el agujero nos queda
Buscar en google "onshape sign in" y te pregunta usuario y contraseña.
Ahora vamos a "create" y "document" ambos en la parte superior izquierda
Le damos nombre y guardamos. A partir de aquí todo lo que se hace se guarda automáticamente
Ahora nos aparecen los 3 planos que corresponden a planta, alzado y perfil (top, front y right). Realmente el perfil no es el plano right sino "left"
Tambien hay un dibujo de un cubo en la parte superior izquierda que nos indica la orientación. Para cambiar la orientacion (rotar) se aprita el botón derecho del ratón y movemos el ratón y vemos como giramos.Con htmx, es facil modificar un componente tipo <div> con la información devuelta por una petición ajax provocada por un elemento de un formulario. En este ejemplo llenamos el componente <div> con el string "Hola
<form> <input type="text" name="miCampo" hx-get="/ruta-del-endpoint" hx-trigger="blur,change" hx-target="#resultado"> </form> <div id="resultado"></div>
#Python y fastHTML
@app.get("/ruta-del-endpoint") def getFieldEvent(request:Request): return "Hola!
Pero si queremos actualizar el valor de un element tipo input, no funciona.
Para ello tenemos que recurrir a javascript
Supongamos que tenemos 4 campos. De ellos 2 se encargan de modificar el conenido de los otros dos campos. En este ejemplo el campo1 modifica al campo2 y el campo3 modifica al campo4
<form> <input type="text" id="campo1" name="campo1" hx-get="/ruta-del-endpoint"
hx-trigger="blur,change" hx-target="#campo2">
<input type="text" id="campo2" name="campo2"><input type="text" id="campo3" name="campo3" hx-get="/ruta-del-endpoint"hx-trigger="blur,change" hx-target="#campo4"><input type="text" id="campo4" name="campo4">
</form>
Supongamos que el código Python del endpoint es el mismo
Para ello vamos a crear un program Python con FastHTML que haga los siguientes pasos:
1. Crear un objeto que guarde los ids de los campos que lanzan el evento como nombre del campo y como valor que sea el id del campo a modificar. En Python sería:
strJs="var paramsChange={'campo1':'campo2', 'campo3':'campo4'}"
2. Creamos un fichero (static/js/fieldChange.js) con el contenido de la función javascript que actualiza los campos: Para ello busca el evento "htmx:afterRequest" y filtra aquellos cuyo endpoint es "/ruta-del-endpoint" y si el campo que lanza el evento (event.target) se encuentra dentro de la variable paramsChange entonces actualiza el valor del campo con lo que retorno la llamada ajax
// Update an input element with the value of the request document.addEventListener("htmx:afterRequest", (event) => { const hxget=event.target.getAttribute('hx-get'); if (hxget) { const elemId=event.target.id; //Only for request type get to the url "/fieldEvent" if (hxget.startsWith("/ruta-del-endpoint") && elemId in paramsChange) {
const targetId=paramsChange[elemId]; const input = document.querySelector(targetId); input.value = event.detail.xhr.responseText; } } });
3. A la variable python "strJs" hay que añadirle el contenido de este fichero: que es javascript
with open('static/js/fieldChange.js', 'r') as file: content = file.read() strJs+="\n"+content
4. Para crear los campos con FastHTML podemos creatr un diccionario para cada campo con los atributos de cada "input". Podríamos haber creado un form , pero para simplificar meto el javascript y los 4 campos dentro de un <div> (fh.Div). A mi me encanta como resuelve fastHTML la creaciópn de campos. Ojo que utiliza guiones bajos "_" en vez de "-" cuando define los parámetros de htmx!
fieldDicts=[ {'type':'text', 'id':'campo1', 'name':'campo1','hx_post':'/ruta-del-endpoint', 'hx_target':'#campo2', 'hx_trigger':'blur,change'}, {'type':'text', 'id':'campo2', 'name':'campo2'}, {'type':'text', 'id':'campo3', 'name':'campo3','hx_post':'/ruta-del-endpoint', 'hx_target':'#campo4', 'hx_trigger':'blur,change'}, {'type':'text', 'id':'campo4', 'name':'campo4'}, ] return fh.Div( fh.Script(strJs), *[fh.Input(**fieldDict) for fieldDict in fieldDicts], )
En Linux-Mozilla los certificados se guardan en la carpeta hija de:
~/.mozilla/firefox
que contiene entre otros el fichero "cert9.db"
Por tanto hay que buscar las carpetas contenedoras de dicho fichero (puede haber varias)
En Linux-Chrome se guardan en la carpeta:
~/.pki/nssdb
Para manejar los certificados contenidos en cada carpeta hay que instalar algunas librerías del paquete NSS (Network Security Services).
sudo apt install libnss3-tools
certutil -L -d sql:$HOME/.mozilla/firefox/XXXX
certutil -L -d sql:$HOME/.pki/nsb
Certificate Nickname Trust Attributes
SSL,S/MIME,JAR/XPI
Mi nick u,u,u
ACME Root CA CT,C,C
Ahora podemos extraer los certificados a partir de la carpeta y el Nickname. En el lisado anterior vemos un nickname llamado "Mi nick". Para obtener este ceerificamos SIN CLAVE PRIVADA hacemos:
certutil -L -n "Mi nick" -d sql:$HOME/.pki/nsb -a > cert.pem
# Guardamos la conraseña en un fichero echo "mypasword" > temp_pass_file_path #Guardamos el certificado con la clave privada, protegidos por la contraseña "mypassword" pk12util -o, cert.pem -d sql:$HOME/.pki/nsb -n "My nick" -k $HOME/.pki/nsb/key4.db -w temp_pass_file_path
#Cambiamos el nombre y nos pedirá la nueva contraseña
openssl rsa -in cert.pem -out nuevo_certificado.pem -aes256
#Comprobamos que podemos leer el fichero con la nueva contraseña
openssl rsa -in nuevo_certificado.pem
Ejecutamos este programa de powershell para extrar todos los certificados a formato pfx y los protegemos con la contraseña "password_pfx"
# Ruta donde se guardarán los archivos PFX $outputFolder = "C:\ruta\certificados" # Crear la carpeta si no existe if (-not (Test-Path -Path $outputFolder)) { New-Item -ItemType Directory -Path $outputFolder } # Iterar sobre todos los certificados que se listan con "Get-ChildItem Cert:\CurrentUser\My" $certificates = Get-ChildItem Cert:\CurrentUser\My foreach ($cert in $certificates) { $filePath = Join-Path -Path $outputFolder -ChildPath ("cert_" + $cert.Thumbprint + ".pfx") $password = ConvertTo-SecureString -String "password_pfx" -Force -AsPlainText Export-PfxCertificate -Cert $cert -FilePath $filePath -Password $password Write-Host "Exportado: $filePath" }
Y para convertir de pfx a pem utilizamos el power shell, manteniendo la misma contraseña:
# Ruta donde están los archivos PFX $pfxFolder = "C:\ruta\certificados" # Ruta donde se guardarán los archivos PEM $pemFolder = "C:\ruta\certificados_pem" # Crear la carpeta para los PEM si no existe if (-not (Test-Path -Path $pemFolder)) { New-Item -ItemType Directory -Path $pemFolder } # Convertir cada PFX a PEM $pfxFiles = Get-ChildItem -Path $pfxFolder -Filter "*.pfx" foreach ($pfx in $pfxFiles) { $pemFilePath = Join-Path -Path $pemFolder -ChildPath ($pfx.BaseName + ".pem") # Ejecutar OpenSSL para la conversión & "openssl" pkcs12 -in $pfx.FullName -out $pemFilePath -nodes -password pass:password_pfx Write-Host "Convertido a PEM: $pemFilePath" }
Solo se ha comprobado en Linux.
Veamos el código python
import os import platform import subprocess from cryptography.hazmat.primitives.serialization import Encoding, pkcs12, NoEncryption from cryptography.x509 import load_der_x509_certificate, load_pem_x509_certificate from cryptography import x509 from Crypto.IO import PEM from Crypto.PublicKey import RSA from OpenSSL.crypto import PKCS12, FILETYPE_PEM, dump_certificate, dump_privatekey import base64 import ssl import tempfile # ------Imprescindible para poder importar de otras carpetas (de basicutils) import sys from pathlib import Path for i in range(2):sys.path.append(str(Path(__file__).parents[i])) try: # if in the same folder then needs a try and import directly from basicutils import xmfiles except Exception as error: import xmfiles # ------Fin imprescindible #def save_certificate_to_file(cert, filename): # """Save a certificate to a file in PEM format.""" # try: # with open(filename, "wb") as f: # f.write(cert.public_bytes(Encoding.PEM)) # print(f"Certificate saved to {filename}") # except Exception as e: # print(f"Error saving certificate to file: {e}") def change_password(input_pem, input_password, output_pem, output_password): ''' Cambia la contraseña de un archivo PEM''' try: # Leer contenido del archivo PEM with open(input_pem, "rb") as file: pem_data = file.read() # Desencriptar la clave privada usando la contraseña existente key, _ = PEM.decode(pem_data, passphrase=input_password.encode("utf-8")) # Cargar la clave como objeto RSA rsa_key = RSA.import_key(key) # Re-encriptar la clave privada con la nueva contraseña encrypted_key = rsa_key.export_key(format="PEM", passphrase=output_password, pkcs=8) # Escribir el nuevo archivo PEM con la nueva contraseña with open(output_pem, "wb") as file: file.write(encrypted_key) print(f"Archivo PEM guardado como '{output_pem}' con la nueva contraseña.") except Exception as e: print(f"Error: {e}") def parse_certificate(browser:str, cert_data)->dict: """Parse a certificate into a dict and print details of an X.509 certificate.""" try: cert = load_der_x509_certificate(cert_data) except ValueError: try: cert = load_pem_x509_certificate(cert_data) except Exception as e: print(f"Failed to parse certificate: {e}") return None try: #print("\nCertificate Details:"); #print(f" Subject: {cert.subject}") # Obtener el CN subject = cert.subject cn = cert.subject.get_attributes_for_oid(x509.NameOID.COMMON_NAME)[0].value print(f" CN: {cn}") browseCN=browser+"-"+cn #print(f" Issuer: {cert.issuer}") ; #print(f" Serial Number: {cert.serial_number}") #print(f" Valid From: {cert.not_valid_before}"); #print(f" Valid To: {cert.not_valid_after}") #print(f" Signature Algorithm: {cert.signature_algorithm_oid}") except Exception as e: print(f"Failed to print certificate details: {e}") return {browseCN:cert} if cn else {'No CN':cert} def export_certificate_and_key_linux(nssDir:str, output_path:str, nickname:str, pkcs12_password:str,exportKey:bool=False): ''' Exports the certificate and key in a file "pem" and also into 2 diferent files, one for the cert (.crt) and another for te key (.key) if exportKey is False, the files ".crt" and ".key" are not created Parameters: nssDir (str): The path to the NSS database. output_path (str): The path where the files will be saved. nickname (str): The nickname of the certificate. pkcs12_password (str): The password for the PKCS#12 file. exportKey (bool): Whether to create crt and key files. ''' try: # Step 1: Define paths #nss_dir = os.path.expanduser("~/.pki/nssdb") if not os.path.exists(nssDir): raise FileNotFoundError(f"NSS database not found in {nssDir}. Ensure Chrome has certificates stored there.") # Step 2: Write password to a temporary file with tempfile.NamedTemporaryFile(delete=False, mode="w", prefix="pkcs12_", suffix=".pass") as temp_pass_file: temp_pass_file.write(pkcs12_password) temp_pass_file_path = temp_pass_file.name # Step 3: Export the certificate and key as a PKCS#12 file pkcs12_file = os.path.join(output_path, f"{nickname}.p12") pk12util_cmd = [ "pk12util", "-o", pkcs12_file, "-d", f"sql:{nssDir}", "-n", nickname, "-k", f"{nssDir}/key4.db", "-w", temp_pass_file_path ] print("Exporting PKCS#12 file...") subprocess.run(pk12util_cmd, check=True) print(f"PKCS#12 file exported to: {pkcs12_file}") if exportKey: # Step 4: Convert PKCS#12 to separate certificate and private key cert_file = os.path.join(output_path, f"{nickname}.crt") key_file = os.path.join(output_path, f"{nickname}.key") openssl_cmd = [ "openssl", "pkcs12", "-in", pkcs12_file, "-clcerts", "-nokeys", "-out", cert_file, "-nodes", "-password", f"pass:{pkcs12_password}" ] print("Extracting certificate...") subprocess.run(openssl_cmd, check=True) print(f"Certificate exported to: {cert_file}") openssl_key_cmd = [ "openssl", "pkcs12", "-in", pkcs12_file, "-nocerts", "-out", key_file, "-nodes", "-password", f"pass:{pkcs12_password}" ] print("Extracting private key...") subprocess.run(openssl_key_cmd, check=True) print(f"Private key exported to: {key_file}") except subprocess.CalledProcessError as e: print(f"Error executing command: {e}") except FileNotFoundError as e: print(e) except Exception as e: print(f"An unexpected error occurred: {e}") def export_user_certs_windows(output_path, password="my-password", export_format="pem"): """ Busca un certificado por nombre en el almacén de Windows, extrae su clave privada y lo guarda como PEM o PFX. Args: name (str): Nombre del certificado a buscar. output_path (str): Ruta donde se guardará el archivo exportado. password (str, optional): Contraseña para proteger el archivo PFX. export_format (str): Formato del archivo de salida ('pem' o 'pfx'). """ import wincertstore try: with wincertstore.CertSystemStore("MY") as store: for cert in store.itercerts(usage=wincertstore.CERT_FIND_ANY): # Extraer el certificado y la clave privada private_key = cert.get_key() certificate = cert.get_cert() # Verificar si la clave privada está disponible if not private_key: print("Advertencia: Clave privada no disponible o no exportable.") return if export_format == "pem": # Exportar como PEM cert_pem = dump_certificate(FILETYPE_PEM, certificate) key_pem = dump_privatekey(FILETYPE_PEM, private_key) with open(output_path, "wb") as f: f.write(key_pem) f.write(cert_pem) print(f"Certificado exportado como PEM: {output_path}") elif export_format == "pfx": # Exportar como PFX pfx = PKCS12() pfx.set_privatekey(private_key) pfx.set_certificate(certificate) pfx_data = pfx.export(password.encode() if password else None) with open(output_path, "wb") as f: f.write(pfx_data) print(f"Certificado exportado como PFX: {output_path}") else: print("Formato no soportado. Usa 'pem' o 'pfx'.") except Exception as e: print(f"Error: {e}") def list_user_certificates_linux(): """List user-installed certificates on Linux and display their details.""" certs = [] certificates=[] allCertsDict={} home_dir = os.path.expanduser("~") # Firefox Certificates firefox_path = os.path.join(home_dir, ".mozilla/firefox") if os.path.exists(firefox_path): #profiles = [d for d in os.listdir(firefox_path) if d.endswith(".default")] #for profile in profiles: # cert_db = os.path.join(firefox_path, profile, "cert9.db") # if os.path.exists(cert_db): # certs.append(("Firefox", cert_db)) certDBs=xmfiles.findFileInFolderRecursive('cert9.db', firefox_path) for i, certDB in enumerate(certDBs): certs.append(("Mz-"+str(i), certDB[1])) # Chrome Certificates chrome_path = os.path.join(home_dir, ".pki/nssdb") if os.path.exists(chrome_path): certs.append(("Ch", chrome_path)) # Display certificate details using `certutil` for browser, cert_db in certs: print(f"\n{browser} Certificates from {cert_db}:") try: output = subprocess.check_output(["certutil", "-L", "-d", f"sql:{cert_db}"], text=True) print(output) #================================================================ # Extract certificate nicknames and details lines = output.splitlines()[2:] # Skip the header lines for line in lines: try: #nickname = line.split()[0] nickname = line.split(' ')[0] print(f"Nickname: {nickname} Browser: {browser}") # Export each certificate in PEM format cert_output = subprocess.check_output( ["certutil", "-L", "-n", nickname, "-d", f"sql:{cert_db}", "-a"], text=True ) certDict=parse_certificate(browser,[cert_output.encode(), nickname, cert_db ]) allCertsDict.update(certDict) #add to all except Exception as e: print(f"Failed to export certificate '{line}'") except Exception as e: print(f"Error reading {browser} certificates: {e}") #return certs return allCertsDict def list_user_certificates_mac(): """List user-installed certificates on macOS and display their details.""" user_certs = [] allCertsDict={} try: output = subprocess.check_output( ["security", "find-certificate", "-c", "User", "-a", "-p"], text=True ) certs = output.split("-----END CERTIFICATE-----") for cert in certs: if cert.strip(): pem_cert = cert + "-----END CERTIFICATE-----" print("\nCertificate PEM Format:") print(pem_cert) user_certs.append(pem_cert) certDict=parse_certificate(pem_cert.encode()) allCertsDict.update(certDict) except Exception as e: print(f"Error accessing user certificates on macOS: {e}") #return user_certs return allCertsDict def main(): print("Listing all user-installed certificates...\n") user_certs = [] if platform.system() == "Linux": # Linux home_dir = os.path.expanduser("~") chrome_path = os.path.join(home_dir, ".pki/nssdb") #export_certificate_and_key_linux(chrome_path, "/home/edu/MyCerts/Prova", "EPN1", "my-password") print("User Certificates (Linux):") user_certs = list_user_certificates_linux() print("===================================================================") for k,v in user_certs.items(): print(k) print(" ",v) export_certificate_and_key_linux(nssDir=v[2], output_path="/home/edu/MyCerts/Prova", nickname=v[1],pkcs12_password="my-password", exportKey=False ) print("-------------------------------") elif platform.system() == "Windows": # Windows print("User Certificates (Windows):") export_user_certs_windows("C:\\Users\\edu\\MyCerts\\Prova", export_format="pem") elif platform.system() == "Darwin": # macOS print("User Certificates (macOS):") user_certs = list_user_certificates_mac() if __name__ == "__main__": main()
Para ello se opta por utilizar Pyjnius, py4j, jpype, scyjava ..
Primeramente se instala maven en ubuntu:
sudo apt install maven -y
Creamos una carpeta que será la de nuestro proyecto, nos situamos dentro de ella
Vamos a mavencentral y buscamos nuestra dependencia por ejempo itext7 y descargamos el pom.xml en la carpteta
Veamos un ejemplo de pom.xml para poder descargar la libreria itext7
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>mi-proyecto-itext</artifactId> <version>1.0-SNAPSHOT</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> <itext.version>9.0.0</itext.version> </properties> <dependencies> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itext7-core</artifactId> <version>${itext.version}</version> <type>pom</type> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <release>17</release> </configuration> </plugin> </plugins> </build> </project>
Ejecutamos
mvn dependency:copy-dependencies -DoutputDirectory=target/dependencies
si no se especifica -DoutputDirectory entonces lo descarga en target/dependencies
o tambien
mvn dependency:resolve -U
pero las copia en ~/.m2/repository/com/itextpdf/itext7-core/7.2.5/itext7-core-7.2.5.jar
Queremos extraer el contenido del nodo <ValorBinario> de este fichero xml que namespaces:
Nos fijamos que el namespace marcado en naranja no tiene nombre, por tanto se aplicará a todas los nodos cuyas etiquetas no tenganprefijo del namespace como "contenido" o "ValorBinario"
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <insidews:documento xmlns="http://administracionelectronica.gob.es/ENI/XSD/v1.0/documento-e/contenido"
xmlns:ns2="http://administracionelectronica.gob.es/ENI/XSD/v1.0/documento-e/metadatos"
xmlns:ns3="http://administracionelectronica.gob.es/ENI/XSD/v1.0/firma"
xmlns:ns4="http://www.w3.org/2000/09/xmldsig#"
xmlns:ns5="http://administracionelectronica.gob.es/ENI/XSD/v1.0/documento-e"
xmlns:ns6="https://ssweb.seap.minhap.es/Inside/XSD/v1.0/metadatosAdicionales"
xmlns:ns7="https://ssweb.seap.minhap.es/Inside/XSD/v1.0/documento-e"
xmlns:insidews="https://ssweb.seap.minhap.es/Inside/XSD/v1.0/WebService"> <ns5:documento Id="ES_L01462384_2022_2_ACORDS_PLE000001"> <contenido Id="CONTENIDO_DOCUMENTO"> <ValorBinario>JVB..</ValorBinario> <NombreFormato>PDF</NombreFormato> </contenido> <ns2:metadatos Id="DOC_ES_L01462384_2022_2_ACORDS_PLE000001_METADATOS"> <ns2:VersionNTI>http://administracionelectronica.gob.es/ENI/XSD/v1.0/documento-e</ns2:VersionNTI> <ns2:Identificador>ES_L01462384_2022_2_ACORDS_PLE000001</ns2:Identificador> <ns2:Organo>L01462384</ns2:Organo> <ns2:FechaCaptura>2024-11-05T00:00:00.000+01:00</ns2:FechaCaptura> <ns2:OrigenCiudadanoAdministracion>true</ns2:OrigenCiudadanoAdministracion> <ns2:EstadoElaboracion> <ns2:ValorEstadoElaboracion>EE99</ns2:ValorEstadoElaboracion> </ns2:EstadoElaboracion> <ns2:TipoDocumental>TD02</ns2:TipoDocumental> </ns2:metadatos> <ns3:firmas> <ns3:firma Id="FIRMA_1"> <ns3:TipoFirma>TF06</ns3:TipoFirma> <ns3:ContenidoFirma> <ns3:FirmaConCertificado> <ns3:ReferenciaFirma xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">#CONTENIDO_DOCUMENTO</ns3:ReferenciaFirma> </ns3:FirmaConCertificado> </ns3:ContenidoFirma> </ns3:firma>
<ns3:firma Id="FIRMA_2"> <ns3:TipoFirma>TF06</ns3:TipoFirma> <ns3:ContenidoFirma> <ns3:FirmaConCertificado> <ns3:ReferenciaFirma xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">#CONTENIDO_DOCUMENTO</ns3:ReferenciaFirma> </ns3:FirmaConCertificado> </ns3:ContenidoFirma> </ns3:firma> </ns3:firmas> </ns5:documento> <ns7:metadatosAdicionales> <ns6:MetadatoAdicional tipo="string" nombre="eEMGDE3.1.Nombre.NombreNatural"> <ns6:valor xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">$5.NOM_DOC$</ns6:valor> </ns6:MetadatoAdicional> </ns7:metadatosAdicionales> </insidews:documento>
para ello se ha creado este programa python
import base64 from lxml import etree def extraer_pdf(xml_path, output_pdf_path): try: # Cargar el archivo XML with open(xml_path, "rb") as xml_file: xml_data = xml_file.read() # Parsear el XML tree = etree.fromstring(xml_data) # Definir los namespaces utilizados en el XML namespaces = { "insidews": "https://ssweb.seap.minhap.es/Inside/XSD/v1.0/WebService", "ns5": "http://administracionelectronica.gob.es/ENI/XSD/v1.0/documento-e", "contenido": "http://administracionelectronica.gob.es/ENI/XSD/v1.0/documento-e/contenido" } # Listar nodos para depuración print("Nodos disponibles:") for elem in tree.iter(): print(f"{elem.tag}") # Buscar el contenido del tag <ValorBinario> valor_binario_node = tree.xpath( "//insidews:documento/ns5:documento/contenido:contenido/contenido:ValorBinario", namespaces=namespaces ) if not valor_binario_node: raise ValueError("No se encontró el tag <ValorBinario> en el documento XML.") # Extraer el contenido en Base64 valor_binario = valor_binario_node[0].text # Decodificar el contenido Base64 pdf_data = base64.b64decode(valor_binario) # Guardar el contenido en el archivo PDF with open(output_pdf_path, "wb") as pdf_file: pdf_file.write(pdf_data) print(f"Archivo PDF extraído correctamente y guardado en: {output_pdf_path}") except Exception as e: print(f"Error al procesar el archivo XML: {e}") # Ruta al archivo XML y al PDF de salida xml_path = "/home/eduard/MyPython/02.llibreriesOLD/ximo-python-library/ES_L01462384_2022_2_ACORDS_PLE000001.xml" output_pdf_path = "mifichero.pdf" # Ejecutar la función extraer_pdf(xml_path, output_pdf_path)
Y cuando nos lista los nodos aparece
{https://ssweb.seap.minhap.es/Inside/XSD/v1.0/WebService}documento {http://administracionelectronica.gob.es/ENI/XSD/v1.0/documento-e}documento {http://administracionelectronica.gob.es/ENI/XSD/v1.0/documento-e/contenido}contenido {http://administracionelectronica.gob.es/ENI/XSD/v1.0/documento-e/contenido}ValorBinario {http://administracionelectronica.gob.es/ENI/XSD/v1.0/documento-e/contenido}NombreFormato {http://administracionelectronica.gob.es/ENI/XSD/v1.0/documento-e/metadatos}metadatos {http://administracionelectronica.gob.es/ENI/XSD/v1.0/documento-e/metadatos}VersionNTI {http://administracionelectronica.gob.es/ENI/XSD/v1.0/documento-e/metadatos}Identificador {http://administracionelectronica.gob.es/ENI/XSD/v1.0/documento-e/metadatos}Organo {http://administracionelectronica.gob.es/ENI/XSD/v1.0/documento-e/metadatos}FechaCaptura {http://administracionelectronica.gob.es/ENI/XSD/v1.0/documento-e/metadatos}OrigenCiudadanoAdministracion {http://administracionelectronica.gob.es/ENI/XSD/v1.0/documento-e/metadatos}EstadoElaboracion {http://administracionelectronica.gob.es/ENI/XSD/v1.0/documento-e/metadatos}ValorEstadoElaboracion {http://administracionelectronica.gob.es/ENI/XSD/v1.0/documento-e/metadatos}TipoDocumental {http://administracionelectronica.gob.es/ENI/XSD/v1.0/firma}firmas {http://administracionelectronica.gob.es/ENI/XSD/v1.0/firma}firma {http://administracionelectronica.gob.es/ENI/XSD/v1.0/firma}TipoFirma {http://administracionelectronica.gob.es/ENI/XSD/v1.0/firma}ContenidoFirma {http://administracionelectronica.gob.es/ENI/XSD/v1.0/firma}FirmaConCertificado {http://administracionelectronica.gob.es/ENI/XSD/v1.0/firma}ReferenciaFirma {http://administracionelectronica.gob.es/ENI/XSD/v1.0/firma}firma {http://administracionelectronica.gob.es/ENI/XSD/v1.0/firma}TipoFirma {http://administracionelectronica.gob.es/ENI/XSD/v1.0/firma}ContenidoFirma {http://administracionelectronica.gob.es/ENI/XSD/v1.0/firma}FirmaConCertificado {http://administracionelectronica.gob.es/ENI/XSD/v1.0/firma}ReferenciaFirma {https://ssweb.seap.minhap.es/Inside/XSD/v1.0/documento-e}metadatosAdicionales {https://ssweb.seap.minhap.es/Inside/XSD/v1.0/metadatosAdicionales}MetadatoAdicional {https://ssweb.seap.minhap.es/Inside/XSD/v1.0/metadatosAdicionales}valor
A raiz de todo esto vemos que en el fichero xml, la ruta a <ValorBinario> es:
<insidews:documento><ns5:documento><contenido><ValorBinario>
Por otra parte si reducimos el listado anterior:
{https://ssweb.seap.minhap.es/Inside/XSD/v1.0/WebService}documento {http://administracionelectronica.gob.es/ENI/XSD/v1.0/documento-e}documento {http://administracionelectronica.gob.es/ENI/XSD/v1.0/documento-e/contenido}contenido {http://administracionelectronica.gob.es/ENI/XSD/v1.0/documento-e/contenido}ValorBinario
Vemos que contenido si tiene un namespace que es "contenido" y tambien ValorBinario tiene el namespace "contenido". Por tanto la ruta para llegar a valor binario es:
# Buscar el contenido del tag <ValorBinario> valor_binario_node = tree.xpath( "//insidews:documento/ns5:documento/contenido:contenido/contenido:ValorBinario", namespaces=namespaces )