I'm trying to convert a csv file into a xml file with Saxon 9.
But I have a problem when I try to check existence and read a csv file with the xslt functions:
unparsed-text-available(),
unparsed-text()
They work fine with a local file, but when I pass a remote file as parameter, unparsed-text-available() return false.
For example,
when I pass "D:\test\test.csv", it works.
when I pass "\\remote-computer\test\test.csv", it cannot find it.
Here is a part of my xsl file:
<xsl:template match="/" name="main">
<xsl:choose>
<xsl:when test="unparsed-text-available($pathToCSV)">
<xsl:variable name="csv" select="unparsed-text($pathToCSV)"/>
....
</xsl:when>
<xsl:otherwise>
<xsl:text>Cannot locate : </xsl:text><xsl:value-of select="$pathToCSV"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
It seems that document() can read remote file, but only for xml files.
Do you know some other functions that I can use for this case? In xslt or saxon?
You'll have to turn that path into a valid URI.
Something like:
unparsed-text(concat('file://',translate($pathToCSV,'\','/')))
Related
I am trying to use XSL choose condition. here I am trying to acheive is, when client sends below xml to Dp System. My XSLT should look for values matching Pv(a) or Pv(b) or Pv(c), if any of these are mactched then send to the backend url which is mentioned in the xsl
else
invoke another rule which is called "Do not call rule" (which is nothing but, picks the local file called error.xml
Thanks for the help
Input xml
<DownloadProfileChannels>
<DownloadProfileChannel>
<IntervalLength>60</IntervalLength>
<PulseMultiplier>0.025</PulseMultiplier>
<Category>Pv(a)</Category> <!-- for every Pv(a) or Pv(b) or Pv(c) -->
<TimeDataEnd>2014-02-20T08:00:00Z</TimeDataEnd>
<MedianValues>
<MedianValue>
<ChannelValue>9112</ChannelValue>
<ProfileStatuses i:nil="true" />
</MedianValue>
<MedianValue>
<ChannelValue>9096</ChannelValue>
<ProfileStatuses i:nil="true" />
</MedianValue>
<MedianValue>
<ChannelValue>9188</ChannelValue>
<ProfileStatuses i:nil="true" />
</MedianValue>
</MedianValue>
</MedianValues>
</DownloadProfileChannel>
</DownloadProfileChannels>
My XSL
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:dp="http://www.w3.org/1999/XSL/Format">
<xsl:template match="/">
<xsl:message dp:priority="debug"> Entered the XSL File </xsl:message>
</xsl:message>
<xsl:choose>
<xsl:when test="contains($Quantity,'Pv(a) or Pv(b)')">
<xsl:variable name="destURL"
select="http://backendurl.com"/>
<dp:set-variable name="'var://service/routing-url'"
value="$destURL"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="destURL"
select="local:///clienterror.xml"/>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
This line:
<xsl:when test="contains($Quantity,'Pv(a) or Pv(b)')">
Is checking if $Quantity contains the literal string 'Pv(a) or Pv(b)'. You need to separate these out into two check like so:
<xsl:when test="contains($Quantity,'Pv(a)') or contains($Quantity,'Pv(b)')">
Firstly, as #Lego Stormtroopr says, you need to separate out the two conditions. But also, I don't think you really want a "contains" test here, you want an "=" test. The contains function would match Pv(a)(b)(c) - anything that has Pv(a) as a substring, whereas I think you want to match the whole node. So it becomes
<xsl:when test="$Quantity = 'Pv(a)' or $Quantity ='Pv(b)'">
which, if you are using XSLT 2.0, can be further abbreviated to
<xsl:when test="$Quantity = ('Pv(a)', 'Pv(b)')">
Alternatively, in XSLT 2.0 you can use regular expression matching:
<xsl:when test="matches($Quantity, 'Pv([ab])')">
I have in an input file:
<a></a>
<b/>
<c>text</c>
I need to converting this to string. Using transformer I am getting below output:
<a/> <!-- Empty tags should not collapse-->
<b/>
<c>text</c>
If I use xslt and output method is "HTML", I get the below output:
<a></a> <!-- This is as expected-->
<b></b> <!-- This is not expected-->
<c>text</c>
I want the structure same as in input file. It is required in my application since I need to calculate index and it will be very difficult to change the index calution logic.
What would be the correct XSLT to use?
What XSLT processor? XSLT is merely a language to transform xml so "html output" is dependent on the processor.
I'm going to guess this first solution is too simple for you but i've had to use this to avoid processing raw html
<xsl:copy-of select="child::node()" />
as this should clone the raw input.
In my case, I have used the following to extract all nodes that had the raw attribute:
<xsl:for-each select="xmlData//node()[#raw]">
<xsl:copy-of select="child::node()" />
</xsl:for-each>
Other options:
2) Add an attribute to each empty node depending on what you want it to do later ie role="long", role="short-hand".
3)
Loop through each node (xsl:for-each)
<xsl:choose>
<xsl:when test="string-length(.)=0"> <!-- There is no child-->
<xsl:copy-of select="node()" />
</xsl:when>
<xsl:otherwise>
...whatever normal processing you have
</xsl:otherwise>
4) Redefine your problem. Both are valid XHTML/XML, so perhaps your problem can be reframed or fixed elsewhere.
Either way, you may want to add more information in your question so that we can reproduce your problem and test it locally.
P.S. Too much text/code to put in a comment, but that's where this would belong.
A possible alternative is to use disable-output-escaping like this:
<xsl:text disable-output-escaping="yes"><a></a></xsl:text>
But I understand that this is a dirty solution...
I have the following test code... I am trying to pass a node-set as a param. After many hours, i finally was able to pass it to my template.
How I pass my node-set to the template:
<xsl:call-template name="listing">
<xsl:with-param name="customData">
<xsl:apply-templates select="exslt:node-set($data)"/>
</xsl:with-param>
</xsl:call-template>
How my template receives it:
<xsl:template name="listing">
<xsl:param name="customData" select="/.."/>
<xsl:variable name="data">
<xsl:choose>
<xsl:when test="not($customData)">
<xsl:value-of select="/data"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$customData"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<textarea><xsl:copy-of select="$data"></xsl:copy-of></textarea>
</xsl:call-template>
If I set the parameters with a one liner, then it would not complain... example:
<xsl:variable name="data" select="$customData"/>
But as soon as I try to set it like this, it breaks:
<xsl:variable name="data">
<xsl:value-of select="$customData"/>
</xsl:variable>
Getting this error message:
org.apache.xpath.objects.XRTreeFrag cannot be cast to org.apache.xpath.objects.XNodeSet
I was only been able to find another thread dated back in 2000, talk about this similar issue... I need to re-nodeset it back using something like node-set($customData)/* but I tried that, and it was a no go.
EDIT:
OK, I can confirm that I successfully passed the node-set inside my template. But I'm still unable to copy it over to my variable... It kept saying that it is still a RTF.
<xsl:template name="listing">
<xsl:param name="customData" as="node-set"/>
<!--<xsl:variable name="data" select="/data"/>-->
<xsl:variable name="data">
<xsl:choose>
<xsl:when test="count($customData) != 0">
<xsl:copy-of select="$customData"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="/data"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<textarea><xsl:value-of select="$customData/record[1]"/></textarea>
<textarea><xsl:value-of select="/data/record[1]"/></textarea>
<textarea><xsl:value-of select="$data/record[1]"/></textarea>
</xsl:template>
The above test, shows that I can access $customData and the original /data without any problem, they both show the record... but $data is messed up. So that means the copy from $customData to $data wasn't working...
I tried the following ways, none of them work:
<xsl:copy-of select="$customData"/>
<xsl:value-of select="$customData"/>
<xsl:apply-templates select="exslt:node-set($customData)"/>
<xsl:apply-templates select="exslt:node-set($customData)/data"/>
Any idea...?
This error message comes from Xalan, which is an XSLT 1.0 processor. If you are using Xalan, then you are probably using Java, which means there is really no reason at all not to move to XSLT 2.0 in the form of Saxon. You will find that XSLT 2.0 removes many of the restrictions of XSLT 1.0, of which this is one of the most irritating.
If there's a good reason why you can't move forward to XSLT 2.0 (and it's hard to think of one), there's a workaround in the form of the exslt:node-set() function, which converts a result-tree fragment (that is, a variable defined using child instructions) into a document node.
Got it working, basically rather than using apply-template, i need to pass the RTF as a parameter to the template. That is the only way I got it to work.
<xsl:with-param name="data" select="exslt:node-set($customData)"/>
Using this method, I was able to MODIFY data in XSL level. This is really cool, I basically manipulate the data I want, then i reconstruct the root /, and then I pass my customData to my template function.
So rather than reading data off the root, I read my own modified data (constructed inside XSL).
Use of exslt:node-set does indeed suppress the error message org.apache.xpath.objects.XRTreeFrag cannot be cast to org.apache.xpath.objects.XNodeSet
However, the node-set that is created for some reason cannot be used in subsequent XPath expressions; at least it doesn't seem to work with Xalan 2.6.0 / XSLT 1.0 which is the version many people are forced to use for one reason or another.
There is a simple solution: instead of setting the variable to a node-set, set it to the XPath expression instead. Then you can use the dyn:evaluate EXSLT function to evaluate the XPath expression held by the variable.
Your code would look something like this:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:dyn="http://exslt.org/dynamic"
extension-element-prefixes="dyn"
exclude-result-prefixes="dyn">
..
<xsl:variable name="data">
<xsl:choose>
<xsl:when test="count(.) != 0">
<xsl:text>.</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>/data</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<textarea>
<xsl:value-of select="dyn:evaluate($data)/record[1]"/>
</textarea>
I am using an XSL when clause to transform one XML file to another XML file. I need to use something like an "exists" function in my when test.
Here's an example source XML:
<People>
<Person personid="1" location="US" fullname="John Doe"/>
<Person personid="2" location="US" fullname="Jane Doe"/>
</People>
<Nicknames>
<Nickname personid="1" nname="Johnny D"/>
</Nicknames>
Here's my example XSL:
<xsl:element name="HASNICKNAME">
<xsl:choose>
<!-- If nickname exists in source XML, return true -->
<xsl:when test="boolean exists function"
<xsl:text>TRUE</xsl:text>
</xsl:when>
<xsl:otherwise>
<xsl:text>FALSE</xsl:text>
</xsl:otherwise>
</xsl:choose>
</xsl:element>
Can someone help with the exists part?
Suppose the variable $personid contains the #personid of the Person you are checking, then this only checks existence:
<xsl:when test="boolean(//Nickname[#personid=$personid]/#nname)">
For similar issues I normally prefer to check for a non-empty/non-whitespace value:
<xsl:when test="normalize-space(//Nickname[#personid=$personid]/#nname)!=''">
If you use a key like <xsl:key name="nn" match="//Nickname" use="#personid"/>, the following is also possible:
<xsl:when test="normalize-space(key('nn',$personid)/#nname)!=''">
The latter does not need the $personid variable but can directly work with the #personid of the Person you are checking…
I want to produce a newline for text output in XSLT. Any ideas?
The following XSL code will produce a newline (line feed) character:
<xsl:text>
</xsl:text>
For a carriage return, use:
<xsl:text>
</xsl:text>
My favoured method for doing this looks something like:
<xsl:stylesheet>
<xsl:output method='text'/>
<xsl:variable name='newline'><xsl:text>
</xsl:text></xsl:variable>
<!-- note that the layout there is deliberate -->
...
</xsl:stylesheet>
Then, whenever you want to output a newline (perhaps in csv) you can output something like the following:
<xsl:value-of select="concat(elem1,elem2,elem3,$newline)" />
I've used this technique when outputting sql from xml input. In fact, I tend to create variables for commas, quotes and newlines.
Include the attribute Method="text" on the xsl:output tag and include newlines in your literal content in the XSL at the appropriate points. If you prefer to keep the source code of your XSL tidy use the entity
where you want a new line.
You can use: <xsl:text>
</xsl:text>
see the example
<xsl:variable name="module-info">
<xsl:value-of select="#name" /> = <xsl:value-of select="#rev" />
<xsl:text>
</xsl:text>
</xsl:variable>
if you write this in file e.g.
<redirect:write file="temp.prop" append="true">
<xsl:value-of select="$module-info" />
</redirect:write>
this variable will produce a new line infile as:
commons-dbcp_commons-dbcp = 1.2.2
junit_junit = 4.4
org.easymock_easymock = 2.4
IMHO no more info than #Florjon gave is needed. Maybe some small details are left to understand why it might not work for us sometimes.
First of all, the 
 (hex) or 
 (dec) inside a <xsl:text/> will always work, but you may not see it.
There is no newline in a HTML markup. Using a simple <br/> will do fine. Otherwise you'll see a white space. Viewing the source from the browser will tell you what really happened. However, there are cases you expect this behaviour, especially if the consumer is not directly a browser. For instance, you want to create an HTML page and view its structure formatted nicely with empty lines and idents before serving it to the browser.
Remember where you need to use disable-output-escaping and where you don't. Take the following example where I had to create an xml from another and declare its DTD from a stylesheet.
The first version does escape the characters (default for xsl:text)
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" encoding="utf-8"/>
<xsl:template match="/">
<xsl:text><!DOCTYPE Subscriptions SYSTEM "Subscriptions.dtd">
</xsl:text>
<xsl:copy>
<xsl:apply-templates select="*" mode="copy"/>
</xsl:copy>
</xsl:template>
<xsl:template match="#*|node()" mode="copy">
<xsl:copy>
<xsl:apply-templates select="#*|node()" mode="copy"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
and here is the result:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE Subscriptions SYSTEM "Subscriptions.dtd">
<Subscriptions>
<User id="1"/>
</Subscriptions>
Ok, it does what we expect, escaping is done so that the characters we used are displayed properly. The XML part formatting inside the root node is handled by ident="yes". But with a closer look we see that the newline character 
 was not escaped and translated as is, performing a double linefeed! I don't have an explanation on this, will be good to know. Anyone?
The second version does not escape the characters so they're producing what they're meant for. The change made was:
<xsl:text disable-output-escaping="yes"><!DOCTYPE Subscriptions SYSTEM "Subscriptions.dtd">
</xsl:text>
and here is the result:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE Subscriptions SYSTEM "Subscriptions.dtd">
<Subscriptions>
<User id="1"/>
</Subscriptions>
and that will be ok. Both cr and lf are properly rendered.
Don't forget we're talking about nl, not crlf (nl=lf). My first attempt was to use only cr:
 and while the output xml was validated by DOM properly.
I was viewing a corrupted xml:
<?xml version="1.0" encoding="utf-8"?>
<Subscriptions>riptions SYSTEM "Subscriptions.dtd">
<User id="1"/>
</Subscriptions>
DOM parser disregarded control characters but the rendered didn't. I spent quite some time bumping my head before I realised how silly I was not seeing this!
For the record, I do use a variable inside the body with both CRLF just to be 100% sure it will work everywhere.
You can try,
<xsl:text>
</xsl:text>
It will work.
I added the DOCTYPE directive you see here:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE xsl:stylesheet [
<!ENTITY nl "
">
]>
<xsl:stylesheet xmlns:x="http://www.w3.org/2005/02/query-test-XQTSCatalog"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
This allows me to use &nl; instead of
to produce a newline in the output. Like other solutions, this is typically placed inside a <xsl:text> tag.
I second Nic Gibson's method, this was
always my favorite:
<xsl:variable name='nl'><xsl:text>
</xsl:text></xsl:variable>
However I have been using the Ant task <echoxml> to
create stylesheets and run them against files. The
task will do attribute value templates, e.g. ${DSTAMP} ,
but is also will reformat your xml, so in some
cases, the entity reference is preferable.
<xsl:variable name='nl'><xsl:text>
</xsl:text></xsl:variable>
I have found a difference between literal newlines in <xsl:text> and literal newlines using
.
While literal newlines worked fine in my environment (using both Saxon and the default Java XSLT processor) my code failed when it was executed by another group running in a .NET environment.
Changing to entities (
) got my file generation code running consistently on both Java and .NET.
Also, literal newlines are vulnerable to being reformatted by IDEs and can inadvertently get lost when the file is maintained by someone 'not in the know'.
I've noticed from my experience that producing a new line INSIDE a <xsl:variable> clause doesn't work.
I was trying to do something like:
<xsl:variable name="myVar">
<xsl:choose>
<xsl:when test="#myValue != ''">
<xsl:text>My value: </xsl:text>
<xsl:value-of select="#myValue" />
<xsl:text></xsl:text> <!--NEW LINE-->
<xsl:text>My other value: </xsl:text>
<xsl:value-of select="#myOtherValue" />
</xsl:when>
</xsl:choose>
<xsl:variable>
<div>
<xsl:value-of select="$myVar"/>
</div>
Anything I tried to put in that "new line" (the empty <xsl:text> node) just didn't work (including most of the simpler suggestions in this page), not to mention the fact that HTML just won't work there, so eventually I had to split it to 2 variables, call them outside the <xsl:variable> scope and put a simple <br/> between them, i.e:
<xsl:variable name="myVar1">
<xsl:choose>
<xsl:when test="#myValue != ''">
<xsl:text>My value: </xsl:text>
<xsl:value-of select="#myValue" />
</xsl:when>
</xsl:choose>
<xsl:variable>
<xsl:variable name="myVar2">
<xsl:choose>
<xsl:when test="#myValue != ''">
<xsl:text>My other value: </xsl:text>
<xsl:value-of select="#myOtherValue" />
</xsl:when>
</xsl:choose>
<xsl:variable>
<div>
<xsl:value-of select="$myVar1"/>
<br/>
<xsl:value-of select="$myVar2"/>
</div>
Yeah, I know, it's not the most sophisticated solution but it works, just sharing my frustration experience with XSLs ;)
I couldn't just use the <xsl:text>
</xsl:text> approach because if I format the XML file using XSLT the entity will disappear. So I had to use a slightly more round about approach using variables
<xsl:variable name="nl" select="'
'"/>
<xsl:template match="/">
<xsl:value-of select="$nl" disable-output-escaping="no"/>
<xsl:apply-templates select="*"/>
</xsl:template>
<xsl:text xml:space="preserve">
</xsl:text>
just add this tag:
<br/>
it works for me ;) .