Di seguito è riportata una funzione che svolge il lavoro essenziale: restituisce un elenco JSON di titoli trovati, ciascuno con il relativo livello e testo.
Questo elemento JSON può inoltre essere utilizzato per generare la struttura HTML necessaria o qualsiasi altra cosa.
Schematicamente funziona in questo modo:
- ottenere il file Markdown come una stringa, e normalizzare line-breaks a solo
\n
(questo è importante per il passo # 3 di seguito)
- Applicare una semplice espressione regolare
/^(?:=|-|#).*$/m
con PREG_OFFSET_CAPTURE
: così partite tutte le linee che sia:
- sono i "underliners" di
<h1>
(quando "=") o <h2>
(quando "-") titoli
- sono titoli da soli (che inizia con "#")
- Iterate le righe abbinate:
- per "underliners", guarda il file di origine per la linea precedente, che si trova come la stringa tra la offset della linea corrente e interruzione di riga precedente; quindi ottenere livello dal tipo underliner e il testo dalla riga precedente
- altrimenti si procurano livello e testo dalla riga corrente stessa
Ecco la funzione:
function markdown_toc($file_path) {
$file = file_get_contents($file_path);
// ensure using only "\n" as line-break
$source = str_replace(["\r\n", "\r"], "\n", $file);
// look for markdown TOC items
preg_match_all(
'/^(?:=|-|#).*$/m',
$source,
$matches,
PREG_PATTERN_ORDER | PREG_OFFSET_CAPTURE
);
// preprocess: iterate matched lines to create an array of items
// where each item is an array(level, text)
$file_size = strlen($source);
foreach ($matches[0] as $item) {
$found_mark = substr($item[0], 0, 1);
if ($found_mark == '#') {
// text is the found item
$item_text = $item[0];
$item_level = strrpos($item_text, '#') + 1;
$item_text = substr($item_text, $item_level);
} else {
// text is the previous line (empty if <hr>)
$item_offset = $item[1];
$prev_line_offset = strrpos($source, "\n", -($file_size - $item_offset + 2));
$item_text =
substr($source, $prev_line_offset, $item_offset - $prev_line_offset - 1);
$item_text = trim($item_text);
$item_level = $found_mark == '=' ? 1 : 2;
}
if (!trim($item_text) OR strpos($item_text, '|') !== FALSE) {
// item is an horizontal separator or a table header, don't mind
continue;
}
$raw_toc[] = ['level' => $item_level, 'text' => trim($item_text)];
}
// create a JSON list (the easiest way to generate HTML structure is using JS)
return json_encode($raw_toc);
}
qui è il risultato che restituisce dal home page of the link you provided:
[
{"level":1,"text":"Welcome to StackEdit!"},
{"level":2,"text":"Documents"},
{"level":4,"text":"<\/i> Create a document"},
{"level":4,"text":"<\/i> Switch to another document"},
{"level":4,"text":"<\/i> Rename a document"},
{"level":4,"text":"<\/i> Delete a document"},
{"level":4,"text":"<\/i> Export a document"},
{"level":2,"text":"Synchronization"},
{"level":4,"text":"<\/i> Open a document"},
{"level":4,"text":"<\/i> Save a document"},
{"level":4,"text":"<\/i> Synchronize a document"},
{"level":4,"text":"<\/i> Manage document synchronization"},
{"level":2,"text":"Publication"},
{"level":4,"text":"<\/i> Publish a document"},
{"level":2,"text":"- Markdown, to publish the Markdown text on a website that can interpret it (**GitHub** for instance),"},
{"level":2,"text":"- HTML, to publish the document converted into HTML (on a blog for example),"},
{"level":4,"text":"<\/i> Update a publication"},
{"level":4,"text":"<\/i> Manage document publication"},
{"level":2,"text":"Markdown Extra"},
{"level":3,"text":"Tables"},
{"level":3,"text":"Definition Lists"},
{"level":3,"text":"Fenced code blocks"},
{"level":3,"text":"Footnotes"},
{"level":3,"text":"SmartyPants"},
{"level":3,"text":"Table of contents"},
{"level":3,"text":"MathJax"},
{"level":3,"text":"UML diagrams"},
{"level":3,"text":"Support StackEdit"}
]
Perché reinventare la ruota? http://parsedown.org/ – BenM
Sto usando parsedown ma non crea un sommario automaticamente –
'[TOC]' non è un markdown di azioni. – BenM