Xpath search for duplicate - xslt

I have the following xml:
<log>
<logentry revision="11956">
<author>avijendran</author>
<date>2013-05-20T10:25:19.678089Z</date>
<msg>
JIRA-1263 - did something
</msg>
</logentry>
<logentry revision="11956">
<author>avijendran</author>
<date>2013-05-20T10:25:19.678089Z</date>
<msg>
JIRA-1263 - did something 22 again
</msg>
</logentry>
</log>
I want to ignore any occurrence of the JIRA-1263 after the first one.
The xpath I am trying is (Which works if the duplicates nodes are following. But if you have duplicates else where(deep down), then it is ignored:
<xsl:variable name="uniqueList" select="//msg[not(normalize-space(substring-before(., '
')) = normalize-space(substring-before(following::msg, '
')))]" />

If you want to get each msg use //msg[starts-with(normalize-space(.), 'JIRA-1263')] to get output JIRA-1263 - did something and JIRA-1263 - did something 22 again.
And if you want to get any element with same codition use //*[starts-with(normalize-space(.), 'JIRA-1263')] which give same result as previous one.
At the end, if you want to get first msg with same condition use //logentry/msg[starts-with(normalize-space(.), 'JIRA-1263')][not(preceding::msg)] to get output JIRA-1263 - did something

You can define a key at the top level of your stylesheet that groups log entries by their first word:
<xsl:key name="logentryByCode" match="logentry"
use="substring-before(normalize-space(msg), ' ')" />
Now you need to select all logentry elements where either
the msg does not start JIRA-nnnn (where nnnn is a number) or
this entry is the first one whose msg starts with this word (i.e. the first occurrence of "JIRA-1234 - anything" for each ticket number)
(note that these two conditions need not be mutually exclusive):
<xsl:variable name="uniqueList" select="log/logentry[
(
not(
starts-with(normalize-space(msg), 'JIRA-') and
boolean(number(substring-before(substring(normalize-space(msg), 6), ' ')))
)
)
or
(
generate-id() = generate-id(key('logentryByCode',
substring-before(normalize-space(msg), ' '))[1])
)
]/msg" />
The boolean(number(...)) part checks whether a string of text can be parsed as a valid non-zero number (the text in this case being the part of the first word of the message that follows JIRA-), and the generate-id trick is a special case of the technique known as Muenchian grouping.
Equally, you could group the msg elements instead of the logentry elements, using match="msg" in the key definition and normalize-space(.) instead of normalize-space(msg).

And here another interpretation of what you try to do.
Find any first logentry which start with JIRA-XXXX.
If this it right try this:
log/logentry[
starts-with(normalize-space(msg), 'JIRA-') and
not
(
substring-before( normalize-space(msg), ' ')= substring-before( normalize-space(preceding::msg), ' ')
)]
This will find any logentry which starts with JIRA- but has not preceding one with the same substring before the first space (JIRA-XXXX) in your example.

Related

fetch value from the input message (this message doesn't have any space)

I have a input string like this,without any space
51=2MA011362X17=MG127AJ4015AG1A20=022=M35=U48=9CVRVC449
Here, number before = is key and after is value. From this string I have to fetch value of 17= (basically fetch the value MG127AJ4015AG1A)
I used <xsl:value-of select="substring-before(substring-after(.,'17='), '=')"/> which is giving me result: MG127AJ4015AG1A20, now I am stuck with removing these last 2 numeric values (20). totally confused how this an be achieved.
Final output string should be - MG127AJ4015AG1A
If it is the case that the number at the end will always be two digits, you put your current expression in a variable, and use substring to remove the last two characters, like so:
<xsl:variable name="match" select="substring-before(substring-after(.,'17='), '=')" />
<xsl:value-of select="substring($match, 1, string-length($match) - 2)"/>

XSLT white space in concat

I have the following code
<xsl:value-of select="concat(string($var15_cond_result_exists), string($var16_cond_result_exists))"/>
which is concatenating 2 strings. Examle John and Smith to JohnSmith.
What i want is a space between first name and last name.
I can do this with adding ,' ', between them in concat. Howered there is posibility that there is no first name or last name so I don't need the white space.
How can i solve this problem?
Is it possible to use some conditions or there is easier solution.
Wrap the concat in normalize-space() which will trim any excess spaces at the start or end
<xsl:value-of
select="normalize-space(concat(string($var15_cond_result_exists), ' ', string($var16_cond_result_exists)))"/>
Note, you may be able to drop the string function inside the concat. Try this too
<xsl:value-of
select="normalize-space(concat($var15_cond_result_exists, ' ', $var16_cond_result_exists))"/>
You don't say which XSLT version you are using. In XSLT 2.0 you can do
<xsl:value-of select="$var15_cond_result_exists, $var16_cond_result_exists"/>
which will automatically insert a space if and only if both items exist. The conversion to string is automatic in both 1.0 and 2.0.

xslt mapping to find substring between

I have my string as below
<Text>Pack:NA Lead:20 Dimension:235</Text>
And need to map
NA to outputfield1
20 to outputfield2
235 to outputfield3
How to do this correctly in xslt mapping where the values 'NA,20,235' could be different each time?
I could only see substring component which takes length as second parameter.
That leads requires several steps to achieve this.
Any better solution to just take the value between Lead: and Dimension for outputfield2?
To extract the Pack value, you can use:
<xsl:value-of select="substring-before(substring-after(Text, 'Pack:'), ' ')" />
To extract the Lead value, use:
<xsl:value-of select="substring-before(substring-after(Text, 'Lead:'), ' ')" />
To extract the Dimension:
<xsl:value-of select="substring-after(Text, 'Dimension:')" />

xslt 1.0 substring-after to ignore case

I have 2 xml nodes like this, for example:
<Model>GRAND MODUS</Model>
<QualifiedDescription>2008 58 Reg Renault Grand Modus 1.2 TCE Dynamique 5drMetallic Flame Red</QualifiedDescription>
I'm trying to use substring-after to split the QualifiedDescription after the Grand Modus like this:
<xsl:variable name="something"><xsl:value-of select='substring-after(QualifiedDescription, Model)' /></xsl:variable>
But obviously it's not working being of it being case sensitive. Is it possible to get substring-after to work case insensitive, but still return the output with case preserved EG.
1.2 TCE Dynamique 5drMetallic Flame Red
Thanks.
You could convert the two strings to the same case using translate in order to work out the character offset of the first within the second, then take a substring of the original QualifiedDescription from that position.
<xsl:variable name="uc" select="'ABCDEFGHIJKLMNOPQRSTUVWXYZ'" />
<xsl:variable name="lc" select="'abcdefghijklmnopqrstuvwxyz'" />
<xsl:variable name="substrStart" select="
string-length(substring-before(translate(QualifiedDescription, $uc, $lc),
translate(Model, $uc, $lc)))
+ string-length(Model)
+ 1" /><!-- +1 because string indexes in XPath are 1-based -->
<xsl:variable name="something"
select="substring(QualifiedDescription, $substrStart)" />
You'd need slightly more complex logic to take account of cases where the QualifiedDescription does not include the Model (since in this case both substring-before and substring-after return the empty string) but you get the idea.
You can do case insensitive if you uppercase all first and substring on uppercase:
substring-after(upper-case(QualifiedDescription), upper-case(Model))

how to parse the value from xml through xsl

<block4>
<tag>
<name>50K</name>
<value>/001/002/300060000120135670
CREDIT AGRICOLE ASSET MANAGEMENT</value>
</tag>
</block4>
I need to get output that looks like:
/001/002,/300060000120135670,CREDIT AGRICOLE ASSET MANAGEMENT
I have done like this in XSL, but I didn't get the output I wanted. Can anyone please give me some idea how I could get that output?
<xsl:for-each select ="block4/tag[name = '50K']">
<xsl:value-of select="
concat(
substring(value,1,8),
(concat(substring(value,9,'
'),',')),
substring-after(value,'
')
)
" />,<xsl:text/>
</xsl:for-each>
concat takes any number of arguments, no need to nest those calls. Besides, substring takes a beginning and an optional length, not a terminating character. Try something like this instead:
<xsl:for-each select ="block4/tag[name = '50K']">
<xsl:value-of select="
concat(
substring(value, 1, 8), ',',
substring(substring-before(value,'
'),9), ',',
substring-after(value,'
')
)
" />,<xsl:text/>
</xsl:for-each>
I've kept the final comma in, which is one of the many things you did not really specify.
Why not use XSLT 2.0 tokenize() function?
See Here