Exportar atributos para CSV🔗

Problema. O mapa tem os dados, mas alguém quer uma planilha.

Solução. Um script Groovy que percorre o ramo e grava CSV.

Antes de começar

O que você vai aprender

  • Extrair os atributos de um ramo para uma planilha
  • Entender que permissões o script exige e por quê
  • Escapar corretamente os campos do CSV

Requisitos🔗

Em Preferências → Scripts, habilite executar scripts sem assinatura e escrever arquivos.

Versão simples🔗

// AtributosParaCsv.groovy
def chaves = ['responsável', 'prazo', 'custo', 'status']
def sep = ';'

def linhas = [(['nó'] + chaves).join(sep)]

node.branch.each { n ->
    if (n == node) return
    def campos = [n.plainText] + chaves.collect { n[it]?.toString() ?: '' }
    linhas << campos.collect { it.replace(sep, ',').replace('\n', ' ') }.join(sep)
}

def destino = new File(System.getProperty('user.home'), 'relatorio.csv')
destino.setText(linhas.join('\n'), 'UTF-8')
c.statusInfo = "${linhas.size() - 1} linhas em ${destino}"

Selecione o nó raiz do ramo e execute. O ponto e vírgula como separador é o que planilhas em português esperam por padrão.

Versão que descobre as chaves sozinha🔗

// AtributosParaCsvAuto.groovy
def sep = ';'
def nos = node.branch.findAll { it != node && it.attributes.names }

def chaves = nos.collectMany { it.attributes.names }.unique().sort()
if (!chaves) {
    ui.informationMessage('Nenhum atributo encontrado neste ramo.')
    return
}

def esc = { v -> (v ?: '').toString().replace(sep, ',').replace('\n', ' ') }
def linhas = [(['caminho'] + chaves).join(sep)]

nos.each { n ->
    def caminho = []
    def p = n
    while (p && p != node.map.root) { caminho.add(0, p.plainText); p = p.parent }
    linhas << ([esc(caminho.join(' > '))] + chaves.collect { esc(n[it]) }).join(sep)
}

def destino = new File(System.getProperty('user.home'), 'relatorio.csv')
destino.setText(linhas.join('\n'), 'UTF-8')
c.statusInfo = "${linhas.size() - 1} linhas, ${chaves.size()} colunas → ${destino}"

A coluna caminho preserva a hierarquia como Fase 1 > Infraestrutura > Servidores, o que salva a informação que a planilha plana perderia.

Respeitando o filtro🔗

Para exportar só o que o filtro ativo mostra, troque a coleta por:

def nos = node.branch.findAll { it != node && it.visible }

Assim você filtra o mapa, roda o script, e a planilha sai com exatamente o resultado da consulta.

Instalando no menu🔗

Grave o arquivo em:

~/.config/freeplane/1.11.x/scripts/AtributosParaCsv.groovy

Reinicie. Ele aparece em Ferramentas → Scripts. Atribua um atalho em Preferências → Atalhos.

Sem o Freeplane🔗

Se o objetivo é só extrair, um script Python sobre o XML dispensa abrir o programa:

import csv, xml.etree.ElementTree as ET

raiz = ET.parse('mapa.mm').getroot()
linhas = []
for no in raiz.iter('node'):
    attrs = {a.get('NAME'): a.get('VALUE') for a in no.findall('attribute')}
    if attrs:
        linhas.append({'no': no.get('TEXT', ''), **attrs})

chaves = sorted({k for l in linhas for k in l})
with open('relatorio.csv', 'w', newline='', encoding='utf-8') as f:
    w = csv.DictWriter(f, fieldnames=chaves, delimiter=';')
    w.writeheader()
    w.writerows(linhas)

Isso roda em pipeline, em CI, e sobre mapas que você nem abriu.

Erros comuns

  • Habilitar escrita de arquivos e esquecer de reavaliar essa permissão depois
  • Gerar CSV sem escapar aspas e separadores, e quebrar a planilha na primeira célula com vírgula
  • Usar , como separador num locale que espera ; — a planilha abre tudo numa coluna
  • Exportar o ramo inteiro quando você queria só as folhas

Você aprendeu

  • O script percorre node.branch e grava um arquivo — daí a permissão de escrita
  • Escapar campos é obrigatório, não opcional
  • O separador depende do locale de quem vai abrir
  • Rodar num mapa de cópia é a precaução mínima ao automatizar

Perguntas para reflexão

  1. Que duas permissões esta receita exige, e o que cada uma libera?
  2. Por que escapar campos importa mesmo em dados que parecem simples?
  3. Como você limitaria a exportação apenas às folhas do ramo?
  4. Que precaução se toma antes de rodar um script sobre um mapa de trabalho?

Artigos relacionados

Referências🔗

  1. Freeplane — Scripting: atributos
  2. Freeplane — Export using XSLT
  3. Freeplane — Batch jobs