How do I use a variable in select in xsl - variables

now
<xsl:for-each select="tm-reg-gaz/trademark/img">
want to change like this.
<xsl:variable name="tag_name">
<xsl:if test="tm-reg-gaz">tm-reg-gaz</xsl:if>
<xsl:if test="mp-tm-reg-gaz">mp-tm-reg-gaz</xsl:if>
</xsl:variable>
<xsl:for-each select="$tag_name/trademark/img">
</xsl:for-each>
I tried these
<xsl:for-each select="$tag_name/trademark/img">
<xsl:for-each select="path[$tag_name]/trademark/img">
<xsl:for-each select="{$tag_name}/trademark/img">
Let me know if it can. Thank you.

You can use select="*[name()=$tagname]/trademark/img".
A better approach is probably
<xsl:variable name="selection" select="tm-reg-gaz|mp-tm-reg-gaz">
<xsl:for-each select="$selection/trademark/img">
</xsl:for-each>
(But the details depend on whether both elements can appear or whether they are mutually exclusive).

Here is my proposal, feel free to shoot it down:
<xsl:variable name="variable" as="node()*">
<xsl:choose>
<xsl:when test="$testme = 'something'">
<xsl:copy-of select="//tm-reg-gaz/trademark/img"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="//mp-tm-reg-gaz/trademark/img"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:for-each select="$variable">
<!-- do something -->
</xsl:for-each>

Related

Find last translate

I have the following xml:
<item>value 1,value 2,value3,</item>
I would now like to achieve the following via an output via xslt:
<item>value 1,value 2,value3</item>
So remove the last comma. Can you help me?
Use this template:
<xsl:template match="item">
<xsl:copy>
<xsl:choose>
<xsl:when test="substring(.,string-length(.))=','">
<xsl:value-of select="substring(.,1,string-length(.)-1)"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="node()"/>
</xsl:otherwise>
</xsl:choose>
</xsl:copy>
</xsl:template>
It will only remove the last char when it is a comma.

navigating to a particular block in xsl upon certain conditions

I have an condition in xsl in which I have to read the data if sert name is gfrt and the value is TTT can you please advise how would the xsl:if tag for this..
<abcData name="aaa" idref="egh">
<sert name="gfrt" idref="tre">TTT</sert>
<sert name="ghhrt" idref="rew">R</sert>
</abcData>
I have gone through this way...
<xsl:if test="./#name=$gfrt">
</xsl:if>
try this
<xsl:template match="sert">
<xsl:if test="#name='gfrt' and .='TTT'">
Do something here...
</xsl:if>
</xsl:template>
or
<xsl:template match="abcData">
<xsl:for-each select="sert">
<xsl:if test="#name='gfrt' and .='TTT'">
Do something here...
</xsl:if>
</xsl:for-each>
</xsl:template>
it depends on which context you are in.

xslt replace value of multiple elements

I need to replace values of multiple elements of an input xml. The input file has around 300 elements of which I need to replace around 100 elements. I have used identity template before, but I think it would require me to write 100 different templates each for replacing a single element value. I am not very good at xslts, so, am I thinking it right, or is there a better an elegant approach? Please advice.
Edit
Here is the Link of sample input xml.
The output will have almost the same structure, but different values for some of the elements.
Well, something I did similar before before so I am happy to share ... modified to your example BUT does not do the value mapping, it does name mapping.
First create a simple mapping file like this (NOTE: you would need the namespaces to do this right
<env:map xmlns:env="http://www.w3.org/2003/05/soap-envelope">
<elem old="CardCode" new="CodeCardNEW"/>
<elem old="CardName" new="IAMNew"/>
</env:map>
Then one template will do you with a lookup. There are likely better ways to do the mapping, I am just for-each looping over them all ... a key would be better. But this gets you there.
Output from your file with above:
<env:Envelope xmlns:env="http://www.w3.org/2003/05/soap-envelope">
<env:Body>
<GetByKeyResponse>
<BOM>
<BO>
<AdmInfo>
<Object>oBusinessPartners</Object>
</AdmInfo>
<BusinessPartners>
<row>
<CodeCardNEW>CR43WEB</CodeCardNEW>
<IAMNew>Zack Burns</IAMNew>
<CardType>cCustomer</CardType>
...
And here's the XSL:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:env="http://www.w3.org/2003/05/soap-envelope"
version="1.0">
<xsl:param name="map" select="document('map.xml')/env:map"></xsl:param>
<xsl:template match="text()" priority="1">
<xsl:value-of select="."/>
</xsl:template>
<xsl:template match="#*|node()">
<xsl:variable name="newname">
<xsl:call-template name="namesub">
<xsl:with-param name="name" select="name()"/>
</xsl:call-template>
</xsl:variable>
<xsl:element name="{$newname}">
<xsl:apply-templates select="#*|node()"/>
</xsl:element>
</xsl:template>
<xsl:template name="namesub">
<xsl:param name="name"/>
<xsl:variable name="newname">
<xsl:for-each select="$map/elem">
<xsl:choose>
<xsl:when test="#old = $name">
<xsl:value-of select="#new"/>
</xsl:when>
</xsl:choose>
</xsl:for-each>
</xsl:variable>
<xsl:choose>
<xsl:when test="string-length($newname) > 0">
<xsl:value-of select="$newname"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$name"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
You should be able to adapt this as long as you have a match on name ... if the name is the same in different hierarchies of the XML, you would need more work.

XSLT1 error when get first occurence of a tag

This question (and my problem) is similar to XSLT1 Get the first occurence of a specific tag... But I have an "Undefined variable" error.
I have a XML with refpos attribute, that can be make by this first XSLT,
<xsl:template match="p[#class='ref']">
<xsl:copy>
<xsl:attribute name="refpos">
<xsl:value-of select="position()"/>
</xsl:attribute>
<xsl:apply-templates />
</xsl:copy>
</xsl:template>
<xsl:template match="#*|node()" name="idt">
<xsl:copy><xsl:apply-templates select="#*|node()"/></xsl:copy>
</xsl:template>
Then, I a main (second) XSLT I have,
<xsl:variable name="firstRef">
<xsl:value-of select="(//p[#class='ref'])[1]/#refpos"/>
</xsl:variable>
<xsl:template match="p[#refpos=$firstRef]">
<title><xsl:apply-templates /></title>
</xsl:template>
<xsl:template match="#*|node()" name="idt">
<xsl:copy><xsl:apply-templates select="#*|node()"/></xsl:copy>
</xsl:template>
But here this XSLT not works!!
PS: I also believe that XSLT1 allow us to do everything in one step.
XSLT 1.0 does not allow variable references in template match expressions (XSLT 2.0 does). You'll have to move the check from the predicate inside the template:
<xsl:template match="p">
<xsl:choose>
<xsl:when test="#refpos=$firstRef">
<title><xsl:apply-templates /></title>
</xsl:when>
<xsl:otherwise>
<xsl:call-template name="idt" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>

XSL : How to pass variable to for each

<xsl:for-each select="$script/startWith">
<xsl:variable name = "i" >
<xsl:value-of select="$script/startWith[position()]"/>
</xsl:variable>
<xsl:for-each select="JeuxDeMots/Element">
<xsl:variable name = "A" >
<xsl:value-of select="eName"/>
</xsl:variable>
<xsl:if test="starts-with($A,$i)= true()">
<xsl:variable name="stringReplace">
<xsl:value-of select="substring($i,0,3)"/>
</xsl:variable>
<xsl:value-of select="$stringReplace"/>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
Problem : variable $i, can not pass in an xsl for-each.
Please help me.
Try replacing the declaration of i with
<xsl:variable name="i" select="string(.)"/>
The context item (i.e. ".") is different for each evaluation of the for-each instruction, but the value of the expression $script/startWith[position()] does not change. (Here, you are making a sequence of startWith elements, and testing each one for the effective boolean value of the expression position(). The expression position() returns a positive integer, so its effective boolean value is always true. So the predicate [position()] is doing no work at all here.
Also, you'll want to replace the declaration of stringReplace with
<xsl:variable name="stringReplace" select="substring($i,1,3)"/>
(String offsets begin with 1 in XPath, not with 0.)
I am guessing that you want to process all of the startWith children of $script, and for each one emit the first three characters of the startWith value once, for each startWith/JeuxDeMots/Element whose eName child begins with the value of startWith.
Actually, the whole thing might be a little easier to read if it were briefer and more direct:
<xsl:for-each select="$script/startWith">
<xsl:variable name = "i" select="string()"/>
<xsl:for-each select="JeuxDeMots/Element">
<xsl:if test="starts-with(eName,$i)">
<xsl:value-of select="substring($i,1,3)"/>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
It makes perfect sense to create the variables $A and $stringReplace if they are used several times in code you're not showing us, but if not, ...
I think the problem is that you change context in first for-each. Then the element JeuxDeMots is not "visible" for second for-each. You can for example try to store it in variable and use this variable in second for-each (there are also another ways how to figure out this problem).
<xsl:template match="/">
<xsl:variable name="doc" select="JeuxDeMots"/>
<xsl:choose>
<xsl:when test="$script/startWith">
<xsl:for-each select="$script/startWith">
<xsl:variable name="i">
<xsl:value-of select="."/>
</xsl:variable>
<xsl:for-each select="$doc/Element">
<xsl:variable name="A">
<xsl:value-of select="eName"/>
</xsl:variable>
<xsl:if test="starts-with($A,$i) = true()">
<xsl:variable name="stringReplace">
<xsl:value-of select="substring($i,0,3)"/>
</xsl:variable>
<xsl:value-of select="$stringReplace"/>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
</xsl:when>
</xsl:choose>
</xsl:template>
Although I'm not sure what exactly you are dealing with it seems to output desired value AsAt.
You could also consider C.M.Sperberg-McQueen post about string offset in XPath.