
Concatenating Files for a Book
During my documentation project, I encountered the need to concatenate multiple Markdown documents into a single comprehensive document. I initially used a FileMaker Script to achieve this and subsequently ran the Markdown conversion to generate a complete HTML file with all the pages combined.
However, I faced some formatting issues during this process. Notably, numerous extra blank lines were being inserted into the text. Upon investigation, I realized that this was due to formatting applied by FileMaker to files with alternate line breaks. FileMaker uses CR (Carriage Return), whereas most pure text editors on Mac use LF (Line Feed). The issue likely arose because LF was converted to CRLF, and when written back, the Markdown converter interpreted the extra CR as blank lines.
To address this, I decided to create an ACF function to handle the concatenation process. This approach provided me with full control over the text within the documents. Additionally, I started by creating a Table of Contents (TOC) section with all the document titles, making it easier to navigate through this lengthy document.
The implementation of this approach was an immediate success. You can view the resulting concatenated document for this manual by clicking the following link: ACF_book.html
Here's a snippet of the ACF function responsible for this operation:
function create_ebook_html ( string book, string html_path, string bookname )
if ( bookname == "") then
throw "Missing bookname";
end if
string s, d;
string sql = format ( "SELECT cat.Sorting, doc.Sorting, doc.DocumentRelPath, doc.Title, cat.Category,
doc.cCategoryText,doc.PrimaryKey FROM ACF_Documents as doc
LEFT OUTER JOIN ACF_Categories as cat ON cat.PrimaryKey = doc.Category_UUID
LEFT OUTER JOIN Books as bk ON bk.PrimaryKey = doc.BookUUID
WHERE bk.Title='%s'
ORDER BY cat.Sorting, doc.Sorting, doc.Title", book);
string sf = ACF_Documents::DocumentRelPath; // Any document in the book. We only want the directory path.
string sourcePath = regex_replace("^(.+)/(.+\..+)$", sf, "\1")+"/";
// print sourcePath;
// return "Debug";
int rs = SQL_Query (sql);
int rc = SQL_getRowCount ( rs );
int md = open ( sourcePath+bookname+".md", "w");
write (md, "# "+Books::HeadingTitle+"\n\n");
int i,x;
array string row;
string curcat = "---", cont, anchor;
// TOC ( Table of Content )
write ( md, "## TABLE OF CONTENT\n\n");
for ( i=1, rc )
row = SQL_GetRow ( rs, i-1);
if ( row[6] != curcat ) then // Category headings in the toc.
write ( md, "\n###"+row[6]+"\n\n");
curcat = row[6];
end if
write ( md, "- [" +row[4]+"](#"+row[7]+ ")\n");
end for
write ( md, "---\n");
// The Main content - from all the MD files.
curcat = "---";
for ( i=1, rc )
row = SQL_GetRow ( rs, i-1);
if ( row[6] != curcat ) then
write ( md, "# "+ row[6]+"\n\n");
curcat = row[6];
end if
x = open (row[3], "r" );
cont = read ( x );
anchor = '<a id="'+row[7]+'"></a>';
write ( md, anchor+"\n"+cont+"\n\n");
close ( x );
write ( md, "<br><hr>[Back to top](#toc_0)\n\n");
end for
close ( md ) ;
sql_close ( rs );
res = EasyConvertMarkdown (sourcePath+bookname+".md", html_path+"/"+bookname+".html", html_path,
ACF_Documents::Style,ACF_Documents::Codestyle, Preferences::ImageTagRemoveText);
// Copy the neccessary files to a new folder.
// Copy file also copies directories.
destfolder = html_path + "/" + bookname + "/";
if ( directory_exists (html_path + "/" + bookname)) then
res = delete_directory ( html_path + "/" + bookname );
end if
res = create_directory (html_path + "/" + bookname ) ;
res = copy_file ( html_path+"/"+bookname+".html", destfolder+"index.html");
res = copy_file ( html_path+"/images", destfolder+"images");
res = copy_file ( html_path+"/css", destfolder+"css");
res = copy_file ( html_path+"/include", destfolder+"include");
res = create_directory ( html_path+ "/" +bookname + "/themes/markdown" );
res = copy_file ( html_path+"/themes/markdown/" + ACF_Documents::Style, destfolder+"themes/markdown/"+ ACF_Documents::Style);
s= html_path+"/themes/code/style/" + ACF_Documents::Codestyle;
d= destfolder+"themes/code/style/"+ ACF_Documents::Codestyle;
res = create_directory ( destfolder+"themes/code/style");
res = copy_file ( s, d);
s= html_path+"/themes/code/style/" + ACF_Documents::Style;
d= destfolder+"themes/code/style/"+ ACF_Documents::Style;
res = copy_file ( s, d);
$$BookHTML = html_path+"/"+bookname+"/"+"index.html";
end
- The function above does much more than the old FileMaker script below does. It is now a more complete solution to combine many separate MarkDown documents into One, and then create a HTML book from it.
- The "EasyConvertMarkdown" function, employed in the script above, is a modified version of the "ConvertMarkdown" function showcased in the "Markdown functions" example. It also utilizes a distinct script known as "EasyPostProcessing." Notably, it differs from the original function in that it doesn't create a left sidebar Table of Contents (TOC). Instead, it allready has the TOC at the top of the document. This adjustment makes it particularly well-suited for printing or generating PDFs. If you're interested in obtaining a copy of this function, please feel free to send me a message. And on the Script for the button:
- The ACF function also provides interlinking from the TOC to the various articles in the book. It also provides link for "go to top" at end of each article.
- The ACF function also copies the neccessary files to a new folder, including the selected theme files in the themes directory, the CSS styles and the images folder, and of course the new html file we have produced. This is convenient if one wants to have a HTML manual included on the install media, not having all the html files on the media.
References:
- Markdown Function, Example