Don't match on an element and then put xsl:choose
inside of the template to distinguish further, instead simply write templates for the different elements or elements with certain attribute values.
And if you want to use analyze-string
then do that in a template of a text
node, not in the template of an element containing mixed content:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="assessmentItem">
<!--SNIP-->
<xsl:apply-templates select="stemArea/stem"/>
<!--SNIP-->
</xsl:template>
<xsl:template match="stem[. = '' and @type!='art'] | stem[. = ' ' and @type != 'art']"/>
<xsl:template match="stem[@style='box' or @style='boxL']">
<p><span label="Tag_7"><xsl:apply-templates/></span></p>
</xsl:template>
<xsl:template match="stem[.//text()[matches(., '\$\{.+\}')]]">
<p>
<xsl:apply-templates/>
</p>
</xsl:template>
<xsl:template match="stem//text()[matches(., '\$\{.+\}')]">
<xsl:analyze-string regex="(\$\{{)(##.+[eqn|art]\d+)([^a-zA-Z0-9]?.*\}})" select=".">
<xsl:matching-substring>
<img alt="{regex-group(2)}" height="10" id="{regex-group(2)}" label="" longdesc="normal" src="{regex-group(2)}" width="10"/>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
</xsl:stylesheet>
With that stylesheet, when applied to the input
<stem>What is the value of <I>f</I>(<I>x</I>) when ${##A112800eqn01:3}</stem>
I get the result
<p>What is the value of <I>f</I>(<I>x</I>) when <img alt="##A112800eqn01" height="10" id="##A112800eqn01" label="" longdesc="normal" src="##A112800eqn01" width="10"/></p>
The above is meant as a suggestion on how to approach your stylesheet design, it is likely not a complete solution as I don't have much input samples to test and don't know the input XML and text format you are trying to process.
I would probably implement
<xsl:template match="stem[. = '' and @type!='art'] | stem[. = ' ' and @type != 'art']"/>
as
<xsl:template match="stem[not(normalize-space()) and @type!='art']"/>
instead but I have mainly tried to show how to structure the stylesheet with templates and how to match on a descendant text node of stem
to ensure the analyze-string
does not swallow elements nodes inside stem
.
As for your edited input requirement, I have changed the regular expression to use non-greedy matching (.*?
), so with the code below you should be able to match on several patterns in a stem
to create several img
elements:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="assessmentItem">
<!--SNIP-->
<xsl:apply-templates select="stemArea/stem"/>
<!--SNIP-->
</xsl:template>
<xsl:template match="stem[. = '' and @type!='art'] | stem[. = ' ' and @type != 'art']"/>
<xsl:template match="stem[@style='box' or @style='boxL']">
<p><span label="Tag_7"><xsl:apply-templates/></span></p>
</xsl:template>
<xsl:template match="stem[.//text()[matches(., '\$\{.+?\}')]]">
<p>
<xsl:apply-templates/>
</p>
</xsl:template>
<xsl:template match="stem//text()[matches(., '\$\{.+?\}')]">
<xsl:analyze-string regex="(\$\{{)(##.+?[eqn|art]\d+)([^a-zA-Z0-9]?.*?\}})" select=".">
<xsl:matching-substring>
<img alt="{regex-group(2)}" height="10" id="{regex-group(2)}" label="" longdesc="normal" src="{regex-group(2)}" width="10"/>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
</xsl:stylesheet>