xmlxsltxslt-2.0xsl-fo

substring-after() function in XSLT seems to remove other formatting in the string


Say I have this text in an XML tag:

<p>!!! Something to note about this @v varname<p>

And I want to use XSL-FO code to format the text following three exclamation points (!!!) into a styled note while italicizing the text that follows the @v symbol. So, for example, the note would look something like this:

NOTE: Something to note about this varname

The code I have below works for the most part, except that the 'varname' isn't italicized in the output. I'm not that proficient in writing XSL-FO, but I'm guessing it has something to do with the substring-after() function that seems to only output plain text. However, I can't seem to find a workaround. What should I be doing differently?

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:fo="http://www.w3.org/1999/XSL/Format"
   xmlns:opentopic="http://www.idiominc.com/opentopic"
   xmlns:opentopic-index="http://www.idiominc.com/opentopic/index"
   xmlns:opentopic-func="http://www.idiominc.com/opentopic/exsl/function"
   xmlns:dita2xslfo="http://dita-ot.sourceforge.net/ns/200910/dita2xslfo"
   xmlns:dita-ot="http://dita-ot.sourceforge.net/ns/201007/dita-ot"
   xmlns:ot-placeholder="http://suite-sol.com/namespaces/ot-placeholder"
   exclude-result-prefixes="dita-ot ot-placeholder opentopic opentopic-index opentopic-func dita2xslfo xs"
   version="2.0">

<xsl:template match="text()[starts-with(., '!!!')]" priority="5" name="note">
      <fo:block xsl:use-attribute-sets="note__common note__note">
         <xsl:call-template name="commonattributes"/>
         <fo:external-graphic
            src="url({concat($artworkPrefix, 'Customization/OpenTopic/common/artwork/NOTE.png')})"
            content-width="scale-to-fit" width="23px"/>
         <fo:block xsl:use-attribute-sets="note__text__note">
            <fo:inline xsl:use-attribute-sets="note__label">NOTE: </fo:inline>
            <xsl:value-of select="substring-after(., '!!!')"/>
         </fo:block>
      </fo:block>
   </xsl:template>

<xsl:template match="text()[contains(., '@v')]" name="varname" priority="4">
      <xsl:analyze-string select="." regex="@v\s+([!-~]+)">
         <xsl:matching-substring>
            <fo:inline font-family="Roboto" font-style="italic">
               <xsl:value-of select="regex-group(1)"/>
            </fo:inline>
         </xsl:matching-substring>
         <xsl:non-matching-substring>
            <xsl:value-of select="."/>
         </xsl:non-matching-substring>
      </xsl:analyze-string>
   </xsl:template>

</xsl:stylesheet>

Solution

  • Both templates match the text node, but the first one has higher priority, so that is the one that is used. If you want both template rules to be applied, you need to arrange this by explicitly applying templates, for example change the inner fo:block of your first template rule to

    <fo:block xsl:use-attribute-sets="note__text__note">
       <fo:inline xsl:use-attribute-sets="note__label">NOTE: </fo:inline>
       <xsl:variable name="remainder" as="text()">
          <xsl:value-of select="substring-after(., '!!!')"/>
       <xsl:variable>
       <xsl:apply-templates select="$remainder"/>
    </fo:block>