Reputation: 5
Trying to enforce some standards in our publishing, so that links to PDF files all open in a new window and get an icon after the link to visually identify the link as one that opens a pdf.
Our cms outputs via xslt so these templates are part of a much larger stylesheet.
Each of these templates work but when both are included in the style sheet, only one gets applied. (or presumably, they both get applied and one just overwrites the other)
How can I resolve it so that both templates apply, either by combining them into one template or changing something in how they match.
<xsl:template match="*/@href[ends-with(., '.pdf') and string-length() > 4]">
<xsl:copy-of select="." />
<xsl:attribute name="title">{[parent::a|@title]} - File is a PDF, opens in new window.</xsl:attribute>
<xsl:attribute name="target">_blank</xsl:attribute>
</xsl:template>
<xsl:template match="//a[@href[ends-with(., '.pdf') and string-length() > 4]]">
<xsl:copy-of select="." />
<span class="reader"> (PDF, <a href="https://get.adobe.com/reader/" target="_blank" title="Get Adobe Acrobat PDF Reader.-Link opens in new window."><img src="{{f:14069022}}" alt="Get Adobe Acrobat PDF Reader.-Link opens in new window." /></a>)</span>
</xsl:template>
Example:
<a href="https://myfile.pdf title="my file">my file</a>
should be transformed into
<a href="https://myfile.pdf title="my file - File is a PDF, opens in new window." target="_blank">my file </a><span>icon, etc...</span>
Upvotes: 0
Views: 51
Reputation: 167696
Don't make a deep copy as you do in
<xsl:template match="//a[@href[ends-with(., '.pdf') and string-length() > 4]]">
<xsl:copy-of select="." />
<span class="reader"> (PDF, <a href="https://get.adobe.com/reader/" target="_blank" title="Get Adobe Acrobat PDF Reader.-Link opens in new window."><img src="{{f:14069022}}" alt="Get Adobe Acrobat PDF Reader.-Link opens in new window." /></a>)</span>
</xsl:template>
instead make a shallow copy and apply-templates:
<xsl:template match="//a[@href[ends-with(., '.pdf') and string-length() > 4]]">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
<span class="reader"> (PDF, <a href="https://get.adobe.com/reader/" target="_blank" title="Get Adobe Acrobat PDF Reader.-Link opens in new window."><img src="{{f:14069022}}" alt="Get Adobe Acrobat PDF Reader.-Link opens in new window." /></a>)</span>
</xsl:template>
If you need the shallow-copy/apply-templates behaviour in general declare it separateley (i.e. in XSLT 3 as <xsl:mode on-no-match="shallow-copy"/>
or in XSLT 2 with a template
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
) and simply use next-match
:
<xsl:template match="//a[@href[ends-with(., '.pdf') and string-length() > 4]]">
<xsl:next-match/>
<span class="reader"> (PDF, <a href="https://get.adobe.com/reader/" target="_blank" title="Get Adobe Acrobat PDF Reader.-Link opens in new window."><img src="{{f:14069022}}" alt="Get Adobe Acrobat PDF Reader.-Link opens in new window." /></a>)</span>
</xsl:template>
In XSLT 1 you could declare
<xsl:template match="@* | node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
and use call it
<xsl:template match="//a[@href[ends-with(., '.pdf') and string-length() > 4]]">
<xsl:call-template name="identity"/>
<span class="reader"> (PDF, <a href="https://get.adobe.com/reader/" target="_blank" title="Get Adobe Acrobat PDF Reader.-Link opens in new window."><img src="{{f:14069022}}" alt="Get Adobe Acrobat PDF Reader.-Link opens in new window." /></a>)</span>
</xsl:template>
Upvotes: 1