XSLT - Replace a number of chars in a string - xslt

I have the following string,
';#6;#'
The above string could be anything, E.g.:
';#1;#' or ';#2;#' , or ';#3;#' ...
I need to be able to replace the contents between the ' and '
Is this possible using something like translate in XSLT 1.0?

This kind of thing is quite difficult in XSLT 1.0. Take a look at the library of string-handling functions available at www.exslt.org - some of them come with XSLT implementations that you can copy into your stylesheet and call (typically as xsl:call-template).

Use substring and concat functions.

Related

replace the character in XSLT

I am using the xslt for transformation but from input 240 characters receiving in one element ,In that element different special characters receiving(eg :---> %,?,/,-,_,#,!,$,^) .
I need to replace the those characters.
It is possible in XSLT 1.0.If it is possible can you please give me the code with examples?.Thanks
Eg:
<remark> whfwlknf234#skl$ck?nvwkld^fnwlfn </remark>
It is possible in XSLT 1.0
Yes, it is possible. Use the translate() function to replace them with ... oh, you didn't say with what.

How do you extract text matching a pattern in XPATH?

I have data that looks like this:
<value>v13772 #FBst0451145:w<up>1118</up>; P{GD3649}v13772#
v13773 #FBst0451146:w<up>1118</up>; P{GD3649}v13773#</value>
How can I process this string in XPATH to extract any and all #FBst####### numbers?
I know of the xpath matches() function... but that only returns true or false. No good if I want the matching string. I've searched around but cannot find a satisfactory answer to this problem, which is probably really common.
Thanks!
In addition to the good answer by Michael Kay, if you want to use only the replace() function, then use:
replace(.,'.*?(#FBst\d+).*','$1')
The result is:
#FBst0451145
#FBst0451146
And if you only want the numbers from the above result, use:
replace(replace(.,'.*?(#FBst\d+).*','$1'),
'[^0-9]+', ' ')
This produces:
0451145 0451146
I Assume you can also use XQuery. The get_matches() function from the FunctX module should work for you. Download the file which supports your version of XQuery. Then import the module whenever you need its functionality.
import module namespace functx = "http://www.functx.com" at "functx-1.0-doc-2007-01.xq";
functx:get-matches(string-join(//text()),'xyz')
Try
tokenize(value, '[^0-9]+')
which should return the sequence of tokens separated by sequences of non-digits.
With help from Dimitre, a working regex is:
replace(.,'.*?(#FBst\d+).*','$1 ','m')
Although it doesn't work unless a newline separates each target string, it will do for now.
Thanks everyone!

need to display char in xslt

Hi all
I am using xslt 1.0. I have the char code as FOA7 which has to displayed as a corresponding character. My input is
<w:sym w:font="Wingdings" w:char="F0A7"/>
my xslt template is
<xsl:template match="w:sym">
<xsl:variable name="char" select="#w:char"/>
<span font-family="{#w:fonts}">
<xsl:value-of select="concat('&#x',$char,';')"/>
</span>
</xsl:template>
It showing the error as ERROR: 'A decimal representation must immediately follow the "&#" in a character reference.'
Please help me in fixing this..Thanks in advance...
This isn't possible in (reasonable) XSLT. You can work around it.
Your solution with concat is invalid: XSLT is not just a fancy string-concatenator, it really transforms the conceptual tree. An encoded character such as  is a single character - if you were to somehow include the letters & # x f 0 a 7 ; then the XSLT processor would be required to include these letters in the XML data - not the string! So that means it will escape them.
There's no feature in XSLT 1.0 that permits converting from a number to a character with that codepoint.
In XSLT 2.0, as Michael Kay points out, you can use codepoints-to-string() to achieve this.
There are two solutions. Firstly, you could use disable-output-escaping. This is rather nasty and not portable. Avoid this at all costs if you can - but it will probably work in your transformer, and it's probably the only general, simple solution, so you may not be able to avoid this.
The second solution would be to hardcode matches for each individual character. That's a mess generally, but quite possible if you're dealing with a limited set of possibilities - that depends on your specific problem.
Finally, I'd recommend not solving this problem in XSLT - this is typically something you can do in pre/post processing in another programming environment more appropriately. Most likely, you've an in-memory representation of the XML document to be able to use XSLT in the first place, in which case this won't even take much CPU time.
<span font-family="{#w:font}">
<xsl:value-of select="concat('&#x', #w:char, ';')"
disable-output-escaping="yes"/>
</span>
Though check #Eamon Nerbonne's answer, why you shouldn't do it at all.
If you were using XSLT 2.0 (which you aren't), you could write a function to convert hex to decimal, and then use codepoints-to-string() on the result.
use '&' for '&' in output:
<xsl:value-of select="concat('&#x',$char,';')"/>

How do I substitute a parameter of an XML tag... using Regex?

Help how do I use regex to replace the value of param below
<?xml version="1.0" encoding="UTF-8" ?>
<games>
<game id="1001" path="C:\Program Files\Warcraft III\war3.exe" param="" display="1" priority="0"/>
</games>
the value of param is empty i wanted to add something to it using regex.
or replace the hole param="" with param="something"
and it has to be the first param after id="1001"
help.
i'm also using autohotkey so.. I don't know if you can just provide me a code to edit xml with autohotkey. :P but regex would do for this.
somebody provided me with this code
RegExReplace(xml,"s)id=""1001"".*?param=""\K[^""]+","HELLO WORLD!")
it works if the param has a value but it won't work if it doesn't.
how do i make it work.
You could use something like this, but you should consider using a proper XML parser instead, since this regex will easily fail in many cases:
s/(id="1001" [^>]*param=").*?"/$1something"/
You might be better off looking at an XML/HTML parsing engine here, assuming you are talking about XML/HTML params. Such engines are made for parsing and modifying this kind of content - regexes are not at all ideal for such work.
But it would help to know more about what you are dealing with, too; what's the environment? Is this HTML/XML data? Where are you modifying it? (client? server?) etc.
If the command you posted works as you said, then all you need to do is change the + to a *, like so:
RegExReplace(xml,"s)id=""1001"".*?param=""\K[^""]*","HELLO WORLD!")
+ means "one or more; * means "zero or more"

Element-in-List testing

For a stylesheet I'm writing (actually for a set of them, each generating a different output format), I have the need to evaluate whether a certain value is present in a list of values. In this case, the value being tested is taken from an element's attribute. The list it is to be tested against comes from the invocation of the stylesheet, and is taken as a top-level <xsl:param> (to be provided on the command-line when I call xsltproc or a Saxon equivalent invocation). For example, the input value may be:
v0_01,v0_10,v0_99
while the attribute values will each look very much like one such value. (Whether a comma is used to separate values, or a space, is not important-- I chose a comma for now because I plan on passing the value via command-line switch to xsltproc, and using a space would require quoting the argument, and I'm lazy-enough to not want to type the extra two characters.)
What I am looking for is something akin to Perl's grep, wherein I can see if the value I currently have is contained in the list. It can be done with sub-string tests, but this would have to be clever so as not to get a false-positive (v0_01 should not match a string that contains v0_011). It seems that the only non-scalar data-type that XSL/XSLT supports is a node-set. I suppose it's possible to convert the list into a set of text nodes, but that seems like over-kill, even compared to making a sub-string test with extra boundaries-checking to prevent false matches.
Actually, using XPath string functions is the right way to do it. All you have to make sure is that you test for the delimiters as well:
contains(concat(',' $list, ','), concat(',', $value, ','))
would return a Boolean value. Or you might use one of these:
substring-before(concat('|,' $list, ',|'), concat(',', $value, ','))
or
substring-after(concat('|,' $list, ',|'), concat(',', $value, ','))
If you get an empty string as the result, $value is not in the list.
EDIT:
#Dimitre's comment is correct: substring-before() (or substring-after()) would also return the empty string if the found string is the first (or the last) in the list. To avoid that, I added something at the start and the end of the list. Still contains() is the recommended way of doing this.
In addition to the XPath 1.0 solution provided by Tomalak,
Using XPath 2.0 one can tokenize the list of values:
exists(tokenize($list, ',')[. = $value])
evaluates to true() if and only if $value is contained in the list of values $list