Skip to content

fix: não imprime afiliação duplicada não referenciada por nenhum contrib - #1331

Open
Rossi-Luciano wants to merge 3 commits into
scieloorg:masterfrom
Rossi-Luciano:fix/pdf-duplicate-unreferenced-affiliations
Open

fix: não imprime afiliação duplicada não referenciada por nenhum contrib#1331
Rossi-Luciano wants to merge 3 commits into
scieloorg:masterfrom
Rossi-Luciano:fix/pdf-duplicate-unreferenced-affiliations

Conversation

@Rossi-Luciano

@Rossi-Luciano Rossi-Luciano commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

O que esse PR faz?

Corrige a lista de afiliações de autores no PDF: alguns artigos imprimiam a mesma instituição duas vezes.

extract_contrib_data montava a lista de afiliações impressas com findall('.//aff'), pegando todo <aff> do documento. Alguns pacotes SciELO carregam uma cópia duplicada/órfã das afiliações que nenhum xref de contribuidor referencia. Confirmei em 7 dos 26 artigos do corpus real (27%), e o padrão de id da cópia duplicada varia bastante entre pacotes — não dá pra filtrar por convenção de nome:

Artigo ids "primários" ids duplicados (nunca referenciados)
a9.xml aff1, aff2 aff1e, aff2e
a11.xml aff01–aff04 aff0100–aff0400
a17.xml aff01 aff0100
a20.xml aff01 aff0100
a23.xml aff1 aff1001
a28.xml aff1, aff2 aff1s, aff2s
a14.xml aff1–aff12 aff13–aff24 (bloco inteiro duplicado)

Em todos os casos, porém, a cópia duplicada nunca é referenciada por nenhum xref[@ref-type="aff"] de contribuidor — só a cópia original é. A correção coleta os rid de todos os xref de afiliação de cada contribuidor (não só o primeiro) e restringe a lista impressa aos <aff> com id referenciado, em vez de listar todo <aff> do documento.

Onde a revisão poderia começar?

packtools/sps/formats/pdf/pipeline/xml.pyextract_contrib_data. aff_mapping (usado para resolver o sobrescrito numérico/label de cada autor) fica inalterado, continua olhando todo <aff>; só a lista final impressa (affiliations) foi filtrada. Mantém um fallback para imprimir tudo se nenhum <aff> for referenciado (defensivo, não visto no corpus real).

Como este poderia ser testado manualmente?

python -m packtools.sps.formats.pdf_generator \
  -i <artigo-com-afiliacao-duplicada>.xml \
  -l layout.docx \
  -o saida.pdf \
  --libreoffice-binary libreoffice

Conferir a lista de afiliações na página 1.

Algum cenário de contexto que queira dar?

Achado revisando visualmente o corpus de teste de 26 artigos reais (layout_examples_rafael/corpus/), inicialmente só em a9.xml. Investigando o padrão de id antes de implementar (por pedido explícito de sempre checar o corpus completo antes de generalizar um fix), achei mais 6 casos com convenções de id completamente diferentes — o pior, a14.xml, tinha 24 afiliações impressas (12 duplicadas), ocupando quase uma página inteira sozinha.

Screenshots

itemE_before_after

Quais são os tickets relevantes?

Nenhuma issue aberta associada; achado durante revisão visual do corpus de teste do gerador de PDF.

Referências

N/A


Segurança da informação (NSI.04)

Seção obrigatória. Marque as opções aplicáveis e justifique quando necessário. Referência: NSI.04 - Norma de Desenvolvimento Seguro.

Este PR manipula dados sensíveis ou pessoais (LGPD)?

  • Sim — descreva os controles de proteção aplicados (criptografia, mascaramento, anonimização, etc.):
  • Não

Este PR altera autenticação, autorização, controle de acesso ou gerenciamento de sessão?

  • Sim — descreva o que mudou e por quê:
  • Não

Este PR introduz, atualiza ou remove dependências de terceiros?

  • Sim — as novas dependências foram verificadas no SBOM/Trivy sem vulnerabilidades críticas/altas em aberto?
    • Verificado e aprovado
    • Pendente / vulnerabilidade aceita com justificativa:
  • Não

Este PR foi validado pelo pipeline de segurança (SonarQube / Trivy)?

  • Sim — link do job:
  • Não aplicável a este PR (justifique): mudança isolada de extração de dados a partir do próprio XML do artigo, sem I/O externo ou entrada não confiável

Este PR concatena, monta ou executa comandos SQL, HTML ou JavaScript a partir de entrada externa?

  • Sim — confirme que há sanitização/parametrização (prepared statements, escaping, etc.):
  • Não

Este PR expõe novos endpoints, telas ou serviços?

  • Sim — HTTPS obrigatório está garantido e o acesso segue o princípio de menor privilégio?
  • Não

Algum segredo, senha, chave ou token está sendo adicionado ao código-fonte?

  • Não, nenhum segredo foi commitado
  • Sim (bloquear merge e corrigir antes de prosseguir)

🤖 Generated with Claude Code

https://claude.ai/code/session_01X8r2LRJ3PGTT9vLaPtb373

extract_contrib_data pegava TODO <aff> do documento via
findall('.//aff') pra montar a lista impressa no PDF. Alguns pacotes
SciELO carregam uma copia duplicada/orfa das afiliacoes que nenhum
xref de contribuidor referencia (confirmado em 7 dos 26 artigos do
corpus real: 27%). O padrao de id da copia duplicada varia bastante
entre pacotes - aff1e/aff2e (a9.xml), aff0100/aff0200/... (a11.xml,
a17.xml, a20.xml), aff1s/aff2s (a28.xml), aff1001 (a23.xml), ou ate um
segundo bloco inteiro renumerado aff13-aff24 duplicando aff1-aff12
(a14.xml, o pior caso: 24 afiliacoes impressas, 12 duplicadas,
ocupando quase uma pagina inteira sozinha).

Nao da pra filtrar por padrao de id (variam demais), mas em todos os
casos a copia duplicada nunca e referenciada por nenhum xref de
contribuidor - so a copia original e. Coleta os rid de TODOS os
xref[ref-type=aff] de cada contrib (nao so o primeiro, ao contrario do
que a resolucao de rotulo em authors_names ja fazia) e restringe a
lista de afiliacoes impressas as que tem id referenciado. Mantem
fallback pra imprimir tudo se nenhum aff for referenciado (nao visto
no corpus real, so defensivo).

aff_mapping (usado pra resolver o rotulo sobrescrito de cada autor) fica
inalterado, continua olhando todo <aff> do documento - so a lista final
impressa foi filtrada.

Validado contra as 26 amostras do corpus: as 7 com o problema caem para
a contagem correta (a9: 4->2, a11: 8->4, a14: 24->12, a17: 2->1, a20:
2->1, a23: 2->1, a28: 4->2); as outras 19 nao mudam.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X8r2LRJ3PGTT9vLaPtb373

@pitangainnovare pitangainnovare left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Revendo os sete casos do corpus, percebi que a premissa da correção não corresponde à estrutura real dos XMLs. As afiliações indicadas como duplicadas/órfãs estão dentro de <sub-article> e são referenciadas pelos xref dos contribuidores desses subartigos. Portanto, a causa do problema é xml_tree.findall('.//aff') atravessar o limite do artigo principal.

Comparei a saída esperada usando apenas ./front/article-meta//aff com a saída atual do PR nos XMLs a1 a a30 e não encontrei nenhuma divergência. Limitar a busca ao <article-meta> principal, sozinho, corrige todos os casos do corpus.

Sugiro corrigir pelo escopo estrutural e reutilizar a mesma lista tanto no aff_mapping quanto na lista impressa:

article_meta = xml_tree.find('./front/article-meta')
affs = article_meta.findall('.//aff')

Assim, não seriam necessários referenced_aff_ids, o filtro por rid nem o fallback. O filtro atual produz o resultado esperado no corpus porque considera somente os xref do primeiro contrib-group, mas o fallback continua usando todos os <aff> do documento e pode voltar a incluir afiliações de <sub-article> quando o artigo principal não tiver referências.

Também sugiro ajustar o teste de regressão para representar a estrutura encontrada no corpus: afiliações do artigo principal em <front><article-meta> e as demais dentro de <sub-article>, em vez de representar a segunda afiliação como órfã no artigo principal.

@pitangainnovare pitangainnovare left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alguns ajustes foram solicitados (restringir busca ao campo article-meta) e por já estarem prontos em máquina local foram incorporados ao PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants