break a for-loop after specific condition match in xslt [closed] - xslt

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 1 year ago.
Improve this question
https://xsltfiddle.liberty-development.net/eieFA1J/16
Here I am trying to match placeholder[#md.mnem='angen'][placeholder.text='UL'] and identify it's preceding <codes.head ID="" md.mnem="hg*"> and store it into variable. and collection all hg* records after that match until i find hg* record with same or smaller(in my example it is hg2, and if i find hg2 or hg1 i have to break the loop)
I am able to select the hg* records after a specific match but unable to break after matching same hg* or smaller one.
can anyone please help me to solve this, the xml and xsl can find in the below link.
https://xsltfiddle.liberty-development.net/eieFA1J/16

An XSLT 3 xsl:iterate instead of an xsl:for-each might help to implement the conventional loop and break algorithm:
<xsl:iterate select="$hgset">
<xsl:choose>
<xsl:when test="#md.mnem gt $hgValue">
<xsl:copy-of select="."/>
</xsl:when>
<xsl:otherwise>
<xsl:break/>
</xsl:otherwise>
</xsl:choose>
</xsl:iterate>
But of course you can also use a recursive function or template to implement the same in XSLT 2 or perhaps just select the first item in your sequence that "breaks" the condition and select anything "before" it with the << operator.
Another option is to use <xsl:for-each-group select="$hgset" group-ending-with="*[#md.mnem le $hgValue]"><xsl:if test="position() = 1"><xsl:copy-of select="current-group()"/></xsl:if></xsl:for-each-group>.

Related

how to do an if like statement or equivalent in XSLT

Is it possible to write out xml based on an "if" "Like" statement or the equivalent of in xslt?
I have an element named "cust_code"
If the element starts with a "HE" then I want to write it out, otherwise jump to the next.
Is it possible?
If statements exist in XSLT.
<xsl:if test="...">
...
</xsl:if>
But this is a simple if, with no alternative.
If you want an equivalent to if ... else ... or switch ... case ..., you need to use the following:
<xsl:choose>
<xsl:when test="...">
</xsl:when>
<xsl:otherwise>
</xsl:otherwise>
</xsl:choose>
You can have as many when cases as necessary.
Links: w3school - if and w3school - choose.
As to having an element starting with a specific string, look at the function starts-with. You can find a good example in this SO answer (just omit the not from the main answer, as their tests was to find strings not starting with a particular string). You can also look at this answer for more information.

XSLT Element Value from MAP [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
This is my school home work and can't figure it out myself.
I need to reformat an XML file from the input source to output XML using Transformation.
My input source has many tags (elements).
I have tags like this:
<tag>
<name>DOB</name>
<value>XX/XX/XX</value>
</tag>
<tag>
<name>Address</name>
<value>123 Main St.</value>
</tag>
and I need to transform these to
<DOB>xx/xx/xx</DOB>
<Address>123 Main St.</Address>
My teacher said use conditional but I don't think that is elegant way
to do it.
No, it's not. And what exactly would the condition be? You should try:
<xsl:template match="tag">
<xsl:element name="{name}">
<xsl:value-of select="value" />
</xsl:element>
</xsl:template>
Note that this will fail if the contents of name are not a valid XML name.

How to use xsl:number count as condition in xsl:if test "condition"?

Within an xsl:for-each select loop, I have <xsl:number count="//headline"/> that correctly gives me the node #; Now I want to use that number in an xsl:if test block, but I cannot get the test expression right, msxml4.dll keeps kicking back errors. Am using xsl 1.0 (and stuck with it for now)
So, in <xsl:if test="expression">...output if the expression is true..</xsl:if>
I want the test expression to essentially be like this (so I can do something specific for Node #4, in this example):
<xsl:number count="//headline"/> = 4
This is what I have that does not work:
<xsl:if test="<xsl:number count="//headline"/> = 4">
Thanks in advance for any insights,
George
As #michael.hor257k explains, the general approach is to put the xsl:number call inside an xsl:variable (or in XSLT 2.0, inside an xsl:function). Sometimes though it's more convenient to abandon xsl:number:
<xsl:if test="count(preceding::headline) = 3">...</xsl:if>
If it's a big document then both xsl:number and preceding::headline are potentially expensive when executed inside a loop, and if this is a concern then you should compare them under your chosen XSLT processor: one may be optimized better than the other.
Come to think of it, your use of xsl:number looks odd to me. The count attribute is a pattern, and the pattern //headline matches exactly the same nodes as the pattern headline. As a result I misread your call on xsl:number as counting all the headlines in the document, whereas it actually only counts the preceding-sibling headlines. I wonder if that is what you intended?
If (!) I understand correctly, you want to do something like:
<xsl:variable name="n">
<xsl:number count="headline"/>
</xsl:variable>
<xsl:value-of select="$n"/>
<xsl:if test="$n = 4">
<!-- do something -->
</xsl:if>

XSLT compound condition that uses ends-with

and I have some code now that says:
<xsl:choose>
<xsl:when test="$Admin = 2">
<img src="../Lists/Announcement/Attachments/1/Banner.jpg" style="height:189px; width:568px;" title="{#Title};" />
</xsl:when>
<xsl:otherwise>
<img src="../Lists/Announcement/Attachments/{#ID}/Banner.jpg" style="height:189px; width:568px;" title="{#Title};" />
</xsl:otherwise>
</xsl:choose>
I would like to compound the condition so that it will also accept an attachment called banner.png also, and show banner.png.
If I use the substring function and give it a negative number will it count backwards from the end of the string?
If I use the substring function and give it a negative number will it count backwards from the end of the string?
No. (What made you think it would? Did you actually look for a specification? Did you try it? Guessing, and asking on SO whether your guess is correct, doesn't sound like a very efficient way of getting things done.)

Combining result from apply-templates with for-each-group (or alternative solution to the problem)

I got a list of articles that is sorted based on their title. In addition to the "main"-title, articles may have alternative titles (and even mulitple of them). When articles are do have alternative titles, the article should be displayed as many times as there are titles (an article with main title and two alternative titles should make three entries in the list). Simon Christian on this forum posted a solution to overcome this (thanks), and I'm able to get the desired list.
However, I need to extend this solution. In addition to the list, I need a jump menu. So I have to extract the first letter of each title (including the alternative titles), take these letters and display them on the top of the list. Each letters is a link to an anchor on the page. In the list, first the letter 'A' may be presented, followed by all articles starting on 'A', then 'B' followed by all articles starting with 'B', and so on. Those letters that is not the first letter of any title, should not be displayed.
I have an old solution on how to get the jump menu, but it only works when I have to extract the title from one place in the source XML. The alternative titles are a couple of levels deeper than the main title. For the old solution I used:
<div class="jumpmenu">
<xsl:for-each-group group-by="substring(title, 1,1)" select="content">
<xsl:sort order="ascending" select="substring(title, 1,1)"/>
<xsl:value-of select="substring(title, 1,1)"/><xsl:text> </xsl:text>
</xsl:for-each-group>
</div>
But as mentioned, it does not take the alternative titles into account. I'm able to get the first letter of all title (including the alternatives) by using this:
<xsl:apply-templates select="content/title|content/contentdata/alternativetitles/alternativetitle" mode="jumpmenu">
<xsl:sort select="string(.)" />
</xsl:apply-templates>
It basically just gets the first letter of all titles and sort them. I've tried to find ways of combining these two (for-each-group and apply-templates), but without luck. Any ideas on how to do this. An example source XML is as follows:
<result>
<element>
<title>ATitle 1</title>
<alternative>
<alternativeTitle>Title 5<alternativeTitle>
</alternative>
<data>
...
</data>
</element>
<element>
<title>CTitle 3</title>
<alternative>
<alternativeTitle>BTitle 2<alternativeTitle>
<alternativeTitle>Title 4<alternativeTitle>
</alternative>
<data>
...
</data>
</element>
</result>
My desired output is something like:
A B C T (links to their respective anchors)
A (anchor)
ATITLE 1 (which is also a link to the full article)
B (anchor)
BTITLE 2 (which is also a link to the full article)
C (anchor)
CTITLE 3 (which is also a link to the full article)
T (anchor)
TITLE 4 (which is also a link to the full article)
TITLE 5 (which is also a link to the full article)
The solution to this will probably help me with another problem, but I'll present it if anyone got ideas for that as well. The articles that have alternative titles, are listed under the same letter as the first letter of the main title. So given the exmaple above, "BTitle 2" is listed under 'C'.
Sorry for the long post, I didn't find any way to make it shorter and still be precise. In advance, thanks!
EDIT: This the code I have so far on the second part of the problem:
<xsl:for-each-group group-by="substring(title, 1,1)" select="content">
<xsl:sort order="ascending" select="substring(title, 1,1)"/>
<xsl:apply-templates mode="overskrift" select="."/>
<xsl:apply-templates select="current-group()/title|current-group()/contentdata/alternativetitles/alternativetitle">
<xsl:sort select="string(.)"/>
</xsl:apply-templates>
</xsl:for-each-group>
That code will list all titles, but lists the alternative titles based on the same first letter as the article's main title..
Well why don't you simply use
<xsl:for-each-group select="content/title|content/contentdata/alternativetitles/alternativetitle" group-by="substring(., 1, 1)">
<xsl:sort select="current-grouping-key()"/>
<xsl:value-of select="current-grouping-key()"/><xsl:text> </xsl:text>
</xsl:for-each-group>
? You should put that code in a template matching the parent of that content element (I am not sure what name it has as your path expressions and the posted XML sample do not match).