XSL - Removing text blocks from string - xslt

I have one question regarding xslt. In my input I have strings like:
<dxrCardNumber2>[EBERG615] [104699] [104913]</dxrCardNumber2>
and I have to remove all brackets and values between the brackets, if they contains a letter.
The result should be:
=> <dxrCardNumber2>104699 104913</dxrCardNumber2>
The position of the data I have to remove is random. I tried it with tokenize and then I can filter the not relevant entries out. But at teh end I have the problem to combine all entries again in one string.

Assuming you can use XSLT 2.0 or higher, you could do:
<xsl:template match="dxrCardNumber2">
<xsl:copy>
<xsl:value-of select="tokenize(translate(., '[]', ''), ' ')[matches(., '^\d+$')]"/>
</xsl:copy>
</xsl:template>

<xsl:template match="dxrCardNumber2">
<xsl:analyze-string select="." regex="\[([A-Z0-9]+)\]\s+\[([0-9]+)\]\s+\[([0-9]+)\]" flags="i">
<xsl:matching-substring>
<dxrCardNumber2><xsl:value-of select="concat(regex-group(2),' ')"/>
<xsl:value-of select="regex-group(3)"/></dxrCardNumber2>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>

Related

How to convert lowercase to uppercase without any change inner elements using XSL

INPUT:
<title>This is <b>sample</b> ack <i>file</i>: good</title>
NEED OUTPUT:
<title>This is <b>sample</b> ack <i>file</i>: Good</title>
Just convert the letter 'g' lowercase to uppercase without any change using XSL.
Thanks in Advance.
In XSLT 2.0 you can do:
<xsl:template match="title/text()">
<xsl:analyze-string select="." regex=":\s*.">
<xsl:matching-substring>
<xsl:value-of select="upper-case(.)"/>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
Demo: https://xsltfiddle.liberty-development.net/gVAkJ5g/1

Select first space in a String

I want to select first space of a string in a text.
Input :
<p>Text 1<italic>should</italic> Text 2.</p>
There is a space after </italic>. I want to select only that space and replace a <s> for that space. How can i do that.
Tried code :
<xsl:template match="p/text()[2]">
<s/>
</xsl:template>
Expected results :
<p type="body">Text 1
<style type="underline">should</style><s/>have surgery.</p>
This tried code not works properly. I am using xslt 2.0
In XSLT 2.0, you could do:
<xsl:template match="p/text()[preceding-sibling::*[1][self::italic]]">
<xsl:analyze-string select="." regex="^\s" >
<xsl:matching-substring>
<s/>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="." />
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
This matches the text node immediately following an italic element, and checks if the first character is a space. If it is, it will be replaced by an empty s element.
Alternatively, you could restrict the match pattern itself to include only nodes that start with a space:
<xsl:template match="p/text()[preceding-sibling::*[1][self::italic]][starts-with(., ' ')]">
<s/>
<xsl:value-of select="substring(., 2)" />
</xsl:template>

XSLT replace char with an element

I'm trying to replace a single char with an element (containing more elements).
Using XSL 2.0.
Example:
<element1>
<element2>some text and the char - I want to replace </element2>
...
</element1>
The - (dash) should now be replaced with a new element:
<element1>
<element2>some text and the char <newElement/> I want to replace </element2>
...
</element1>
I tried already:
<xsl:template match="element1">
<xsl:analyze-string select="." regex="-">
<xsl:matching-substring>
<newElement/>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
But this removed all the other elements inbetween (because only strings are "returned").
And with the function replace() you only can insert strings (no < possible).
Any further ideas?
Your template matches an element(), but replaces text(). If you match text() and replace text() instead while copying the rest, it will work as expected:
<!-- modified identity template matching no text() nodes -->
<xsl:template match="element() | comment() | processing-instruction()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*" />
</xsl:copy>
</xsl:template>
<xsl:template match="text()">
<xsl:analyze-string select="." regex="-">
<xsl:matching-substring>
<newElement/>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:copy-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
Two corrections are needed:
Your template should match element2, not element1.
At the beginning and end of your tempate you should add
opening / closing tag for element2 (something like in
the identity template).
So your template should look like this:
<xsl:template match="element2">
<element2>
<xsl:analyze-string select="." regex="-">
<xsl:matching-substring>
<newElement/>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</element2>
</xsl:template>
Of course, your script should include also the identity template.

match cases based on range with alphabets

I've the below XML.
<para>39B</para>
<para>76</para>
Here I'm able to match the exact number, but the problem came up when there is a range mentioned like below.
if the range 39A-39P
print case1
if the range 72-85
print case2
The code i tried
<xsl:template match="text()">
<xsl:analyze-string select="." regex="([\w]+)">
<xsl:matching-substring>
<xsl:variable name="regex1">
<xsl:choose>
<xsl:when test="contains(regex-group(1), '^39[A-P]$')">
<xsl:text>CAse 1</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>Case 2</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:value-of select = "$regex1"/>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
please let me know how can i solve this.
Thanks
With XSLT 2.0 you can use regular expressions so for the alphanumeric case you can use
<xsl:template match="para[matches(., '^39[A-P]$')]">case1</xsl:template>
and a simple number comparison for the second case
<xsl:template match="para[. ge 72 and . le 85]">case2</xsl:template>

convert into camel case based on the string position

I've the below XML.
<title>1. IN AGENTS IN GENERAL</title>
Here i'm trying to convert this into camel case, and if there are a set of words, if they occur they have to be changed into lower case. But the condition is, if these words come in starting, they have to be changed into camel case, else lower case.
And my XSL is
<xsl:template match="title">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="title/page"/>
<xsl:param name="Conjunction">^(of|to|and|the|for|on|or|an|as|by|of|it|between|with|in|into|on|onto|here|a)$</xsl:param>
<xsl:template match="title/text()">
<xsl:analyze-string select="." regex="(\w)(\w*)">
<xsl:matching-substring>
<xsl:value-of
select="if (matches(., $Conjunction, 'i'))
then lower-case(.)
else concat(upper-case(regex-group(1)), lower-case(regex-group(2)))"/>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:template>
and as per the input the Expected output should be
1. In Agents in General
but what is get is
1. in Agents in General
here is the working demo. DEmo
please let me know how can i get this done.
Thanks
If you can assume a full-stop delimits each sentence, and you want the first word of each sentence to be capitalised regardless, you could tokenize the text by full-stop...
<xsl:for-each select="tokenize(., '\.')">
You then apply your regular expression on each part separately, but include a check on the position in the matching-substring so that it doesn't convert the first match to lower case.
Try this template
<xsl:template match="title/text()">
<xsl:for-each select="tokenize(., '\.')">
<xsl:if test="position() > 1">.</xsl:if>
<xsl:analyze-string select="." regex="(\w)(\w*)">
<xsl:matching-substring>
<xsl:value-of
select="if (matches(., $Conjunction, 'i') and position() > 2)
then lower-case(.)
else concat(upper-case(regex-group(1)), lower-case(regex-group(2)))"/>
</xsl:matching-substring>
<xsl:non-matching-substring>
<xsl:value-of select="."/>
</xsl:non-matching-substring>
</xsl:analyze-string>
</xsl:for-each>
</xsl:template>
In your current code, try changing:
<xsl:value-of select="if (matches(., $Conjunction, 'i'))
to
<xsl:value-of select="if (matches(., $Conjunction, 'i') and position() != 3)