Skip to content

append_fragment falha com < literal no texto e proccess_special_content perde referências silenciosamente #101

Description

@Rossi-Luciano

Descrição do problema

Ao processar o arquivo bn-2025-1828.docx, a task get_labels falhou com o seguinte erro no Celery:

ERROR proccess_special_content: 'NoneType' object is not subscriptable

Task markup_doc.tasks.get_labels raised unexpected:
Error('StartTag: invalid element name, line 1, column 661')

  File "/app/markup_doc/xml.py", line 666, in get_xml
    append_fragment(node_p, d['value']['paragraph'])
  File "/app/markup_doc/labeling_utils.py", line 1088, in append_fragment
    wrapper = etree.XML(f"<_wrap_>{clean}</_wrap_>")
lxml.etree.Error: StartTag: invalid element name, line 1, column 661

O registro foi marcado como PROCESSED mas text_xml ficou NULL — o XML não foi gerado.


Bug 1 — append_fragment: < literal no texto quebra o parse XML

append_fragment (labeling_utils.py:1057) executa uma série de limpezas no fragmento de texto antes de parseá-lo como XML, incluindo remove_unpaired_tags. Contudo, remove_unpaired_tags só reconhece
sequências no formato <nome...> via regex:

r'<(/?)([a-zA-Z0-9]+)(?:\s[^>]*)?>'

Um < literal sem > correspondente — como em expressões do tipo a < b, < 50% ou <2x — não casa com esse padrão e passa intacto para o resultado. Em seguida, append_fragment detecta o < na string (linha
1083) e encaminha o fragmento para etree.XML(f"<wrap>{clean}</wrap>"), que falha porque < b, < 50% etc. não são nomes de tag XML válidos.

O & solto é escapado (linha 1072), mas o < literal não recebe tratamento equivalente.


Bug 2 — proccess_special_content: None não tratado causa perda silenciosa de referências

proccess_special_content (labeling_utils.py:1124) itera sobre menções a figuras, tabelas e equações no texto e chama search_special_id para localizar o ID do elemento correspondente no corpo do
documento. Quando o elemento não é encontrado, search_special_id retorna None, e a linha seguinte:

"reftype": dict_type.get(id[0].lower(), 'other')

lança TypeError: 'NoneType' object is not subscriptable. O bloco except Exception captura o erro, imprime no log e continua — a referência é descartada sem nenhum registro estruturado da falha.


Solução sugerida

Bug 1 — adicionar passo de escape em append_fragment logo após remove_unpaired_tags:

clean = re.sub(r'<(?![/a-zA-Z_])', '&lt;', clean)

Isso escapa < que não sejam início de tag válida (<letra, </letra, <_), preservando tags HTML legítimas como , .

Bug 2 — checar None antes de acessar id[0] em proccess_special_content e substituir o except genérico por tratamento explícito:

id = search_special_id(data_body, label)
if id is None:
    continue  # referência sem correspondência no corpo — ignorar sem crash
res.append({
    "label": label,
    "id": id,
    "reftype": dict_type.get(id[0].lower(), 'other')
})

Prioridade

Bug 1 é crítico — impede a geração do XML. Bug 2 é perda silenciosa de dados — referências a figuras/tabelas sem correspondência no corpo desaparecem sem aviso.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions