Spaces:
Sleeping
Sleeping
File size: 2,116 Bytes
37eaffd 9be5ad7 37eaffd 9be5ad7 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | from __future__ import annotations
import difflib
import re
from ..models.schema import TEISchema
from ..models.spans import ResolvedSpan
def validate_spans(
spans: list[ResolvedSpan],
schema: TEISchema,
source: str,
) -> list[ResolvedSpan]:
"""
Filter out spans that fail schema validation.
Rejected when:
- element is not in the schema
- an attribute name is not listed for that element
- an attribute value is not in the element's allowed_values (when constrained)
- span bounds are out of range
"""
valid: list[ResolvedSpan] = []
for span in spans:
# Bounds sanity check
if span.start < 0 or span.end > len(source) or span.start >= span.end:
continue
elem = schema.get(span.element)
if elem is None:
continue # element not in schema
allowed_names = {a.name for a in elem.attributes}
attr_ok = True
for attr_name, attr_value in span.attrs.items():
if attr_name not in allowed_names:
attr_ok = False
break
attr_def = next((a for a in elem.attributes if a.name == attr_name), None)
if attr_def and attr_def.allowed_values is not None:
if attr_value not in attr_def.allowed_values:
attr_ok = False
break
if not attr_ok:
continue
valid.append(span)
return valid
def validate_output(xml: str, source: str) -> None:
"""Raise ValueError if xml text content differs from source (tags stripped, whitespace normalised)."""
def _norm(t: str) -> str:
return re.sub(r'\s+', ' ', t).strip()
got = _norm(re.sub(r'<[^>]+>', '', xml))
expected = _norm(source)
if got != expected:
diff = '\n'.join(
difflib.unified_diff(
expected.split(), got.split(),
fromfile='source', tofile='injected',
)
)
raise ValueError(
f"inject_xml text content mismatch — annotated output differs from source.\n{diff}"
)
|