Reputation: 183
I need to validate an xml that I generate with two XSD files provided. I am struggling because one of the XSD files references the other one and it looks that I am getting errors because of that.
The following is the "Invoice schema":
<?xml version="1.0" encoding="utf-8"?>
<!-- XSD ver.23/08/2021 -->
<xs:schema xmlns:ds="http://www.w3.org/2000/09/xmldsig#" attributeFormDefault="unqualified"
elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:import namespace="http://www.w3.org/2000/09/xmldsig#" schemaLocation="../SignatureSchema.xsd"/>
<xs:element name="facturaElectronicaCompraVenta">
<xs:complexType>
<xs:sequence>
<xs:element name="cabecera">
<xs:complexType>
<xs:sequence>
<xs:element name="nitEmisor">
<xs:simpleType>
<xs:restriction base="xs:integer">
<xs:minInclusive value="1"/>
<xs:maxInclusive value="9999999999999"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="razonSocialEmisor">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="200"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="municipio">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="25"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="telefono" nillable="true">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="25"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="numeroFactura">
<xs:simpleType>
<xs:restriction base="xs:integer">
<xs:minInclusive value="1"/>
<xs:maxInclusive value="9999999999"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="cuf">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="100"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="cufd">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="100"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="codigoSucursal">
<xs:simpleType>
<xs:restriction base="xs:integer">
<xs:minInclusive value="0"/>
<xs:maxInclusive value="9999"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="direccion">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="500"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="codigoPuntoVenta" nillable="true">
<xs:simpleType>
<xs:restriction base="xs:integer">
<xs:minInclusive value="0"/>
<xs:maxInclusive value="9999"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="fechaEmision" type="xs:dateTime"/>
<xs:element name="nombreRazonSocial" nillable="true">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="500"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="codigoTipoDocumentoIdentidad">
<xs:simpleType>
<xs:restriction base="xs:integer">
<xs:minInclusive value="1"/>
<xs:maxInclusive value="5"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="numeroDocumento">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="20"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="complemento" nillable="true">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:maxLength value="5"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="codigoCliente">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="100"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="codigoMetodoPago">
<xs:simpleType>
<xs:restriction base="xs:integer">
<xs:minInclusive value="1"/>
<xs:maxInclusive value="308"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="numeroTarjeta" nillable="true">
<xs:simpleType>
<xs:restriction base="xs:integer">
<xs:minInclusive value="0"/>
<xs:maxInclusive value="9999999999999999"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="montoTotal">
<xs:simpleType>
<xs:restriction base="xs:decimal">
<xs:totalDigits value="17"/>
<xs:fractionDigits value="2"/>
<xs:minExclusive value="0"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="montoTotalSujetoIva">
<xs:simpleType>
<xs:restriction base="xs:decimal">
<xs:totalDigits value="17"/>
<xs:fractionDigits value="2"/>
<xs:minInclusive value="0"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="codigoMoneda">
<xs:simpleType>
<xs:restriction base="xs:integer">
<xs:minInclusive value="1"/>
<xs:maxInclusive value="154"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="tipoCambio">
<xs:simpleType>
<xs:restriction base="xs:decimal">
<xs:totalDigits value="17"/>
<xs:fractionDigits value="2"/>
<xs:minExclusive value="0"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="montoTotalMoneda">
<xs:simpleType>
<xs:restriction base="xs:decimal">
<xs:totalDigits value="17"/>
<xs:fractionDigits value="2"/>
<xs:minExclusive value="0"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="montoGiftCard" nillable="true">
<xs:simpleType>
<xs:restriction base="xs:decimal">
<xs:totalDigits value="17"/>
<xs:fractionDigits value="2"/>
<xs:minInclusive value="0"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="descuentoAdicional" nillable="true">
<xs:simpleType>
<xs:restriction base="xs:decimal">
<xs:totalDigits value="17"/>
<xs:fractionDigits value="2"/>
<xs:minInclusive value="0"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="codigoExcepcion" nillable="true">
<xs:simpleType>
<xs:restriction base="xs:integer">
<xs:minInclusive value="0"/>
<xs:maxInclusive value="1"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="cafc" nillable="true">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="50"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="leyenda">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="200"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="usuario">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="100"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="codigoDocumentoSector" type="xs:integer" fixed="1"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="detalle" minOccurs="1" maxOccurs="500">
<xs:complexType>
<xs:sequence>
<xs:element name="actividadEconomica">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="10"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="codigoProductoSin">
<xs:simpleType>
<xs:restriction base="xs:integer">
<xs:minInclusive value="1"/>
<xs:maxInclusive value="99999999"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="codigoProducto">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="50"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="descripcion">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="1"/>
<xs:maxLength value="500"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="cantidad">
<xs:simpleType>
<xs:restriction base="xs:decimal">
<xs:totalDigits value="17"/>
<xs:fractionDigits value="2"/>
<xs:minExclusive value="0"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="unidadMedida">
<xs:simpleType>
<xs:restriction base="xs:integer">
<xs:minInclusive value="1"/>
<xs:maxInclusive value="86"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="precioUnitario">
<xs:simpleType>
<xs:restriction base="xs:decimal">
<xs:totalDigits value="17"/>
<xs:fractionDigits value="2"/>
<xs:minExclusive value="0"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="montoDescuento" nillable="true">
<xs:simpleType>
<xs:restriction base="xs:decimal">
<xs:totalDigits value="17"/>
<xs:fractionDigits value="2"/>
<xs:minInclusive value="0"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="subTotal">
<xs:simpleType>
<xs:restriction base="xs:decimal">
<xs:totalDigits value="17"/>
<xs:fractionDigits value="2"/>
<xs:minExclusive value="0"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="numeroSerie" nillable="true">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="0"/>
<xs:maxLength value="1500"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
<xs:element name="numeroImei" nillable="true">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:minLength value="0"/>
<xs:maxLength value="1500"/>
</xs:restriction>
</xs:simpleType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element ref="ds:Signature"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
And the following one is the "Signature schema":
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:tns="http://www.w3.org/2000/09/xmldsig#" attributeFormDefault="unqualified"
elementFormDefault="qualified" targetNamespace="http://www.w3.org/2000/09/xmldsig#"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Signature">
<xs:complexType>
<xs:sequence>
<xs:element name="SignedInfo">
<xs:complexType>
<xs:sequence>
<xs:element name="CanonicalizationMethod">
<xs:complexType>
<xs:attribute name="Algorithm" type="xs:string" use="required"/>
</xs:complexType>
</xs:element>
<xs:element name="SignatureMethod">
<xs:complexType>
<xs:attribute name="Algorithm" type="xs:string" use="required"/>
</xs:complexType>
</xs:element>
<xs:element name="Reference">
<xs:complexType>
<xs:sequence>
<xs:element name="Transforms">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" name="Transform">
<xs:complexType>
<xs:attribute name="Algorithm" type="xs:string"
use="required"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="DigestMethod">
<xs:complexType>
<xs:attribute name="Algorithm" type="xs:string" use="required"/>
</xs:complexType>
</xs:element>
<xs:element name="DigestValue" type="xs:string"/>
</xs:sequence>
<xs:attribute name="URI" type="xs:string" use="required"/>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="SignatureValue" type="xs:string"/>
<xs:element name="KeyInfo">
<xs:complexType>
<xs:sequence>
<xs:element name="X509Data">
<xs:complexType>
<xs:sequence>
<xs:element name="X509Certificate" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
The "Invoice schema" references the "Signature schema" with the namespace "schemaLocation" to the following location "../SignatureSchema.xsd". I am working with Odoo and I am storing the "Invoice schema" file under "MyModule/data/xsd/sale_purchase" and the "Signature schema" uder "MyModule/data/xsd/".
So I validate my files with the following code:
def _validate_invoice_xml(self):
root = self._get_xml_tree_root()
# Validate generated xml
xsd_file_path = get_module_resource('MyModule', 'data/xsd/sale_purchase', 'InvoiceSchema.xsd')
with open(xsd_file_path) as xsd_file:
invoice_schema = xsd_file.read()
# Decode XSD file
invoice_xsd = ET.fromstring(invoice_schema.encode('ascii'))
xmlschema = ET.XMLSchema(invoice_xsd)
validation_result = xmlschema.validate(root)
if not validation_result:
log = xmlschema.error_log
error = log.last_error
raise exceptions.ValidationError('XML file validation error:' + '\n' + str(error.message))
But when I run my code I get the following error:
lxml.etree.XMLSchemaParseError: Element '{http://www.w3.org/2001/XMLSchema}element', attribute 'ref': The QName value '{http://www.w3.org/2000/09/xmldsig#}Signature' does not resolve to a(n) element declaration., line 344
I believe that the error is related with the referencing of the "Signaute schema" with schemaLocation="../SignatureSchema.xsd". But I am not sure, the files are located where they should.
Why am I getting this error and how can I avoid it?
Upvotes: 0
Views: 374
Reputation: 183
As Michael Kay commented, I needed to get the absolute path to the XSD file. In odoo I have managed to do it by using the following code:
import os
# This gets the location of the absolute location of the python file running
current_location = os.path.dirname(os.path.realpath(__file__))
# Replacing part of the path to point to the XSD file location
schema_file_location = current_location.replace('models', 'data/pathToMyXSDfile.xsd')
# Validate XML file
xsd_file = ET.parse(schema_file_location)
xmlschema = ET.XMLSchema(xsd_file)
validation_result = xmlschema.validate(root)
Upvotes: 1