# -*- coding: utf-8 -*-
"""
SeisComp XML function used for both inventory and event module.
:author:
EOST (École et Observatoire des Sciences de la Terre)
:copyright:
The ObsPy Development Team (devs@obspy.org)
:license:
GNU Lesser General Public License, Version 3
(https://www.gnu.org/copyleft/lesser.html)
"""
import os
import re
from lxml import etree
from obspy.io.quakeml.core import _xml_doc_from_anything
# SCXML version for which an XSD file is available
SCHEMA_VERSION = ['0.6', '0.7', '0.8', '0.9', '0.10', '0.11', '0.12']
[docs]def _is_sc3ml(path_or_file_object):
"""
Simple function checking if the passed object contains a valid scxml file
according to the list of versions given in parameters. Returns True of
False.
The test is not exhaustive - it only checks the root tag but that should
be good enough for most real world use cases. If the schema is used to
test for a StationXML file, many real world files are false negatives as
they don't adhere to the standard.
:type path_or_file_object: str
:param path_or_file_object: File name or file like object.
:rtype: bool
:return: `True` if file is a SCXML file.
"""
if hasattr(path_or_file_object, "tell") and hasattr(path_or_file_object,
"seek"):
current_position = path_or_file_object.tell()
if isinstance(path_or_file_object, etree._Element):
xmldoc = path_or_file_object
else:
try:
xmldoc = _xml_doc_from_anything(path_or_file_object)
except ValueError:
return False
finally:
# Make sure to reset file pointer position.
try:
path_or_file_object.seek(current_position, 0)
except Exception:
pass
if hasattr(xmldoc, "getroot"):
root = xmldoc.getroot()
else:
root = xmldoc
match = re.match(
r'{http://geofon\.gfz-potsdam\.de/ns/seiscomp3-schema/([-+]?'
r'[0-9]*\.?[0-9]+)}', root.tag)
return match is not None
[docs]def validate(path_or_object, version=None, verbose=False):
"""
Check if the given file is a valid SCXML file.
:type path_or_object: str
:param path_or_object: File name or file like object. Can also be an etree
element.
:type version: str
:param version: Version of the SCXML schema to validate against.
:type verbose: bool
:param verbose: Print error log if True.
:rtype: bool
:return: `True` if SCXML file is valid.
"""
if hasattr(path_or_object, "tell") and hasattr(path_or_object, "seek"):
current_position = path_or_object.tell()
if isinstance(path_or_object, etree._Element):
xmldoc = path_or_object
else:
try:
xmldoc = _xml_doc_from_anything(path_or_object)
except ValueError:
return False
finally:
# Make sure to reset file pointer position.
try:
path_or_object.seek(current_position, 0)
except Exception:
pass
# Read version number from file
if version is None:
match = re.match(
r'{http://geofon\.gfz-potsdam\.de/ns/seiscomp3-schema/([-+]?'
r'[0-9]*\.?[0-9]+)}', xmldoc.tag)
try:
version = match.group(1)
except AttributeError:
raise ValueError("Not a SCXML compatible file or string.")
if version not in SCHEMA_VERSION:
raise ValueError('%s is not a supported version. Use one of these '
'versions: [%s].'
% (version, ', '.join(SCHEMA_VERSION)))
# Get the schema location.
xsd_filename = 'sc3ml_%s.xsd' % version
schema_location = os.path.join(os.path.dirname(__file__), 'data',
xsd_filename)
xmlschema = etree.XMLSchema(etree.parse(schema_location))
valid = xmlschema.validate(xmldoc)
# Pretty error printing if the validation fails.
if verbose and valid is not True:
print("Error validating SCXML file:")
for entry in xmlschema.error_log:
print("\t%s" % entry)
return valid