"""A deliberately narrow authored PLS alias profile, not full PLS/XSD validation."""
import xml.etree.ElementTree as ET
import json
NS='http://www.w3.org/2005/01/pronunciation-lexicon';LANG='{http://www.w3.org/XML/1998/namespace}lang'
ET.register_namespace('',NS)
def build():
    root=ET.Element('{'+NS+'}lexicon',{'version':'1.0','alphabet':'ipa',LANG:'fa-IR'})
    for word,alias in [('Velu','وِلو'),('D8','دی هشت')]:
        entry=ET.SubElement(root,'{'+NS+'}lexeme');ET.SubElement(entry,'{'+NS+'}grapheme').text=word;ET.SubElement(entry,'{'+NS+'}alias').text=alias
    return ET.tostring(root,encoding='utf-8',xml_declaration=True)
def inspect(raw):
    if not isinstance(raw,bytes) or not 0<len(raw)<=4096:raise ValueError('UTF-8 bytes, 1..4096 bytes')
    text=raw.decode('utf-8')
    if '<!DOCTYPE' in text.upper() or '<!ENTITY' in text.upper():raise ValueError('DTD/entities unsupported')
    root=ET.fromstring(text)
    if root.tag!='{'+NS+'}lexicon' or root.attrib!={'version':'1.0','alphabet':'ipa',LANG:'fa-IR'}:raise ValueError('local root profile')
    if (root.text or '').strip() or not 1<=len(root)<=20:raise ValueError('entry count/root text')
    entries=[];seen=set()
    for e in root:
        if e.tag!='{'+NS+'}lexeme' or e.attrib or (e.text or '').strip() or (e.tail or '').strip():raise ValueError('local lexeme profile')
        if [c.tag for c in e]!=['{'+NS+'}grapheme','{'+NS+'}alias']:raise ValueError('one grapheme then one alias required by this local profile')
        for c in e:
            if c.attrib or len(c) or not (c.text or '').strip() or (c.tail or '').strip():raise ValueError('plain nonempty child text required')
        word,alias=[c.text for c in e]
        if word in seen:raise ValueError('duplicate grapheme unsupported by local profile')
        seen.add(word);entries.append({'grapheme':word,'alias':alias})
    return entries
if __name__=='__main__':
    raw=build();entries=inspect(raw);assert entries==[{'grapheme':'Velu','alias':'وِلو'},{'grapheme':'D8','alias':'دی هشت'}]
    bad=[raw.replace(NS.encode(),b'urn:wrong'),raw.replace(b'fa-IR',b'en-US'),raw.replace(b'<grapheme>Velu</grapheme>',b''),raw.replace(b'<alias>',b'<phoneme>').replace(b'</alias>',b'</phoneme>'),b'<!DOCTYPE lexicon>'+raw,raw.replace('وِلو'.encode(),b' ')]
    for x in bad:
        try:inspect(x)
        except (ValueError,ET.ParseError):pass
        else:raise AssertionError('unsupported profile accepted')
    print(json.dumps({'entries':entries,'unsupported_cases_rejected':6,'XSD_validation':False,'full_PLS_validation':False,'audio_generated_or_listened':False,'engine_compatibility_tested':False},ensure_ascii=False,indent=2))
