Source code for src.xmlChecks.daptLangCheck

# SPDX-FileCopyrightText: Copyright © 2026 BBC
#
# SPDX-License-Identifier: BSD-3-Clause

from src.validationLogging.validationCodes import ValidationCode
from src.validationLogging.validationLogger import ValidationLogger
from xml.etree.ElementTree import Element
from src.xmlUtils import make_qname, ns_xml
from .ttmlUtils import ns_ttml
from .xmlCheck import XmlCheck


xmllang_attr_tag = make_qname(
    namespace=ns_xml,
    name='lang')


[docs] class daptLangAudioNonMatchingCheck(XmlCheck): """ Checks that the computed xml:lang of every <audio> element matches its parent's computed xml:lang """ def __init__(self) -> None: super().__init__()
[docs] def run( self, input: Element, context: dict, validation_results: ValidationLogger) -> bool: valid = True tt_ns = \ context.get('root_ns', ns_ttml) content_el_tags = [ make_qname(namespace=tt_ns, name=el_name) for el_name in ['body', 'div', 'p', 'span', 'audio'] ] audio_el_tag = make_qname(namespace=tt_ns, name='audio') # iterate through the tt/body// to get the computed # xml:lang attribute for each <audio> element and its parent # and check they match each other. valid &= self.recursively_compute_xml_lang_and_check_audio( input=input, parent_computed_lang='', content_el_tags=content_el_tags, audio_el_tag=audio_el_tag, validation_results=validation_results ) if valid: validation_results.good( location='audio elements', message='xml:lang checked', code=ValidationCode.dapt_lang_audio ) return valid
[docs] def recursively_compute_xml_lang_and_check_audio( self, input: Element, parent_computed_lang: str, content_el_tags: list[str], audio_el_tag: str, validation_results: ValidationLogger, ) -> bool: valid = True this_computed_lang = input.get(xmllang_attr_tag, '') \ if xmllang_attr_tag in input.keys() \ else parent_computed_lang if input.tag == audio_el_tag and \ this_computed_lang != parent_computed_lang: valid = False validation_results.error( location='audio element xml:lang attribute', message='Computed value "{}" is not the same as parent ' 'element computed value "{}"' .format(this_computed_lang, parent_computed_lang), code=ValidationCode.dapt_lang_audio ) children = [el for el in input if el.tag in content_el_tags] for child in children: valid &= self.recursively_compute_xml_lang_and_check_audio( input=child, parent_computed_lang=this_computed_lang, content_el_tags=content_el_tags, audio_el_tag=audio_el_tag, validation_results=validation_results ) return valid
[docs] class nonEmptyLangRootCheck(XmlCheck): """ Checks xml:lang attribute is present and is not empty """ def __init__(self) -> None: super().__init__()
[docs] def run( self, input: Element, context: dict, validation_results: ValidationLogger) -> bool: valid = True if xmllang_attr_tag in input.keys(): xmllang_attr_val = input.get(xmllang_attr_tag, '') if xmllang_attr_val == '': valid = False validation_results.error( location='{} element'.format(input.tag), message='Empty xml:lang attribute value prohibited', code=ValidationCode.dapt_lang_root ) else: valid = False validation_results.error( location='{} element'.format(input.tag), message='Required xml:lang attribute is missing', code=ValidationCode.dapt_lang_root ) if valid: validation_results.good( location='{} element'.format(input.tag), message='xml:lang present and not empty', code=ValidationCode.dapt_lang_root ) return valid