XPath duplicates syntax error - xslt

I am using the XSL below to test if self axis exists in the following axis, if it does, then select the first preceding value. I am getting a syntax error help please. Reference to what I am trying to achieve:
Remove duplicates xslt/xpath
<xsl:if test="self::*/#Cat=following::*/#Cat">
<xsl:value-of select="preceding-sibling::*/#Cat[1]=[self::*/#Cat=following::*/#Cat]"/>
</xsl:if>

The syntax error is the square brackets around the expression that follows "[1]=".
Are you sure you want to be using "following" rather than "following-sibling"?
Also, if there is an attribute #Cat then there will only be one such attribute, so selecting the first is pointless.

Related

XSLT 2 analyze-string finding block names

I am trying to detect strings in other languages in my XML.
I thought I could use something like :
<xsl:analyze-string select="$mystring" regex="(\p{InGreek})" >
but I am unable to make this work.
Do you think this is possible in XSLT ? How would you do this ?
Thanks a lot.
Maria
(XSLT 2, Saxon-HE 9.8.0.8)
I think the right category name would be IsGreek so the regular expression would be \p{IsGreek}, however as the regex attribute of xsl:analyze-string allows attribute value templates you either need to put the expression into a string variable <xsl:param name="pattern" as="xs:string">\p{IsGreek}</xsl:param>you reference as regex="{$pattern}" or you need to duplicate the curly braces, as in regex="\p{{IsGreek}}".

normalize-space() not working

There is xslt code for version 1.0 but I want to convert it to version 2.0.
<xsl:value-of select="normalize-space(round((. - $var1) div $var2))"/>
But when I try to run it, the SAXON output is:
F [Saxon-HE 9.5.0.2] XPTY0004: Required item type of first argument of normalize-space() is xs:string; supplied value has item type numeric
help me in finding and solve this issue? Thanks in advance.
As the error message mentions, normalize-space expects a string as an argument, but round returns a numeric value. Numbers don't actually have spaces in though, so there is no need to use normalize-space on the result.
This should work instead:
<xsl:value-of select="round((. - $var1) div $var2)"/>

Building custom hyperlink

This is driving me slightly potty!
I have a datasheet webpart and I would like to add a hyperlink to one of the columns to open the item in the popout/modal fashion.
So far I have:
<a><xsl:attribute name="href">
<xsl:value-of select="concat('https://mysite/_layouts/listform.aspx?PageType=4&ListId={listiD}&ID=',#ID,'&ContentTypeID=0x0100B0D8940B0260E54DA1649533F29D58D7')"/>
</xsl:attribute>
<xsl:value-of select="#Title" /></a></td>
(I have edited the above code to remove identifying features)
The error that I am getting is "This Web Part does not have a valid XSLT stylesheet. Error: A semi colon character was expected"
I really don't know what to do to fix this!
Thanks in advance,
MW
This is because of the use of the ampersand & in your statement. It needs to be escaped as & to stop XSTL trying to treat the following characters as an entity.
Try this instead:
<xsl:value-of select="concat('https://mysite/_layouts/listform.aspx?PageType=4&ListId={listiD}&ID=',#ID,'&ContentTypeID=0x0100B0D8940B0260E54DA1649533F29D58D7')"/>

XSLT substring and hash tag

Can someone tell me why this is not working?
Throughout my document I have several column breaks marked as follows: <cb ed="#S" n="45rb"/>
The hash tag is there to refer to another element where the source document is identified.
Now I want to display the column break in the following document. So that it looks like this:
|S45rb|. I thought I could use a simple substring function to get rid of the hash tag like so.
<xsl:template match="TU:cb">
<xsl:variable name="hashms"><xsl:value-of select="//TU:cb/#ed"/></xsl:variable>
<xsl:variable name="ms"><xsl:value-of select="substring($hashms,1,1)"/></xsl:variable>
<span>| <xsl:value-of select="$ms"/> <xsl:value-of select="//TU:cb/#n"/> |</span>
</xsl:template>
When I do it this way I get the following result: |#75ra|. Shouldn't the first 1 in the argument refer to the first character of the string and then the second 1 tell it to move over one character and leave me with the desired S? Instead I don't get the S but only the hash tag. Is there something about hash tags and strings I do not know?
Thanks for your help.
XSL is not 0 base, if you want to start at the second character (after the #), it should be 2 rather than 1.
http://www.w3schools.com/Xpath/xpath_functions.asp
substring($hashms,2,1) = S
You can also omit the length, which might be of benefit for extensibility later on. Especially if whatever comes after the # is the identifier, why limit your code?
substring($hashms,2) = S
substring('#S2',2) = S2

apostrophe text comparison in xsl

I have a problem with text with apostrophe symbol
example i try to test this xml having the symbol is then how can i compare ?
<xsl:for each select="country[nation='India's]">
this is statement showing error
Regards
Nanda.A
One way to do it would be:
<xsl:variable name="apos" select='"&apos;"'/>
<!-- ... later ... -->
<xsl:for-each select="country[nation=concat('India', $apos, 's')]">
The problem here is twofold:
XSLT defines no way of character escaping in strings. So 'India\'s' is not an option.
You must get through two distinct layers of evaluation.
These are:
XML well-formedness: The XML document your XSLT program consists of must be well-formed. You cannot violate XML rules.
XSLT expression parsing: The resulting attribute value string (after XML DOM parsing is done) must be make sense to the XSLT engine.
Constructs like:
<xsl:for-each select="country[nation='India's']">
<xsl:for-each select="country[nation='India&apos;s']">
pass the XML layer but violate the XSLT layer, because in both cases the effective attribute value (as stored in the DOM) is country[nation='India's'], which clearly is an XPath syntax error.
Constructs like:
<xsl:for-each select="country[nation=concat('India', "'", 's')]">
<xsl:for-each select="country[nation=concat("India", "&apos;", "s")]">
clearly violate the XML layer. But they would not violate the XSLT layer (!), since their actual value (if the XSLT document could be parsed in the first place) would come out as country[nation=concat('India', "'", 's')], which is perfectly legal as an XPath expression.
So you must find a way to pass through both layer 1 and layer 2. One way is the variable way as shown above. Another way is:
<xsl:for-each select="country[nation=concat('India', "'", 's')]">
which would appear to XSLT as country[nation=concat('India', "'", 's')].
Personally, I find the "variable way" easier to work with.