XSLT xsl:choose probem - xslt

one of my xml lines looks like this:
<cf_task_subscription amount="1200.0" code="GBP">£1,200.00</cf_task_subscription>
I would like to set up a xls:choose rule like the below but I can't do this because the XML is adding the £ sign:
<xsl:variable name="value" select="/hash/cf_task_subscription"/>
<xsl:choose>
<xsl:when test="$value > 1200.0">John Doe</xsl:when>
<xsl:when test="$value = 1200.0">Jane Doe</xsl:when>
<xsl:otherwise>Unassigned</xsl:otherwise>
</xsl:choose>
so my question is, is there a way I can tell xsl to only consider the amount="1200.00" part of the cf_task_subscription tag?
Thanks,

Since the information has carefully been provided in structured form in attributes, separately from the "display form" in the text node, then take advantage of it:
<xsl:when test="$value/#amount > 1200.0">John Doe</xsl:when>

Related

XSLT Choose - testing attribute value

I'm strugling with a Choose statement and the corresponding Test-Clause.
If have the following XML (just an extract) which represents an datamodel exportet from Enterprise Architect as XMI:
<xmi:XMI xmi:version="2.1" xmlns:uml="http://schema.omg.org/spec/UML/2.1" xmlns:xmi="http://schema.omg.org/spec/XMI/2.1" xmlns:thecustomprofile="http://www.sparxsystems.com/profiles/thecustomprofile/1.0" xmlns:EAUML="http://www.sparxsystems.com/profiles/EAUML/1.0"> <xmi:Documentation exporter="Enterprise Architect" exporterVersion="6.5"/> <uml:Model xmi:type="uml:Model" name="EA_Model" visibility="public"> <packagedElement xmi:type="uml:Package" xmi:id="EAPK_F3388CFE_57A7_4d84_8866_3FB3AADE565A" name="Data Model - SQLServer2012" visibility="public">
<packagedElement xmi:type="uml:Artifact" xmi:id="EAID_B62341D4_41C6_4c83_A60A_4CA65C2E185E" name="Database SQLServer2012" visibility="public"/>
<packagedElement xmi:type="uml:Package" xmi:id="EAPK_BA7676C5_40BC_4bd9_A0F5_F6B15E534E8E" name="Logical Model" visibility="public">
<packagedElement xmi:type="uml:Class" xmi:id="EAID_2DC36189_CCFB_40bf_A1CB_CD4FB08FE8B5" name="AnamneseStatus" visibility="public">
<ownedAttribute xmi:type="uml:Property" xmi:id="EAID_9BBF5184_37F8_4729_9DC1_7ED3B4D8FC98" name="RCHIUNET05_ContextKey" visibility="public" isStatic="false" isReadOnly="false" isDerived="false" isOrdered="true" isUnique="false" isDerivedUnion="false">
<lowerValue xmi:type="uml:LiteralInteger" xmi:id="EAID_LI000001_37F8_4729_9DC1_7ED3B4D8FC98" value="1"/>
<upperValue xmi:type="uml:LiteralInteger" xmi:id="EAID_LI000002_37F8_4729_9DC1_7ED3B4D8FC98" value="1"/>
<type xmi:idref="EASQL_Server_2012_nvarchar"/>
</ownedAttribute>
<ownedAttribute xmi:type="uml:Property" xmi:id="EAID_BC1F93D0_A7F4_474c_A27E_26D3ABCCFB7B" name="MRNCmpdId" visibility="public" isStatic="false" isReadOnly="false" isDerived="false" isOrdered="false" isUnique="true" isDerivedUnion="false">
<lowerValue xmi:type="uml:LiteralInteger" xmi:id="EAID_LI000003_A7F4_474c_A27E_26D3ABCCFB7B" value="1"/>
<upperValue xmi:type="uml:LiteralInteger" xmi:id="EAID_LI000004_A7F4_474c_A27E_26D3ABCCFB7B" value="1"/>
<type xmi:idref="EASQL_Server_2012_nvarchar"/>
</ownedAttribute>
..........
So with my XSL I will loop throug the relevant nodes and extract the tablenames and attributes. this works without problem. Now I need to translate the EA datatype into another datatype definition.
Lets say: EASQL_Server_2012_nvarchar needs to become System.String
The XSL doing this looks like this (since there are other datatypes the Choose Statement will be longer than showed here):
<xsl:for-each select="ownedAttribute[#xmi:type='uml:Property']">
<xsl:text disable-output-escaping="yes"><</xsl:text>
<xsl:value-of select="'Element Name="'"/>
<xsl:value-of select="#name"/>
<xsl:value-of select="'" '"/>
<xsl:choose>
<xsl:when test="#xmi:idref = 'EASQL_Server_2012_nvarchar'">
<xsl:value-of select="'Type="'"/>
<xsl:value-of select="'System.String'"/>
<xsl:value-of select="'" '"/>
<xsl:value-of select="'MaxLength="'"/>
<xsl:value-of select="'400'"/>
<xsl:value-of select="'" '"/>
</xsl:when>
<xsl:when test="#xmi:idref = 'EASQL_Server_2012_int'">
<xsl:value-of select="'Type="'"/>
<xsl:value-of select="'System.Int32'"/>
<xsl:value-of select="'" '"/>
</xsl:when>
......
Now my problem is, that it will not hit the test conditions and always run into the "otherwise" statement.
Does somebody see why the test condition is not working?
Thank you for any help on this.
Cheers
Sandro
I suspect that instead of:
<xsl:when test="#xmi:idref = 'EASQL_Server_2012_nvarchar'">
you want to do:
<xsl:when test="type/#xmi:idref = 'EASQL_Server_2012_nvarchar'">
since in the partial example you have posted, ownedAttribute (which is your context node when you run this test) has no xmi:idref attribute, but its child element type does.
P.S. I don't know what you're doing overall, but I cringe whenever I see:
<xsl:text disable-output-escaping="yes"><</xsl:text>
This should never be necessary. If - as it seems - you're not outputting XML, set the output method to text. Then it's not necessary to disable output escaping.

XSL transformation with link in variable name

I have the following XSL which I render into my HTML:
<xsl:for-each select="user">
<xsl:variable name="exampleurl">
<xsl:choose>
<xsl:when test="objecttype='2'">
Check this out: 
<strong><a class="link" href="http://www.example.com/beinspired">Inspiration</a></strong>.
</xsl:when>
</xsl:choose>
</xsl:variable>
<xsl:value-of select="$exampleurl" />
</xsl:for-each>
However, when I print the variable $exampleurl only the text "Check this out: Inspiration." is printed. But the word "Inspiration" is not a clickable URL like I would want.
How to fix this?
value-of creates a text node, you want
<xsl:copy-of select="$exampleurl" />
(or of course in this case you don't need a variable at all, but I assume that's just the small example?

xslt comma separate list of values

I am creating a summary view of Microsoft InfoPath form(s) using a custom XSLT Stylesheet.
I have a selection of the radio buttons on the form which are clicked "Yes", "No"
e.g.
What is the primary construction of the building?
Steel Yes
No
Timber Yes
NO
etc....
In the stylesheet I have
<tr>
<td>
The primary contruction of the building is
<xsl:choose>
<xsl:when test="/my:myFields/my:BrickPrimaryConstruction= 'true'">
Brick
</xsl:when>
</xsl:choose>
<xsl:choose>
<xsl:when test="/my:myFields/my:TimberPrimaryConstruction = 'true'">
Timber Framed
</xsl:when>
</xsl:choose>
<xsl:choose>
<xsl:when test="/my:myFields/my:ConcretePrimaryConstruction = 'true'">
Concrete Framed
</xsl:when>
</xsl:choose>
etc....
What I want to achieve in the final HTML output is something like:
The primary construction of the building is Brick, Concrete Framed, Prefabricated
I have not got much experience of XSLT, but what is the best way of achieving this?
Avoiding this:
, Concrete Framed, Prefabricated,
or
Brick, , Prefabricated
Normally in C# I would assign to a string and check if it is empty before appending a comma and then trim commas on the ends however I know that I cannot assign variables in xslt.
EDIT
I also mentioned that I wanted to be able to reuse the function in other situations such as
<xsl:value-of select="/my:myFields/my:Road"/>,
<xsl:value-of select="/my:myFields/my:District"/>,
<xsl:value-of select="/my:myFields/my:City"/>,
<xsl:value-of select="/my:myFields/my:County"/>,
<xsl:value-of select="/my:myFields/my:Postcode"/>
where these would be separated by comma or a new line character, but there is the possibility that the "District" for example might be blank resulting in "Road, , City" etc.
Try this:
<tr>
<td>
The primary contruction of the building is
<xsl:for-each select="/my:myFields/my:*[ends-with(local-name(), 'PrimaryConstruction') and (.='true')]">
<xsl:if test="position()!=1" xml:space="preserve">, </xsl:if>
<xsl:choose>
<xsl:when test="self::my:BrickPrimaryConstruction">Brick</xsl:when>
<xsl:when test="self::my:TimberPrimaryConstruction">Timber Framed</xsl:when>
<xsl:when test="self::my:ConcretePrimaryConstruction">Concrete Framed</xsl:when>
etc...
</xsl:choose>
</xsl:for-each>
Basically, the for-each loops over all the relevant fields, so that you can check their position and only emit the comma if you're not on the first item (XSLT has a 1-based index). Since the for-each already filters only the relevant entries, we then only have to check the type, not whether the value is true or not.
Note that you can extend the same principle to emit an "and" for the last item instead of a comma if you like to do so.
Maybe look at Implode.
Then, you could do
<xsl:variable name="theItems">
<xsl:if test="/my:myFields/my:BrickPrimaryConstruction= 'true'">
<foo>Brick</foo>
</xsl:if>
</xsl:variable>
<xsl:call-template name="implode">
<xsl:with-param name="items" select="exsl:node-set($theItems)" />
</xsl:call-template>
You have to convert $theItems, which is a xml fragment, to a node-set. This can only be archived using non-standart methods. XML.com shows some methods to archive it using various XML processors.

XSLT: contains() for multiple strings

I have a variable in XSLT called variable_name which I am trying to set to 1, if the Product in question has attributes with name A or B or both A & B.
<xsl:variable name="variable_name">
<xsl:for-each select="product/attributes">
<xsl:if test="#attributename='A' or #attributename='B'">
<xsl:value-of select="1"/>
</xsl:if>
</xsl:for-each>
</xsl:variable>
Is there any way to match multiple strings using the if statement, as mine just matches if A is present or B is present. If both A & B are present, it does not set the variable to 1. Any help on this would be appreciated as I am a newbie in XSLT.
You can use xsl:choose statement, it's something like switch in common programming languages:
Example:
<xsl:variable name="variable_name">
<xsl:for-each select="product/attributes">
<xsl:choose>
<xsl:when test="#attributename='A'">
1
</xsl:when>
<xsl:when test=" #attributename='B'">
1
</xsl:when>
<!--... add other options here-->
<xsl:otherwise>1</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:variable>
This will set new variable with name variable_name with the value of attribute product/attributes.
For more info ... http://www.w3schools.comwww.w3schools.com/xsl/el_choose.asp
EDIT: And another way (a little dirty) by OP's request:
<xsl:variable name="variable_name">
<xsl:for-each select="product/attributes">
<xsl:if test="contains(text(), 'A') or contains(text(), 'B')">
1
</xsl:if>
</xsl:for-each>
</xsl:variable>
It will be helpful if you provide the xml you're writing your xslt against.
This might not help...
Is it 'legal' to have two XML element attributes with the same name (eg. <element x="1" x="2" />)?
Is this what you are trying to process? Try parsing your XML file through xmllint or something like it to see if it is valid.
xmllint --valid the-xml-file.xml
My guess is that you will get a 'attribute redefined' error.

XSLT: opening but not closing tags

Is there a way to open a tag and not close it? For example:
<xsl:for-each select=".">
<span>
</xsl:for-each>
This is my code: http://pastebin.com/1Xh49YN0 . As you can see i need to open on a when tag and close it on another when tag (row 43 and 63).
This piece of code is not valid because XSLT is not well formed, but is there a way to do a similar thing? Thank you
Move the content between the two existing xsl:choose elements to a new template
In the xsl:when, open and close your span. Inside the span, call this new template.
Add an xsl:otherwise to the xsl:choose, in this, call the template, without adding a span.
As a general point, try to use xsl:apply-templates a bit more often, rather than xsl:for-each, it should make it easier to understand what is going on.
You can't - XSLT isn't about generating a text file or a sequence of characters, it's about transforming one document tree into another. That the tree eventually gets serialized into a textual format is incidental.
This is why, for example, you can't choose between and in the output file - they're both represent exactly the same document tree.
You can almost always achieve what is intended by refactoring into separate templates that call each other.
You can use disable-output-escaping, but it's generally considered a bit of a hack, and I understand it's deprecated in XSLT 2.
Untested, obviously, but if I understood your original code correctly, this should be pretty close.
<xsl:choose>
<xsl:when test="$pos">
<xsl:for-each select="$s">
<xsl:choose>
<!-- inizio contesto -->
<xsl:when test="$pos[.=position()+$context_number]">
<xsl:text>INIZIO CONTESTO</xsl:text>
</xsl:when>
<!-- fine contesto -->
<xsl:when test="$pos[.=position()-$context_number]">
<xsl:text>FINE CONTESTO</xsl:text>
</xsl:when>
<!-- parola -->
<xsl:when test="$pos[.=position()]">
<span class="word"><xsl:value-of select="."/></span>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="."/>
</xsl:otherwise>
</xsl:choose>
<xsl:if test="position() != last()">
<xsl:text> </xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:when>
<xsl:otherwise>
<!-- stampo tutta la riga -->
<xsl:value-of select="$s"/>
</xsl:otherwise>
</xsl:choose>
Hint: <xsl:when test="(. - $current_pos) eq 0"> is equivalent to <xsl:when test=".=$current_pos">. ;-)