How to dynamically fetch value from url in XSLT - url

I have a url of type C:/Documents and Settings/Saxon/output1/index.html?value=65abc
Now i need to fetch this part from url '65abc' in my xslt. I am getting this value from the previous page when click on a link.
Any idea of how to do it?

Use:
substring-after($pPath, '=')
where $pPath is a reference to the global external xsl:param that contains the value of the url-like) file path, passed from the invoker of the transformation.
In case that pPath contains more than one query-string parameter and you want to access the value of first one, then use:
substring-after(substring-before(substring-after($pPath, '?'), '&'), '=')
If you are using XSLT 2.0 (XPath 2.0), then you can access the value of the the query-string-parameter named $pQName using:
substring-after
(tokenize(substring-after($pPath, '?'), '&')
[starts-with(., concat($pQName, '='))],
'='
)
Here are complete code examples:
The simplest case:
. . .
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:param name="pPath" select=
"'C:/Documents and Settings/Saxon/output1/index.html?value=65abc'"/>
<xsl:template match="node()|#*">
<xsl:sequence select="substring-after($pPath, '=')"/>
</xsl:template>
</xsl:stylesheet>
when this is applied on any XML document (not used), the wanted result is produced:
65abc
.2. When this transformation is performed on any XML document (not used):
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:param name="pPath" select=
"'C:/Documents and Settings/Saxon/output1/index.html?value=65abc&x=1&y=2'"/>
<xsl:param name="pQName" select="'x'"/>
<xsl:template match="node()|#*">
<xsl:sequence select=
"substring-after
(tokenize(substring-after($pPath, '?'), '&')
[starts-with(., concat($pQName, '='))],
'='
)"/>
</xsl:template>
</xsl:stylesheet>
the wanted string (the value for the query-string parameter named x) is produced:
1

Related

Merging and inheriting parameters

Using xslt version 3.0 (saxon):
I have something like the following
<root>
<template ID='1'>
<params>
<a>1</a>
<b>1</b>
</params>
</template>
<document1 templateID='1'>
<params>
<b>4</b>
<c>5</c>
</params>
</document1>
</root>
Basicly I need to convert into something like
<root>
<document1 templateID='1'>
<params>
<a>1</a>
<b>4</b>
<c>5</c>
</params>
</document1>
</root>
In the example parameter a is inherited from the template while parameter b is overwritten by the document itself and parameter c is not known or set in the template. It is akin to inheritance or how css work. I hope you get the idea. Before starting the task I thought this should not be too difficult (and still hoping Im just overlooking something).
I have tried something with concat'ing the two nodeset (using nodeset1 , nodeset2 to preserve the order) and using a preceding-sibling name based 'select'/'filtering' - but this strategy seems not to work as it seems they are not actual siblings. Could this be done with a clever group-by ? Can it be done at all ? (I think it can)
I am using xslt version 3.0 (saxon)
I think you want to group or merge, merging in XSLT 3 would be
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">
<xsl:output indent="yes"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:key name="template-by-id" match="template" use="#ID"/>
<xsl:template match="template"/>
<xsl:template match="*[#templateID]/params">
<xsl:copy>
<xsl:merge>
<xsl:merge-source name="template" select="key('template-by-id', ../#templateID)/params/*">
<xsl:merge-key select="string(node-name())"/>
</xsl:merge-source>
<xsl:merge-source name="doc" select="*">
<xsl:merge-key select="string(node-name())"/>
</xsl:merge-source>
<xsl:merge-action>
<xsl:copy-of select="(current-merge-group('doc'), current-merge-group('template'))[1]"/>
</xsl:merge-action>
</xsl:merge>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/jyH9rN8/
grouping would be
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="#all"
version="3.0">
<xsl:output indent="yes"/>
<xsl:mode on-no-match="shallow-copy"/>
<xsl:key name="template-by-id" match="template" use="#ID"/>
<xsl:template match="template"/>
<xsl:template match="*[#templateID]/params">
<xsl:copy>
<xsl:for-each-group select="key('template-by-id', ../#templateID)/params/*, *" group-by="node-name()">
<xsl:copy-of select="head((current-group()[2], .))"/>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/jyH9rN8/1
I think, as xsl:merge requires input to be sorted on any merge key or to sort the input first, the grouping above is easier and more reliable, unless your params child elements are really named with sorted letters or words from the alphabet.

Exponent or power calculation in saxon9HE

Please suggest how to do math functions like power in XSLT2 with Saxon 9HE.
Getting following error:
Cannot find a matching 2-argument function named {http://exslt.org/math}power()
XML:
<root><num>12.3</num></root>
XSLT 2.0:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
xmlns:math="http://exslt.org/math"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
extension-element-prefixes="exsl math">
<xsl:output method="text" encoding="UTF-8"/>
<xsl:strip-space elements="*"/>
<!--1/(1+e^(-t))--><!-- this is required formula -->
<xsl:template match="num">
<xsl:variable name="varE"><xsl:value-of select="."/></xsl:variable>
<xsl:variable name="varT"><xsl:text>0.718</xsl:text></xsl:variable>
<xsl:variable name="varPower">
<xsl:value-of select="1 div (1 + math:power(number($varE), number(-$varT)))"/>
</xsl:variable>
<xsl:value-of select="$varPower"/>
</xsl:template>
</xsl:stylesheet>
There are XPath standardized math functions like math:pow e.g. math:pow(2, 4) in the namespace https://www.w3.org/2005/xpath-functions/math e.g with the namespace declaration xmlns:math="http://www.w3.org/2005/xpath-functions/math" available in all editions of Saxon (at least with 9.8 but I think it also works with earlier version like 9.7 and 9.6 (documentation http://saxonica.com/html/documentation9.6/functions/math/pow.html says since 9.6 in all editions).

tokenize with delimeter inside and outside of a string with xslt 2.0

I do have an input with randon values in parentheses,square brackets,Curly brackets and values outside brackets.Any type of bracket can occur in any randam position, where all are seperated by delimeter comma.
I have used <xsl:for-each select="tokenize(test,',')">
but as comma is present both inside and outside of brackets. It became impossible to achieve desired output. Please help me out
for example
INPUT
<test>{ST456,PT154},[GH456,JH768],(HJ789,KY456),GH789,PI345</test>
Desired OUTPUT
<test>{ST456,PT154}</test>
<test>[GH456,JH768]</test>
<test>(HJ789,KY456)</test>
<test>GH789</test>
<test>PI345</test>
You can use the xsl:analyze-string element in XSLT 2 or in XSLT 3 the same element or instead the analyze-string function, as in
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fn="http://www.w3.org/2005/xpath-functions"
expand-text="yes"
exclude-result-prefixes="xs fn"
version="3.0">
<xsl:param name="regex-pattern" as="xs:string" expand-text="no">\[([^\]]+)\]|\{([^\}]+)\}|\(([^)]+)\)|([^,]+)</xsl:param>
<xsl:output indent="yes"/>
<xsl:template match="test">
<xsl:apply-templates select="analyze-string(., $regex-pattern)//fn:group"/>
</xsl:template>
<xsl:template match="fn:group">
<test>{.}</test>
</xsl:template>
</xsl:stylesheet>
Online sample is at https://xsltfiddle.liberty-development.net/6qVRKw9, for XSLT 2 you would simply use an xsl:analyze-string element with the same pattern and then remove leading or trailing braces:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
expand-text="yes"
exclude-result-prefixes="xs"
version="2.0">
<xsl:param name="regex-pattern" as="xs:string" expand-text="no">\[([^\]]+)\]|\{([^\}]+)\}|\(([^)]+)\)|([^,]+)</xsl:param>
<xsl:output indent="yes"/>
<xsl:template match="test">
<xsl:analyze-string select="." regex="{$regex-pattern}">
<xsl:matching-substring>
<test>
<xsl:value-of select="replace(., '^[\[\{\(]|[\}\]\)]$', '')"/>
</test>
</xsl:matching-substring>
</xsl:analyze-string>
</xsl:template>
</xsl:stylesheet>
https://xsltfiddle.liberty-development.net/6qVRKw9/1

Identify values that dont match in all Nodes and Attributes: XSLT2.0

I need to go over all the xml attributes and text nodes to identify existence of character from list and output the values the characters values that didnt match.
I am able to check the text() nodes but I am not able to perform a check on attributes.
<xsl:template match="#*|node()">
<xsl:variable name="getDelimitersToUseNodes" select="('$' ,'#' ,'*' ,'~')[not(contains(current(),.))]"/>
<xsl:variable name="getDelimitersToUseAttr" select="string-join(('$','#','*','~')[not(contains(#*/,.))],',')"/>
<xsl:variable name="getDelimitersToUse" select="concat(string-join($getDelimitersToUseNodes,','),',',string-join($getDelimitersToUseAttr,','))"/>
<!--xsl:variable name="delim" select="distinct-values($getDelimitersToUse,',')"/-->
<xsl:value-of select="$getDelimitersToUse"/>
</xsl:template>
My mocked up sample file is below
<?xml version="1.0"?>
<sample>
<test1 name="#theGoofy">My$#test</test1>
<test2 value="$##">description test2*</test2>
</sample>
You could process all those text and attribute nodes and make that same check as before. You haven't really said which output format you want, assuming text you could use
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:param name="characters" as="xs:string*" select="'$' ,'#' ,'*' ,'~'"/>
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:apply-templates select="//text() | //#*"/>
</xsl:template>
<xsl:template match="text() | #*">
<xsl:value-of select="'Text', ., 'does not contain', $characters[not(contains(current(), .))], '
'"/>
</xsl:template>
</xsl:stylesheet>
to get a result like
Text #theGoofy does not contain $ * ~
Text My$#test does not contain * ~
Text $## does not contain * ~
Text description test2* does not contain $ # ~
If you simply want to check all characters not contained in all text nodes and attribute nodes then an approach like
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xsl:param name="characters" as="xs:string*" select="'$' ,'#' ,'*' ,'~'"/>
<xsl:output method="text"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="nodes-to-inspect" as="node()*" select="//text() | //#*"/>
<xsl:template match="/">
<xsl:value-of select="for $c in $characters return $c[not($nodes-to-inspect[contains(., $c)])]"/>
</xsl:template>
</xsl:stylesheet>
should do.

XSLT: output " without it being parsed

I am trying to achieve the following XML output:
<Foo bar=""" />
My XSLT file is as follows:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:template match="/">
<xsl:variable name="quote">
<xsl:text>"</xsl:text>
</xsl:variable>
<Foo bar="{$quote}"/>
</xsl:template>
</xsl:stylesheet>
Unfortunately, this gives me the output:
<Foo bar="""/>
How do I alter my XSLT to output & quot; without it being parsed into either a " character or a & #34;?
Ian Roberts has already made the very good point that it doesn't actually matter. But if you really, really wanted to do this, then in XSLT 2.0 (but not XSLT 1.0) you could make use of a character map, like so:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:output method="xml" use-character-maps="quotes" />
<xsl:character-map name="quotes">
<xsl:output-character character=""" string="&quot;" />
</xsl:character-map>
<xsl:template match="/">
<xsl:variable name="quote">
<xsl:text>"</xsl:text>
</xsl:variable>
<Foo bar="{$quote}"/>
</xsl:template>
</xsl:stylesheet>

Resources