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

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)"/>

Related

string length of a xml structure

I have a large XSD I process using several templates to get a new XSD.
In one of the last steps I would like to determine the length of the xml (actually an XSD) that was captured in a variable xsdresult.
Using the string-length function I see a strange length not matching the variable length of xsdresult. Size of string/xsd is over 52000 chars but I see Length: 9862 What am I doing wrong?
<!-- Catch output in variable -->
<xsl:variable name="xsdresult">
<xsl:call-template name="start"/>
</xsl:variable>
<xsl:template name="start">
<xsl:apply-templates/>
</xsl:template>
<!-- Build required doc parts -->
<xsl:variable name="docparts">
<xsl:call-template name="builddocparts"/>
</xsl:variable>
<xsl:template name="builddocparts">
Length: <xsl:value-of select="string-length(normalize-unicode($xsdresult))"/>
</xsl:template>
...
A call to string-length() is equivalent to a call to string-length(.), which in turn coerces the current node to a string, so it's equivalent to string-length(string(.)). The value of the string() function is the string value of the node, which for an element node is the string formed by the concatenation of all descendant text nodes.
If you want to know how the minimum amount of space the serialized XML document will take on disk, given a simple serialization, then you must add:
For each non-empty element, the length of its start-tag: the length of the element type name, plus 2 for the start-tag delimiters < ... >, plus the sum of the lengths of the attribute-value specifications.
For each attribute-value specification, you will need one character for leading whitespace, plus the length of the attribute name, plus the string length of the attribute's value, plus three for the equal sign and quotation marks, plus five characters for each time a quotation mark is replaced by &apos; or ".
For each non-empty element, the length of its end-tag (length of its element type name plus 3).
For each empty element, the length of its sole tag (length of its element type name, plus length of its attribute-value specifications, plus 3).
For each occurrence of < in the data or in attribute values, three characters for the escaping as <.
For each occurrence of ampersand in the data or in attribute values, four characters for escaping as &.
Not part of the minimum amount, but possibly part of the space you'll need on disk:
The total width of any whitespace added, if you indent the XML structurally.
The number of CDATA marked sections you serialize, times 12 (for <![CDATA[ + ]]>).
The number of characters saved by using CDATA marked sections instead of < and &.

Test some conditions using XSL 1.0

1) How to check if the number variable has only 4 digits using XSL1.0.
<xsl:variable name="number" select="0715" />
2) How to check if the version variable has a numeric digit followed by an upper case using XSL1.0
<xsl:variable name="version" select="V1" />
1) How to check if the number variable has only 4 digits using XSL1.0.
<xsl:variable name="number" select="0715" />
This is impossible, because the value of $number is exactly the same as if you wrote
<xsl:variable name="number" select="715" />
The insignificant zero disappears long before you can test for its presence. So perhaps you just want ($number < 10000)?
On the other hand, if you're testing that a string comprises exactly four digits, use translate($x, '0123456789', '9999999999') = '9999'.
2) How to check if the version variable has a numeric digit followed by an upper case using XSL1.0
Depends a little what you mean by "followed" - can there be anything in between? If you mean 'immediately followed', then you can use the same trick:
translate(substring($x, 1, 1), '0123456789', '9999999999') = '9'
and
translate(substring($x, 2, 1), 'ABCD...XYZ', 'Z') = 'Z'
Use the string-length() function to determine the ... well, the length of a string.
You could test for:
translate($version, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789', 'AAAAAAAAAAAAAAAAAAAAAAAAAA0000000000') = 'A0'
Note: This tests for a single upper case character followed by a single digit - IOW, the string "V1" passes this test.
Note also that your variable points to an element named V1, not to a string containing "V1".

Xpath search for duplicate

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.

How to remove character from string using xslt?

<Scheduled>
<xsl:value-of select="//RequestParameters/Identifier/DepartureDate">
</xsl:value-of>
</Scheduled>
In this xslt code iam getting a last character as 'z' in "//RequestParameters/Identifier/DepartureDate" i want to remove z and please help on this.
If the value of //RequestParameters/Identifier/DepartureDate contains 'z' only at the end, you can use substring-before function.
<xsl:value-of select="substring-before(//RequestParameters/Identifier/DepartureDate, 'z')">
edit:
If you want to get the first 10 characters of the value, you can use substring function.
<xsl:value-of select="substring(//RequestParameters/Identifier/DepartureDate, 1, 10)">
In general, you may want to convert an element value in ISO 8601 date format to another format by adding a javascript function to your xslt, and call that function in your Xpath expression.
For instance, when you have added a (javascript) function convertToDate that extracts the date part of the input value in the format yyyymmdd, the Xpath expression
convertToDate (//RequestParameters/Identifier/DepartureDate)
will result in a value
20111016
assuming there is only one DepartureDate element in the input, having value
2011-10-16T09:40:00.000Z

xslt choosing between select="1" or select="'1'"

What is the difference between <xsl:variable name="test" select="1"/>
and <xsl:variable name="test" select="'1'"/> ?
if both results are result tre fragments.. so basically the two lines of code above are identical?
If so. how do we decide which to use?
The first sample creates a variable of type number with the number value 1, the second a variable of type string with the string value "1". Result tree fragments are not created with your code samples, that would be done with <xsl:variable name="test">1</xsl:variable>.
As #Martin pointed out, the first one binds the variable to a number and the second one to a string.
how do we decide which to use?
Think of the use you will do with that variable. For example, in the first case you will be able to do:
item[$test]
This won't be possible in the second case, unless you use number() function.
As per the comments below, string or number will not make any difference when using any of the comparison operators. Even when comparing against nodes sets or rtfs. You can read this on the specs (a bit verbose) or try some silly test.
What still is evident is the different behavior you can obtain when dealing with node positions. For example, if you have:
<xsl:variable name="number2" select="2"/>
<xsl:variable name="string2" select="'2'"/>
<xsl:variable name="rtf2">2</xsl:variable>
and you have the input like this:
<root>
<test>a</test>
<test>b</test>
</root>
By using:
<xsl:value-of select="/root/test[$rtf2]"/>
<xsl:value-of select="/root/test[$string2]"/>
<xsl:value-of select="/root/test[$number2]"/>
You will get:
aab
while this:
<xsl:value-of select="/root/test[position()=$rtf2]"/>
<xsl:value-of select="/root/test[position()=$string2]"/>
<xsl:value-of select="/root/test[$number2]"/>
will return:
bbb
due to implicit conversion caused by comparison operators.
XPath 1.0 and XSLT 1.0 treat numbers and strings as pretty much interchangeable, with very few exceptions. A notable exception is item[$test]. But "=" behaves slightly differently too: as numbers 4 and 04 are equal, but as strings they are not.
In XPath 2.0 and XSLT 2.0 the type system is much richer and the difference between strings and numbers is much more noticeable: many operations defined on numbers won't work on strings, and vice-versa.
How to decide? If it's all-numeric, you would normally want to use a number, unless it's something like a phone number, where leading zeros are significant, and it's therefore not really a number but a string of digits.