I have an xml file which describes (among other things) elements with attribute values that describe fully qualified java class names. I am trying to write an XSLT transformation to modify the class names described in this file, such that (for example) ocurrances of com.example.MyClass
will become com.example.MockMyClass
.
Here's that example again in the context of a fragment of the original file:
<event type="node-enter">
<action name="MyActionName" class="com.example.MyClass">
<bodyTemplate>
templates/MyTemplate.vm
</bodyTemplate>
</action>
</event>
I want the result to be:
<event type="node-enter">
<action name="MyActionName" class="com.example.MockMyClass">
<bodyTemplate>
templates/MyTemplate.vm
</bodyTemplate>
</action>
</event>
I'm doing this transformation using the Java JAXP API, and had written a lovely XSLT 2.0 compliant regex routine to get the results I want, only to discover that Java 5 doesn't support XSLT 2.0, which is required for regex support.
So my question is, what is the best way to achieve this using the archaic JAXP XSLT 1.0 API? That is, without the use of regular expressions. I looked for similar problems, but the requirement for backreferencing regex groups seems to make this a tricky one. This question is a start, but I need to insert text, within a matching string, rather than just replacing.
For reference, here is my regex (XSLT 2.0) attempt:
<xsl:stylesheet version='1.0' xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
<xsl:template match='/'>
<xsl:analyze-string select='action/@class' regex='([A-Za-z0-9]+[$\.])+([A-Za-z0-9]+)'>
<xsl:matching-substring>
<xsl:value-of select='regex-group(1)'/>
<xsl:text>Mock</xsl:text>
<xsl:value-of select='regex-group(2)'/>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select='.'/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
</xsl:stylesheet>
The following seems long, however it uses ready parts (the
strRev
template is provided by FXSL and needs not be re-written). Also, nearly half of the code is the identity template and passing params to<xsl:call-template>
. This is much shorted in XSLT 2.0.When we have ready smaller parts/functions like the
strRev
template /reverse()
function, then this solution doesn't require writing long and error-prone home-made recursive code.The basic idea is that the last
'.'
character in a string is the first'.'
character in the reversed string.when this transformation is applied on the provided XML document:
the wanted, correct result is produced:
II. XSLT 2.0 solution:
Exactly the same algorithm, but in XSLT 2.0 is really short:
How about the following?
This takes a classname as an input parameter and adds "Mock" after the final ".". You can call it with, for example,
(I just gave it a quick try in Firefox, you might find you need to do some tidying up of white space.)