Am getting duplicates in the list, SO i wanted to make distinct .
Workflow Type (
<xsl:for-each select="//Bonaire/RBS/WorkflowTypeList">
<xsl:if test="#BSSLOOKUPTYPEID=//Bonaire/Request/#TYPE_BSSLOOKUPTYPEID">
<xsl:value-of select="#TYPENAME"/>
</xsl:if>
</xsl:for-each>
)
That can be done in a one-liner using distinct-values() and predicate expression ([...]) :
<xsl:for-each select="distinct-values(//Bonaire/RBS/WorkflowTypeList[#BSSLOOKUPTYPEID=//Bonaire/Request/#TYPE_BSSLOOKUPTYPEID]/#TYPENAME)">
<xsl:value-of select="."/>
</xsl:for-each>
Related
I have a variable #expectedLength. I need to assign it to a style attribute.
<xsl:if test="#expectedLength">
<xsl:attribute name="style">
<xsl:value-of select="'width:200px'"/>
</xsl:attribute>
</xsl:if>
I need to replace 200 with the value of #expectedLength. How can I use the variable?
You could change your snippet to
<xsl:if test="#expectedLength">
<xsl:attribute name="style">width: <xsl:value-of select="#expectedLength"/>;</xsl:attribute>
</xsl:if>
That should work with any version of XSLT.
In XSLT 2 and later you can also use the select expression
<xsl:if test="#expectedLength">
<xsl:attribute name="style" select="concat('width: ', #expectedLength, ';')"/>
</xsl:if>
I would prefer to and suggest to set up a template
<xsl:template match="#expectedLength">
<xsl:attribute name="style" select="concat('width: ', #expectedLength, ';')"/>
</xsl:template>
and then to make sure higher up that any attribute nodes are processed.
In XSLT 2.0 I have a parameter than comes in as a delimited string of document names like:
ms609_0080.xml~ms609_0176.xml~ms609_0210.xml~ms609_0418.xml
I tokenize() this string and cycle through it with xsl:for-each to pass each document to a key. The results from the key I then assemble into a comma-delimited string to output to screen.
<xsl:variable name="list_of_corresp_events">
<xsl:variable name ="tokenparam" select="tokenize($paramCorrespdocs,'~')"/>
<xsl:for-each select="$tokenparam">
<xsl:choose>
<xsl:when test=".[position() != last()]">
<xsl:value-of select="document(concat($paramSaxondatapath, .))/(key('correspkey',$correspid))/#xml:id"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="concat(document(concat($paramSaxondatapath, .))/(key('correspkey',$correspid))/#xml:id, ', ')"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:variable>
Everything works fine except that when I output the variable $list_of_corresp_events it looks like the following, with an unexpected trailing comma:
ms609-0080-2, ms609-0176-1, ms609-0210-1, ms609-0418-1,
Ordinarily the last comma should not appear based on test=".[position() != last()]" ? Possibly positions don't work for tokenized data? I didn't see a way to apply string-join() to this.
Many thanks.
Improving on the solution from #zx485, try
<xsl:for-each select="$tokenparam">
<xsl:if test="position()!=1">, </xsl:if>
<xsl:value-of select="document(concat($paramSaxondatapath, .))/(key('correspkey',$correspid))/#xml:id"/>
</xsl:for-each>
Two things here:
(a) you don't need to repeat the same code in both conditional branches
(b) it's more efficient to output the comma separator before every item except the first, rather than after every item except the last. That's because evaluating last() involves an expensive look-ahead.
Change
<xsl:when test=".[position() != last()]">
to
<xsl:when test="position() != last()">
Then it should all work as desired.
It seems you can simplify this to
<xsl:variable name="list_of_corresp_events">
<xsl:value-of select="for $t in tokenize($paramCorrespdocs,'~') document(concat($paramSaxondatapath, $))/(key('correspkey',$correspid))/#xml:id" separator=", "/>
</xsl:variable>
or with string-join
<xsl:variable name="list_of_corresp_events" select="string-join(for $t in tokenize($paramCorrespdocs,'~') document(concat($paramSaxondatapath, $))/(key('correspkey',$correspid))/#xml:id, ', ')"/>
In XSLT 2.0 I have long string (parameter) with a delimiter (;) inside a delimiter (~), more specifically a triplet inside a delimiter.
Data is organized like so:
<parameter>qrsbfs;qsvsv;tfgz~dknk;fvtea;gtvath~pksdi;ytbdi;oiunhu</parameter>
The first tokenize($mystring,'~') in a for-each produces :
qrsbfs;qsvsv;tfgz
dknk;fvtea;gtvath
pksdi;ytbdi;oiunhu
Within that tokenization, I need to treat it by looping again:
qrsbfs
qsvsv
tfgz
dknk
fvtea
gtvath
pksdi
ytbdi
oiunhu
I can do intensive string manipulation to get there using concat, string-length, and substring-before/substring-after, but I wondered if there wasn't a more elegant solution that my neophyte mind wasn't overlooking?
EDIT, adding nested tokenize that returned incorrect results:
<xsl:for-each select="tokenize($myparameter,'~')">
<xsl:for-each select="tokenize(.,';')">
<xsl:if test="position()=1">
<xsl:value-of select="."/>
</xsl:if>
<xsl:if test="position()=2">
<xsl:value-of select="."/>
</xsl:if>
<xsl:if test="position()=3">
<xsl:value-of select="."/>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
If you wanted a one line solution, you could do something like this, using nested for-in-return statements:
<xsl:sequence select="for $n in tokenize(.,'~') return concat(string-join(tokenize($n,';'),'
'),'
')"/>
If you don't need to tokenize them separately, you could replace the ~ with ; and tokenize all 9 elements at the same time:
tokenize(replace(parameter,'~',';'),';')
For what it's worth, the code in https://xsltfiddle.liberty-development.net/pPqsHUe uses
<xsl:template match="parameter">
<xsl:for-each select="tokenize(., '~')">
<xsl:value-of select="tokenize(., ';')" separator="
"/>
<xsl:text>
</xsl:text>
</xsl:for-each>
</xsl:template>
and with output method text produces
qrsbfs
qsvsv
tfgz
dknk
fvtea
gtvath
pksdi
ytbdi
oiunhu
<p>
<p1>c</p1>
<a languageCode="en">a1</a>
<a languageCode="de">a2</a>
<ca>
<cc>056</cc>
<cs>BE-VAN</cs>
<cs>BG-VLI</cs>
<cs>BG-VLI</cs>
</ca>
<ca>
<cc>056</cc>
<cs>BE-VAN</cs>
<cs>BG-VLI</cs>
<cs>BG-VLI</cs>
</ca>
</p>
i tried this does not work:
<xsl:for-each select="p/ca/*">
<xsl:if test="not(preceding-sibling::*[1]/name() = local-name())">
<precedingParent n="{preceding-sibling::*[1]/parent::*/name()}"></precedingParent>
</xsl:if>
</xsl:for-each>
but expected
output should be:
<precedingParent n="a"></precedingParent>
I am looping in ca and for instance in first occurence of cs
If a want to find the preceding sibling of the parent for parent ca for element cs ? how do i do it?
The expression you are looking for is ../preceding-sibling::*[1]/name(). For example,
<xsl:for-each select="p/ca/*">
<xsl:if test="not(preceding-sibling::*[1]/name() = local-name())">
<precedingParent n="{../preceding-sibling::*[1]/name()}"></precedingParent>
</xsl:if>
</xsl:for-each>
Note that name(../preceding-sibling::*[1]) would also work (in XSLT 1.0 and XSLT 2.0).
On the other hand, you could be slightly more efficient by having a nested loop, and getting the preceding value before selecting the child elements, to save it having to be recalculated each time:
<xsl:for-each select="p/ca">
<xsl:variable name="precedingParent" select="name(preceding-sibling::*[1])" />
<xsl:for-each select="*">
<xsl:if test="not(preceding-sibling::*[1]/name() = local-name())">
<precedingParent n="{$precedingParent}"></precedingParent>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
In the following code snippet, I'm trying to get position of EMP_ID field from the available fields. This works fine if there's just one occurrence of EMP_ID.
But if there are more than one occurences then variable 'empid_field' will have positions of all the occurrences appended one after the other. i.e if EMP_ID is at postions 1, 8, and 11, then 'empid_field' would be '1811'.
Is there any way I get position of first occurrence only? Or Can I get comma separated positions atleast? (Code sample would be highly appreciated as I'm new to XSL programming)
<xsl:variable name="empid_field">
<xsl:for-each select="$fields">
<xsl:if test="internalName='EMP_ID'">
<xsl:value-of select="position()"/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
The easiest solution which is in my mind is to extend this. But I think there are also solutions which look more pretty.
<xsl:variable name="empid_field">
<xsl:for-each select="$fields">
<xsl:if test="internalName='EMP_ID'">
<xsl:value-of select="position()"/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="first_empid_field">
<xsl:value-of select="$empid_field[1]"/>
</xsl:variable>
The variable $first_empid_field will only have the first position value.
Ok got something ...
Created a comma separated string and picked the part before the delimiter.
<xsl:variable name="empid_fields" >
<xsl:for-each select="$fields">
<xsl:if test="internalName='EMP_ID'">
<xsl:value-of select="position()" />
<xsl:text >, </xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="empid_field" >
<xsl:value-of select="substring-before($empid_fields, ', ')" />
</xsl:variable>