Include document metadata in html head

Hello,

I have a project that has several individual sections that each need to be compiled independently. That’s simple; just specify the compile group and compile individually.

The problem I’m facing is that I have metadata associated with the containing folder of each section, such as the synopsis, or a custom-metadata specifying that section’s version. I’ve seen several other threads that discuss how that metadata isn’t available to the project, and when I’m generating plain text, I can get around that by creating my output file’s header in the “section layout” for the top directory of a section.

But now I have to generate html, and I can’t for the life of me figure out how generate it where that metadata is made available in the section of the resulting html file.

I’ve tried many things, and the closest I’ve come is using multimarkdown (I’m willing to convert my entire project to MMD if that’s what it takes). If I included the “Meta-Data” file with each section, I could just store the section meta-data in that, but that’s not really a great solution, because it would involve copying that Meta-Data file for each section, and updating each file if my requirements change. Not very maintainable.

The other thing I’m willing to try is this xslt template file. My idea is to include the document metadata in elements in the section layout, then use xslt to move it into the header with all the other metadata. I’d be okay with this, but I can’t figure out how to get xslt templates to work. The manual says:

But how? It doesn’t say what the meta-data key needs to be. Or if I include the template right there inside the meta-data value, or if I specify a file that contains the template. All my guesses have failed, and I can’t find any examples online.

I’ve also thought of somehow scrapping the generated html header entirely, and then handcrafting it myself, but I can’t figure out how to do that either (not without manually deleting the header after the file has been generated.)

I would be thankful for any advice for how I could accomplish what I’m trying to do. I’m close to giving up.

Thank you,
Flibbles

For anyone interested, I came up with a solution to this problem (although it’s not stellar). It uses xslt.

  1. I’m compiling with: “Multimarkdown -> Web Page (.html)”.
  2. I add my document-dependent metadata in the “prefix” part of my “section layout” for directories that I use as compile groups. For instance, I might have:
<title><$ParentTitle>: <$CompileGroup></title>
<meta name="part" content="<$position> of 5"/>
<meta name="alt-authors" content="<$custom:contributors>"/>
<meta name="summary" content="<$synopsis>"/>

This code will show up at the top of my generated HTML, however, it’s inside the element. Not in the with all the Project-wide metadata.
Note: Make sure Scrivener doesn’t turn those quotes into smart quotes, or MMD will escape all those elements, and they’ll be useless.

  1. I specify in the compatibility section to “Use XSLT post-processing”
  2. I specify an xslt file in the “Meta-Data” section of the compile wizard. The key is “HTML XSLT” (took me a while to figure that out; it’s not documented anywhere). The value will be, in my case, “html.xslt”, but you can make it anything (and you probably should make it more specific).
  3. Make html.xslt. This file will go in your “/Applications/Scrivener.app/Contents/Resources/MultiMarkdown/XSLT” directory or wherever you have Multimarkdown installed. This is the reason my solution is kinda janky. You have to add template files in strange places completely divorced from your project…
  4. Anyway, this file will contain xslt that takes care of moving all those and elements into where they belong. My xslt file looks like this:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="html" indent="yes"/>
  <!-- Without this, the <head> element will look a little wonky given all the
       surgery we're putting it through. -->
  <xsl:strip-space elements="head"/>
  
  <xsl:template match="head">
    <head>
      <!-- This extravegant xpath includes everything that was already in the
           head with a few exceptions:
           1. no <meta name="htmlxlst" ...> // not needed in final product
           2. no <title ...> // In my case, my title is document specific, so
              I can't use the project created one. -->
      <xsl:copy-of select="@* | node()[not(contains(@name, 'htmlxslt') or name()='title')]" />
      
      <!-- This copies the title from the document metadata. -->
      <xsl:for-each select="//body/descendant::title">
        <title>
          <xsl:copy-of select="@*" />
          <xsl:apply-templates />
        </title>
      </xsl:for-each>
      
      <!-- This copies up all meta elements from the body. -->
      <xsl:for-each select="//body/descendant::meta">
        <meta>
          <xsl:copy-of select="@*" />
          <xsl:apply-templates />
        </meta>
      </xsl:for-each>
    </head>
  </xsl:template>

  <!-- This overrides the identity template and excises the meta elements
       in the body, including their containing tag-->
  <xsl:template match="body/*[meta] | body/*[title]" />

  <!-- Identity Template. For all unspecified nodes, they're copied as-is.
       Their children are recursed into. -->
  <xsl:template match="/ | @* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()" />
    </xsl:copy>
  </xsl:template>
</xsl:stylesheet>

That should be it. It works for me anyway. It’s obviously not a perfect solution, and I’m pretty sure all the manual xslt stuff is deprecated, but there you go. I hope this helps somebody else out there with this incredibly esoteric problem.

Your welcome,
-Flibbles