[FIX] tools: fix filename resolution in XSD imports
With PRs odoo/89145 and enterprise/26393 came new methods for retrieving XSD files and using them for XML validation. The new retrieval method expects modules to provide a 'prefix' that is prepended to the XSD's filename. For example, l10n_cl_edi will name its XSD files 'l10n_cl_edi.<filename>.xsd'. However, this messes things up when one XSD file needs to import another. For example, l10n_cl_edi.DTE_v10.xsd has the statement '<xs:include schemaLocation="SiiTypes_v10.xsd"/>' Currently, the filename resolver has no way of knowing that this should resolve to 'l10n_cl_edi.SiiTypes_v10.xsd', not 'SiiTypes_v10.xsd'. In addition, the new retrieval method saves the ZIP archives received over the network under the '<filename.xsd>'. Thus 'SiiTypes_v10.xsd' might actually be a ZIP-encoded file. So, we need to do something to fix the imports. Here are two possible solutions: 1. We scrap this 'prefix' stuff and either save the ZIP files under a different name, or we just don't save them. 2. Or, we provide a mechanism for indicating a prefix to the filename resolver. Personally, I don't see the point in saving the ZIP files, and this 'prefix' stuff seems pointless. So I prefer solution 1. But, because I assume there must be a reason to all of that 'prefix' stuff, here is an implementation of solution 2. I'd be keen to know the reason, btw. EDIT: In addition to the first issue described above, we have the second issue that some XSD files returned by the Chilean SII are encoded using ISO-8859-1 encoding (e.g. SiiTypes_v10.xsd). If we leave them in this encoding, then LXML isn't able to parse them when performing imports. closes odoo/odoo#102601 Solution: convert the files to UTF-8 before storing them. X-original-commit: 75555df56475b457331938453657c1f73d231e33 Related: odoo/enterprise#32482 Signed-off-by: Josse Colpaert <jco@odoo.com>
This commit is contained in:
+12
-8
@@ -1,7 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Utilities for generating, parsing and checking XML/XSD files on top of the lxml.etree module."""
|
||||
|
||||
import base64
|
||||
import logging
|
||||
import requests
|
||||
import zipfile
|
||||
@@ -20,18 +19,20 @@ class odoo_resolver(etree.Resolver):
|
||||
It will search filenames in the ir.attachments
|
||||
"""
|
||||
|
||||
def __init__(self, env):
|
||||
def __init__(self, env, prefix):
|
||||
super().__init__()
|
||||
self.env = env
|
||||
self.prefix = prefix
|
||||
|
||||
def resolve(self, url, id, context):
|
||||
"""Search url in ``ir.attachment`` and return the resolved content."""
|
||||
attachment = self.env['ir.attachment'].search([('name', '=', url)])
|
||||
attachment_name = f'{self.prefix}.{url}' if self.prefix else url
|
||||
attachment = self.env['ir.attachment'].search([('name', '=', attachment_name)])
|
||||
if attachment:
|
||||
return self.resolve_string(base64.b64decode(attachment.datas), context)
|
||||
return self.resolve_string(attachment.raw, context)
|
||||
|
||||
|
||||
def _check_with_xsd(tree_or_str, stream, env=None):
|
||||
def _check_with_xsd(tree_or_str, stream, env=None, prefix=None):
|
||||
"""Check an XML against an XSD schema.
|
||||
|
||||
This will raise a UserError if the XML file is not valid according to the
|
||||
@@ -42,12 +43,15 @@ def _check_with_xsd(tree_or_str, stream, env=None):
|
||||
If env is given, it can also be the name of an attachment in the filestore
|
||||
:param odoo.api.Environment env: If it is given, it enables resolving the
|
||||
imports of the schema in the filestore with ir.attachments.
|
||||
:param str prefix: if given, provides a prefix to try when
|
||||
resolving the imports of the schema. e.g. prefix='l10n_cl_edi' will
|
||||
enable 'SiiTypes_v10.xsd' to be resolved to 'l10n_cl_edi.SiiTypes_v10.xsd'.
|
||||
"""
|
||||
if not isinstance(tree_or_str, etree._Element):
|
||||
tree_or_str = etree.fromstring(tree_or_str)
|
||||
parser = etree.XMLParser()
|
||||
if env:
|
||||
parser.resolvers.add(odoo_resolver(env))
|
||||
parser.resolvers.add(odoo_resolver(env, prefix))
|
||||
if isinstance(stream, str) and stream.endswith('.xsd'):
|
||||
attachment = env['ir.attachment'].search([('name', '=', stream)])
|
||||
if not attachment:
|
||||
@@ -259,7 +263,7 @@ def load_xsd_files_from_url(env, url, file_name, force_reload=False,
|
||||
return fetched_attachment
|
||||
|
||||
|
||||
def validate_xml_from_attachment(env, xml_content, xsd_name, reload_files_function=None):
|
||||
def validate_xml_from_attachment(env, xml_content, xsd_name, reload_files_function=None, prefix=None):
|
||||
"""Try and validate the XML content with an XSD attachment.
|
||||
If the XSD attachment cannot be found in database, (re)load it.
|
||||
|
||||
@@ -275,7 +279,7 @@ def validate_xml_from_attachment(env, xml_content, xsd_name, reload_files_functi
|
||||
if env.context.get('skip_xsd', False):
|
||||
return
|
||||
try:
|
||||
_check_with_xsd(xml_content, xsd_name, env)
|
||||
_check_with_xsd(xml_content, xsd_name, env, prefix)
|
||||
except FileNotFoundError:
|
||||
if not reload_files_function:
|
||||
_logger.warning("You need to provide a function used to (re)load XSD files")
|
||||
|
||||
Reference in New Issue
Block a user