1# Licensed under a 3-clause BSD style license - see LICENSE.rst 2""" 3Various XML-related utilities 4""" 5 6 7# ASTROPY 8from astropy.logger import log 9from astropy.utils import data 10from astropy.utils.xml import check as xml_check 11from astropy.utils.xml import validate 12 13# LOCAL 14from .exceptions import (warn_or_raise, vo_warn, W02, W03, W04, W05) 15 16 17__all__ = [ 18 'check_id', 'fix_id', 'check_token', 'check_mime_content_type', 19 'check_anyuri', 'validate_schema' 20 ] 21 22 23def check_id(ID, name='ID', config=None, pos=None): 24 """ 25 Raises a `~astropy.io.votable.exceptions.VOTableSpecError` if *ID* 26 is not a valid XML ID_. 27 28 *name* is the name of the attribute being checked (used only for 29 error messages). 30 """ 31 if (ID is not None and not xml_check.check_id(ID)): 32 warn_or_raise(W02, W02, (name, ID), config, pos) 33 return False 34 return True 35 36 37def fix_id(ID, config=None, pos=None): 38 """ 39 Given an arbitrary string, create one that can be used as an xml id. 40 41 This is rather simplistic at the moment, since it just replaces 42 non-valid characters with underscores. 43 """ 44 if ID is None: 45 return None 46 corrected = xml_check.fix_id(ID) 47 if corrected != ID: 48 vo_warn(W03, (ID, corrected), config, pos) 49 return corrected 50 51 52_token_regex = r"(?![\r\l\t ])[^\r\l\t]*(?![\r\l\t ])" 53 54 55def check_token(token, attr_name, config=None, pos=None): 56 """ 57 Raises a `ValueError` if *token* is not a valid XML token. 58 59 As defined by XML Schema Part 2. 60 """ 61 if (token is not None and not xml_check.check_token(token)): 62 return False 63 return True 64 65 66def check_mime_content_type(content_type, config=None, pos=None): 67 """ 68 Raises a `~astropy.io.votable.exceptions.VOTableSpecError` if 69 *content_type* is not a valid MIME content type. 70 71 As defined by RFC 2045 (syntactically, at least). 72 """ 73 if (content_type is not None and 74 not xml_check.check_mime_content_type(content_type)): 75 warn_or_raise(W04, W04, content_type, config, pos) 76 return False 77 return True 78 79 80def check_anyuri(uri, config=None, pos=None): 81 """ 82 Raises a `~astropy.io.votable.exceptions.VOTableSpecError` if 83 *uri* is not a valid URI. 84 85 As defined in RFC 2396. 86 """ 87 if (uri is not None and not xml_check.check_anyuri(uri)): 88 warn_or_raise(W05, W05, uri, config, pos) 89 return False 90 return True 91 92 93def validate_schema(filename, version='1.1'): 94 """ 95 Validates the given file against the appropriate VOTable schema. 96 97 Parameters 98 ---------- 99 filename : str 100 The path to the XML file to validate 101 102 version : str, optional 103 The VOTABLE version to check, which must be a string \"1.0\", 104 \"1.1\", \"1.2\" or \"1.3\". If it is not one of these, 105 version \"1.1\" is assumed. 106 107 For version \"1.0\", it is checked against a DTD, since that 108 version did not have an XML Schema. 109 110 Returns 111 ------- 112 returncode, stdout, stderr : int, str, str 113 Returns the returncode from xmllint and the stdout and stderr 114 as strings 115 """ 116 if version not in ('1.0', '1.1', '1.2', '1.3'): 117 log.info(f'{filename} has version {version}, using schema 1.1') 118 version = '1.1' 119 120 if version in ('1.1', '1.2', '1.3'): 121 schema_path = data.get_pkg_data_filename( 122 f'data/VOTable.v{version}.xsd') 123 else: 124 schema_path = data.get_pkg_data_filename( 125 'data/VOTable.dtd') 126 127 return validate.validate_schema(filename, schema_path) 128