Amy Higgins
Amy Higgins

Reputation: 31

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>

Upvotes: 0

Views: 113

Answers (2)

Michael Kay
Michael Kay

Reputation: 163595

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>

Upvotes: 0

Daniel Haley
Daniel Haley

Reputation: 52888

Using xsl:value-of is just going to give you a computed text node. No other processing will be done so your other template matching text() will never be matched.

Also if you use xsl:apply-templates the other text() template won't work because substring-after() returns an xs:string and not a text() node.

As an alternative, try using xsl:next-match and remove the !!! in the other template...

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:fo="http://www.w3.org/1999/XSL/Format" 
    version="2.0">

    <xsl:output indent="true"/>

    <xsl:template match="text()[starts-with(., '!!!')]" priority="5" name="note">
        <fo:block>
            <fo:external-graphic src="TBD.png" content-width="scale-to-fit" width="23px"/>
            <fo:block>
                <fo:inline>NOTE: </fo:inline>
                <xsl:next-match/>
            </fo:block>
        </fo:block>
    </xsl:template>

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

</xsl:stylesheet>

Fiddle: http://xsltfiddle.liberty-development.net/jyH7UDK/1

Upvotes: 0

Related Questions