1# Licensed under a 3-clause BSD style license - see LICENSE.rst 2 3""" 4Functions to do XML schema and DTD validation. At the moment, this 5makes a subprocess call to xmllint. This could use a Python-based 6library at some point in the future, if something appropriate could be 7found. 8""" 9 10 11import os 12import subprocess 13 14 15def validate_schema(filename, schema_file): 16 """ 17 Validates an XML file against a schema or DTD. 18 19 Parameters 20 ---------- 21 filename : str 22 The path to the XML file to validate 23 24 schema_file : str 25 The path to the XML schema or DTD 26 27 Returns 28 ------- 29 returncode, stdout, stderr : int, str, str 30 Returns the returncode from xmllint and the stdout and stderr 31 as strings 32 """ 33 34 base, ext = os.path.splitext(schema_file) 35 if ext == '.xsd': 36 schema_part = '--schema ' + schema_file 37 elif ext == '.dtd': 38 schema_part = '--dtdvalid ' + schema_file 39 else: 40 raise TypeError("schema_file must be a path to an XML Schema or DTD") 41 42 p = subprocess.Popen( 43 f"xmllint --noout --nonet {schema_part} {filename}", 44 shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 45 stdout, stderr = p.communicate() 46 47 if p.returncode == 127: 48 raise OSError( 49 "xmllint not found, so can not validate schema") 50 elif p.returncode < 0: 51 from astropy.utils.misc import signal_number_to_name 52 raise OSError( 53 "xmllint was terminated by signal '{}'".format( 54 signal_number_to_name(-p.returncode))) 55 56 return p.returncode, stdout, stderr 57