Hello I am writing an xslt program and I have this problem. I would like to separate an int into two different int.
Let me show and example:
<node>
<xsl:variable name="test" select="root/node/value"/>
...
<xsl:variable name="first" .../>
<xsl:variable name="second" .../>
...
<xsl:value-of select="first"/>
<xsl:value-of select="second"/>
</node>
Here value equals for example "1234" and first would be "12" and second "34".
I thinked of maybe divide the first one by 100 and keep the result as an int and for the second I still have no idea.
Is there an easier way to do it ?
Thank you.
I am guessing (!) you want to do:
floor($yourvalue div 100)
and:
$yourvalue mod 100
Related
While using the XSLT, I got a problem with a foreach loop with XML root node data.
From below XML, I need to extract an additional HI segment( with BF13 and BF14 values) only if there is a DiagnosisPosition="BF13|14"
XML:
<?xml version="1.0"?>
<root>
<ns0:Diagnosis DiagnosisPosition="BF01|02" CodeList="BF" DiagnosisCode="1" PresentOnAdmission="Y" LCR_CD="" />
<ns0:Diagnosis DiagnosisPosition="BF01|02" CodeList="BF" DiagnosisCode="5" PresentOnAdmission="Y" LCR_CD="" />
<ns0:Diagnosis DiagnosisPosition="BF02|03" CodeList="BF" DiagnosisCode="12" PresentOnAdmission="" LCR_CD="" />
<ns0:Diagnosis DiagnosisPosition="BF13|14" CodeList="BF" DiagnosisCode="13" PresentOnAdmission="Y" LCR_CD="" />
<ns0:Diagnosis DiagnosisPosition="BF14|15" CodeList="BF" DiagnosisCode="14" PresentOnAdmission="Y" LCR_CD="" />
</root>
XSLT used:
<xsl:variable name="var:v334" select="userCSharp:StringSubstring(string(s0:Diagnosis/#DiagnosisPosition) , "1" , "4")" />
<xsl:variable name="var:v335" select="userCSharp:LogicalEq(string($var:v334) ,"BF13" )" />
<xsl:if test="$var:v335">
<xsl:for-each select="s0:Diagnosis">
<xsl:variable name="var:v33611" select="string(#DiagnosisPosition)" />
<xsl:variable name="var:v33711" select="userCSharp:StringSubstring($var:v33611 , "1" , "4")" />
<xsl:variable name="var:v33811" select="userCSharp:LogicalEq(string($var:v33711) , "BF13")" />
<xsl:if test="$var:v33811">
<ns0:HI_OtherDiagnosisInformation>
<xsl:for-each select="s0:Diagnosis">
For each loop is not working. Scope of this foreach loop is lost and goes to the root foreach loop.
<xsl:variable name="var:v336" select="string(#DiagnosisPosition)" />
<xsl:variable name="var:v337" select="userCSharp:StringSubstring($var:v336 , "1" , "4")" />
<xsl:variable name="var:v338" select="userCSharp:LogicalEq(string($var:v337) , "BF13")" />
<xsl:if test="$var:v338">
--Writing values of CodeList and Diagnosis codes
</xsl:if>
<xsl:variable name="var:v345" select="string(#DiagnosisPosition)" />
<xsl:variable name="var:v346" select="userCSharp:StringSubstring($var:v345 , "1" , "4")" />
<xsl:variable name="var:v347" select="userCSharp:LogicalEq(string($var:v346) , "BF14")" />
<xsl:if test="$var:v347">
--Writing values of CodeList and Diagnosis codes
</xsl:if>
</xsl:for-each>
</ns0:HI_OtherDiagnosisInformation>
</xsl:if>
</xsl:for-each>
</xsl:if>
I just need to extract an additional HI segment only when there is a BF13, BF14 elements else no HI segment.
I tried lots of ways but unable to get it to work and need some help/suggestions.
Any help is very much appreciated.
Thank you and looking forward for responses.
If you realy need two nested loops, both running through all Diagnosis elements,
then the inner loop should have the form:
<xsl:for-each select="../ns0:Diagnosis">
Apparently you forgot that the current element within a loop (.) is each element
from the sequence stated in the select clause.
I think hovewer, that you do not need the inner loop.
You wrote that you need to exctract additional information for certain Diagnosis
elements, only if their DiagnosisPosition starts with either BF13 or BF14.
So maybe a single loop will be sufficient?
Instead of the inner loop you should:
Read DiagnosisPosition value (once only, in your example you read it twice, under 2 different variables).
Put <xsl:if ...> checking whether this value starts with BF13 or BF14.
Place additional output within this if.
Or maybe this additional segment of output data is to be output if either "number" (chars 3-4 or 6-7 from DiagnosisPosition, (2 chars before or after "|")) is 13 or 14?
In that case change the test condition accordingly.
I have a XSLT maps that I use for some transformation. My problem is how can I remember the count 1.e; the number of times a loop has run. For example
<xsl: for each> // This runs some 3 times
<xsl: call-template > // This call template recursively runs 10 times
<xsl: with- param >
</xsl: call-template >
<xsl: for each>
In the above example outer for loop runs 3 times and inner call-template recurively call itself to print some thing suppose 10 times. So In all I have 3*10 = 30 cycles.
What I need over here is suppose I have an intial number 001, When for loop runs first time it will call template that will recursively call itself 10 times. So I printed numbers starting from 001 - 010
The next time I run the loop I again printed the numbers from 001-010 ans so on the third time. But What I want is to remember the last count. Suppose in first iteration I reached 010. So in second iteration I will start the count from 011 and print up to 021.
And in the third time I will print starting from 022-032.
But can any one suggest me how can I do that ? How can I remember the last value up to which the printing is already done?
And one more thing I'm actually limited to XSLT1.0. Thats the reason I have to loop like the example above.
This would be a great help
What I want to do is like this,
Suppose I have an input xml as,
<A>
<B from="123456781" to="123456782">
........
</B>
<B from="123456781" to="123456785">
........
</B>
<B from="123456788" to="123456788">
........
</B>
</A>
In above xml each node B is associated with a range "from-to". I need to create as many ouputB node as there is number in given range. and I also have to get unique count of each outputB node that is created. For example output xml can be like ,
<root>
<outputB value="123456781" id="001"> // from first B node from="123456781" to="123456782"
<outputB value="123456782" id="002">
<outputB value="123456781" id="003">
<outputB value="123456782" id="004">// from second B node from="123456781" to="123456785"
<outputB value="123456783" id="005">
<outputB value="123456784" id="006">
<outputB value="123456785" id="007">
<outputB value="123456788" id="008">// from third B node from="123456788" to="123456788"
</root>
So In above xsl I have recursively populated on the basis of range values in from and to parameter while I have lopped bu for-each on each input B node. Thus creating the exact number of outputB nodes. But the problem here is maintaining unique count or id in generated xml.
Thanks :)
XSLT is a functional language. You can't "remember" things in a functional language: there is no concept of time, no memory of things in the past. You need to compute everything in the output as a function of something in the input.
You don't remember values in XSLT or even add up as you go along, except in very specific circumstances. However, in general, you don't need to.
So if you have:
<xsl:for-each select="conditiona"> // This runs some 3 times
then you have all you need to provide a count:
<xsl:value-of select="count(conditiona)"/> // this displays 3
When you call the template you just pass in a parameter of the 'depth'.
<xsl:template Name="x">
<xsl:param name="depth">
<xsl:call-template name="x">
<xsl:with param name="depth" select=="depth+1" />
</xsl:call-template>
</xsl:template>
Then you do something similar for your outer loop. It is not clear how you are doing this loop, but you may be able to use position(). Then the number you want is position()*10 + depth.
How's this? You can run it at this XMLPlayground (see output source). It avoids the for-each completely (always best avoided in XSLT).
There's two key concepts here:
repeated template matching on the same node for as long as its range requires
having nodes kick off the process for their following sibling, rather than having the root-matching template apply to all B nodes. This way, a "where did you get up to?" relationship can be maintained via passed params. It's unorthodox, but works.
Code:
<!-- root - kick things off, for each B node -->
<xsl:template match="/">
<xsl:apply-templates select='//B[1]' />
</xsl:template>
<!-- iteration content - B nodes -->
<xsl:template match='B'>
<!-- recursion params -->
<xsl:param name='index' select='#from' />
<xsl:param name='id' select='position()' />
<xsl:param name='pos' select='position()' />
<!-- output node -->
<outputB value='{$index}' id='{$id}' />
<!-- now recurse for... -->
<xsl:choose>
<!-- ...as range requires -->
<xsl:when test='(#from and #to) and (not($index) or $index < #to)'>
<xsl:apply-templates select='.'>
<xsl:with-param name='index' select='$index + 1' />
<xsl:with-param name='id' select='$id + 1' />
</xsl:apply-templates>
</xsl:when>
<!-- ...next B node, if there is one -->
<xsl:when test='following-sibling::B'>
<xsl:apply-templates select='following-sibling::B[1]'>
<xsl:with-param name='id' select='$id + 1' />
</xsl:apply-templates>
</xsl:when>
</xsl:choose>
</xsl:template>
Outputs:
<outputBs value="123456781" id="1"/>
<outputBs value="123456782" id="2"/>
<outputBs value="123456783" id="3"/>
<outputBs value="123456781" id="4"/>
<outputBs value="123456782" id="5"/>
<outputBs value="123456783" id="6"/>
<outputBs value="123456784" id="7"/>
<outputBs value="123456785" id="8"/>
<outputBs value="123456788" id="9"/>
i have two variables in xslt,i am not able to add those and assign to another variable,
Any help would be appreciated.
<xsl:variable name="Book" select="hummpty" />
<xsl:variable name="Book1" select="andro" />
<xsl:variable name="Total">
<xsl:value-of select="$Book + $Book1/>
</xsl:variable>
When i try to print 'Total' i am getting value as NaN.
How do i achieve this? After achieving this , i would like to assign this as an attribute value.
eg:
<Book totakBook="$Total" />
Something like above.
Any help appreciated.
If you actually want to concatenate string values, try this:
<xsl:value-of select="concat($Book, $Book1)" />
Try this
<xsl:value-of select="sum($Book + $Book1)"/>
provided both variables contain valid numeric values.
I'm outputting text with XSLT. I need to count the number of lines of each section and write it out to my output file. How this could be done?
My output is like this:
HDR+aaa:bbb'
AAA+78901234567890+String1:String2'
BBB+123+String'
CCC+321:1212'
DDD+112211'
DDD+121122'
XXX+number_of_records+78901234567890'
AAA+1234567890+String1:String2'
BBB+123+String'
CCC+321:1212'
DDD+1212:2121'
BBB+123+String'
BBB+122+String'
CCC+String'
XXX+number_of_records+1234567890'
The number_of_records should contain number of lines from AAA to XXX including both lines. In the first section the number of lines should be 6 and in the second message it should be 8. The first and the last line of each section will share the same unique ID-number.
The number of lines cannot be counted from source since there is so much processing inside XSLT.
A conceptually simple way to do this would be to use a second-stage process. Take the output of your initial transformation (what you posted) and run it through a template (or stylesheet like #Alejandro's) that parses it into lines, and groups the lines starting with AAA... and ending with XXX. See Up-conversion using XSLT 2.0 for a very clear and practical tutorial on doing this, using tokenize(), xsl:analyze-string, and xsl:for-each-group. Then count the lines in each group, and re-output each line, plug the line count into the XXX record.
But that's inefficient, and somewhat error-prone, since you would be parsing the initial output. Why parse a serialization of information that the stylesheet already had internally? You could avoid the inefficiency by changing your initial output to XML, something like
<hdr>
<section id="78901234567890">
<!-- It sounds like AAA's ID actually applies to the section? -->
<AAA String1="..." String2="..."/>
<BBB .../>
<!-- no need to include XXX at this stage AFAICT -->
</section>
<section id="1234567890">
...
</section>
</hdr>
Then the second-stage template (or a separate stylesheet) could take this XML as input and very easily serialize it as you have done above, counting the lines as it goes.
In XSLT 1.0, you would have to use a separate stylesheet to process the output XML, or else use the extension function node-set(). (But even with a separate stylesheet processor, you could still avoid the cost of re-parsing the intermediate XML, if you can pipeline the two stylesheet processors together using SAX.) In XSLT 2.0, you can process the XML output of one template with another template, without restriction.
Just for fun, until you post your input sample and stylesheet building that text output, this stylesheet:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="result" name="result">
<xsl:param name="pString" select="."/>
<xsl:variable name="vAfter" select="substring-after($pString, 'AAA+')"/>
<xsl:choose>
<xsl:when test="$vAfter!=''">
<xsl:variable name="vId"
select="substring-before($vAfter, '+')"/>
<xsl:variable name="vEnd"
select='concat("XXX+number_of_records+",$vId,"'
")'/>
<xsl:variable name="vInto"
select="substring-before($vAfter,$vEnd)"/>
<xsl:value-of
select='concat(substring-before($pString,"AAA+"),
"AAA+",
$vInto,
"XXX+",
string-length(translate($vInto,
translate($vInto,
"
",
""),
"")) + 1,
"+",$vId,"'
")'/>
<xsl:call-template name="result">
<xsl:with-param name="pString"
select="substring-after($vAfter,$vEnd)"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$pString"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
With this input:
<result>
HDR+aaa:bbb'
AAA+78901234567890+String1:String2'
BBB+123+String'
CCC+321:1212'
DDD+112211'
DDD+121122'
XXX+number_of_records+78901234567890'
AAA+1234567890+String1:String2'
BBB+123+String'
CCC+321:1212'
DDD+1212:2121'
BBB+123+String'
BBB+122+String'
CCC+String'
XXX+number_of_records+1234567890'
</result>
Output:
HDR+aaa:bbb'
AAA+78901234567890+String1:String2'
BBB+123+String'
CCC+321:1212'
DDD+112211'
DDD+121122'
XXX+6+78901234567890'
AAA+1234567890+String1:String2'
BBB+123+String'
CCC+321:1212'
DDD+1212:2121'
BBB+123+String'
BBB+122+String'
CCC+String'
XXX+8+1234567890'
My solution: I created an extension function that increments number_of_records by one each time I call it. I use xsl:comment to suppress the output until I really need to output the number. I reset the number_of_records after each XXX+ -line.
Doing this in two steps vould have caused too much hassle.
I need to be able to store a node set in variable and then perform more filting/sorting on it afterward. All the examples I've seen of this involve either using XSL2 or extensions neither of which are really an option.
I've a list of hotels in my XML doc that can be sorted/filtered and then paged through 5 at a time. I'm finding though I'm repeating alot of the logic as currently I've not found a good way to store node-sets in xsl variable and then use xpath on them for further filtering/sorting.
This is the sort of thing I'm after (excuse the code written of the top of my head so might not be 100%):
<xsl:variable name="hotels" select="/results/hotels[active='true']" />
<xsl:variable name="3_star_or_less" select="/results/hotels[number(rating) <= 3]" />
<xsl:for-each select="3_star_or_less">
<xsl:sort select="rating" />
</xsl:for-each>
Has anyone got an example of how best to do this sort of thing?
Try this example:
<xsl:variable name="hotels" select="/results/hotels[active='true']" />
<xsl:variable name="three_star_or_less"
select="$hotels[number(rating) <= 3]" />
<xsl:for-each select="$three_star_or_less">
<xsl:sort select="rating" />
<xsl:value-of select="rating" />
</xsl:for-each>
There is no problem storing a node-set in a variable in XSLT 1.0, and no extensions are needed. If you just use an XPath expression in select attribute of xsl:variable, you'll end up doing just that.
The problem is only when you want to store the nodes that you yourself had generated in a variable, and even then only if you want to query over them later. The problem here is that nodes you output don't have type "node-set" - instead, they're what is called a "result tree fragment". You can store that to a variable, and you can use that variable to insert the fragment into output (or another variable) later on, but you cannot use XPath to query over it. That's when you need either EXSLT node-set() function (which converts a result tree fragment to a node-set), or XSLT 2.0 (in which there are no result tree fragments, only sequences of nodes, regardless of where they come from).
For your example as given, this doesn't seem to be a problem. Rubens' answer gives the exact syntax.
Another note, if you want to be able to use the variable as part of an XPath statement, you need to select into the variable with <xsl:copy-of select="."/> instead of <xsl:value-of select="."/>
value-of will only take the text of the node and you wont be able to use the node-set function to return anything meaningful.
<xsl:variable name="myStringVar">
<xsl:value-of select="."/>
</xsl:variable>
<!-- This won't work: -->
<Output>
<xsl:value-of select="node-set($myStringVar)/SubNode" />
</Output>
<xsl:variable name="myNodeSetVar">
<xsl:copy-of select="."/>
</xsl:variable>
<!-- This will work: -->
<Output>
<xsl:value-of select="node-set($myNodeSetVar)/SubNode" />
</Output>