XSLT check if string contains: ' - xslt-1.0

I have to check that my XML don't contains sumbol ' in text fields. But I don't know how to order it, because such way it don't work:
<xsl:for-each select="//Surname">
<xsl:if test="contains(text(), ''')">
<xsl:text>ERROR!</xsl:text>
</xsl:if>
</xsl:for-each>
I tried \' and other variants, it don't works. How it is possible to do?

Related

xslt 3.0 conditional dynamic element creation

I have a variable:
<xsl:variable name="courseType" select="Record[1]/course-type"/>
and based on a value I would like to create a dynamic element:
<xsl:if test="$courseType ='B'">
<xsl:element name="newElement">
</xsl:if>
...
other nodes
...
<xsl:if test="$courseType ='B'">
</xsl:element>
</xsl:if>
The problem is that:
The element type "xsl:element" must be terminated by the matching end-tag "".
is there any way to achieve this?
You haven't provided much content but you can certainly use e.g.
<xsl:variable name="other-nodes">
...
</xsl:variable>
<xsl:choose>
<xsl:when test="$course-type = 'B'">
<newElement>
<xsl:sequence select="$other-nodes"/>
</newElement>
</xsl:when>
<xsl:otherwise>
<xsl:sequence select="$other-nodes"/>
</xsl:otherwise>
</xsl:choose>
Note that I have used a literal result element for newElement instead of using xsl:element as I only consider the use of xsl:element necessary if you want to compute the element name at run-time but it does not matter for the solution of the original problem whether you use a literal result element or xsl:element.

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.

Looping a variable length array with namespaces in XSLT

My previous question[1] is related to this. I found the answer for that. Now I want to loop a variable length array with namespaces. My array:
<ns:array xmlns:ns="http://www.example.org">
<value>755</value>
<value>5861</value>
<value>4328</value>
<value>2157</value>
<value>1666</value>
</ns:array>
My XSLT code:(have added the namespace in the root)
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ns1="http://www.example.org">
<xsl:template match="/">
<xsl:variable name="number" select="ns:array" />
<xsl:for-each select="$number">
<xsl:value-of select="$number" />
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
[1]https://stackoverflow.com/questions/20287219/looping-a-variable-length-array-in-xslt
IMHO you confused yourself by introducing a variable called number which actually contains a node set of value tags. Then, as a consequence you used your variable as singe item/node which does not yield the desired result (presumingly, since you did not really tell us what you want to do with the values).
Also, I think your question does not really have anything to with namespace issues as such. You just have to make sure that the namespaces in your select expressions match the namespaces in your input file.
I would suggest to do without the variable and change the way you retrieve the current value:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:ns1="http://www.example.org">
<xsl:template match="/">
<xsl:for-each select="ns:array">
<!-- Inside here you can work with the `value` tag as the _current node_.
There are two most likely ways to do this. -->
<!-- a) Copy the whole tag to the output: -->
<xsl:copy-of select="." />
<!-- or b1) Copy the text part contained in the tag to the output: -->
<xsl:value-of select="." />
<!-- If you want to be on the safe side with respect to white space
you can also use this b2). This would handle the case that your output
is required not to have any white space in it but your imput XML has
some. -->
<xsl:value-of select="normalize-space(.)" />
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

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.

Numeric variable/parameter in XSLT

I have this XSLT:
<xsl:template match="/">
<xsl:variable name="errorCount" select="count($orders/*[1]/cm:Error)" />
<xsl:apply-templates select="#*|node()">
<xsl:with-param name="errorCount" select="$errorCount" tunnel="yes" />
</xsl:apply-templates>
</xsl:template>
<xsl:template match="status">
<xsl:param name="errorCount" tunnel="yes" />
<xsl:copy>
<xsl:choose>
<xsl:when test="$errorCount > 0">
<xsl:text>ERROR</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>OK</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:copy>
</xsl:template>
The tunneling and all seems to work, but the transformation fails with the following error:
Required item type of first operand of '>' is numeric; supplied value has item type xs:string
I first had the variable declaration in the template where it is it used, and then it worked fine. Moved it because I need to use the same count in other templates too.
How/Where do I declare that this variable/parameter is in fact a number?
Since you are using XSLT 2.0, then you should also add an as attribute to your xsl:param in the template. For example (you may have to use a different as value depending on what you need the resulting number to be, such as if you'll have values that have decimals; you would also need to correct the tunnel value, per Michael Kay's point):
<xsl:param name="errorCount" tunnel="yes" as="xs:integer" />
The transform would fail if it couldn't be converted to the as type (in this case, an integer). Eero's solution may look cleaner because you'll still have to check to see if the value is greater than zero. But, because you are using XSLT 2.0, the best practice is to type your parameters/variables.
You can use number() to convert a string to a number:
<xsl:when test="number($errorCount) > 0">
<xsl:text>ERROR</xsl:text>
</xsl:when>
My suspicion is that because you wrote tunnel="true" rather than tunnel="yes", the fact that you specified tunnel at all is being (incorrectly) ignored, and the parameter is being given its default value, which is a zero-length string.