Check if a file exists using xslt

Hi,

I am a novice in xslt and am using it for customizing my reports on selenium tool.

I would like to know a step by step method to be able to check if a file exists in a particular directory.  If it does then I will fill in a value fora particular column else the column will be left blank.

The key to getting the points is a detailed step by step procedure.
manajitAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

CEHJCommented:
Why would you try to use xslt for such a task? xslt is for document transformation
0
mccarlIT Business Systems Analyst / Software DeveloperCommented:
Unfortunately, this is not an easy thing to do or potentially not even possible at all, hence I agree with CEHJ that you should seriously think about other options too. However, in some (fairly specific) situations it may be possible...

If the files that you want to check existence for are ALL text files and the process that runs the XSLT has permission to "read" the file (ie. it's not enough to just be able to list a directories contents) you could do something like the following
XSLT
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text"/>
<xsl:template match="/">
	<xsl:for-each select="//file">
		<xsl:value-of select="@path" />
		<xsl:text>&#x09;&#x09;</xsl:text>
		<xsl:value-of select="unparsed-text-available(@path)" />
		<xsl:text>&#x0d;&#x0a;</xsl:text>
	</xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Open in new window

You would use this with an input XML like...
<filelist>
	<file path="file:///C:/Temp/IMG_0146.JPG" />
	<file path="file:///C:/Temp/IMG_0147.JPG" />
	<file path="file:///C:/Temp/IMG_0148.JPG" />
	<file path="file:///C:/Temp/test1.txt" />
	<file path="file:///C:/Temp/test2.txt" />
	<file path="file:///C:/Temp/test3.txt" />
</filelist>

Open in new window

If the file paths were not in this specific URI format, you would need to use xpath/xslt functions to manipulate the file path before calling uparsed-text-available. Note, when I run this on my system, the first two jpeg files DO exist but the output is still false because they are not text files. However, for the text files I get the correct output based on whether those files are in that directory or not.


If the above is no good for you but you are using an XSLT engine that supports extension functions (there are a few but I pretty much only use Saxon which I know does support them) you can setup an XSLT to be able to call Java functions and in this case you might be able to call the File.exists method (or a custom class method that you create) to determine whether the file exists. If this is potentially a solution, let us know the name and version of your XSLT engine and we can assist further. (I'm not providing any detail solution here just yet because that solution can vary widely based on what engine you are using)


A final possibility is that if you are only interested in determining the existence of files that AREN'T part of the input XML (ie. rather than having an XML like my example above, you only need to know the existence of a file that you know the name of BEFORE running the XSLT, you can determine whether that file exists using normal Java methods and then pass the result of that (true/false) into the XSLT as a parameter. Again the exact method of passing parameters may depend on the engine that you are using, so let us know the name/version and I can provide more info.
0
manajitAuthor Commented:
Thank you mccarl for the detailed explanation.  It gives me a much better understanding.

So,  I would like to use the extension functions. However, I may sound extremely stupid here but how do I find out the xslt engine which is being used?

I am using selenium 2.33 for automation testing and using junit 4 jar files. I am using ant version 1.99. I believe the xslt is used by junit for the transformation.  I am using xslt version 1.0. Could you help me know how to go about finding which xslt engine is being used or what is it dependent on.

Thanks.
0
Determine the Perfect Price for Your IT Services

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden with our free interactive tool and use it to determine the right price for your IT services. Download your free eBook now!

mccarlIT Business Systems Analyst / Software DeveloperCommented:
I may sound extremely stupid here but how do I find out the xslt engine which is being used?
No, that's not stupid at all. I find that this is one of the more confusing parts of Java and that is after working with it for years!

If you don't know than it is quite likely that you are using the in-built parser/transformer that comes with recent versions of Java itself and this is called Xerces/Xalan. The only way that you could be using a different version is if the implementation of a different parser is present on your classpath. So if you haven't purposefully used a different version (and any of the libraries that you are using haven't included other versions) you should be using the default in-built one. I haven't had any experience with Selenium so I can't say whether it does include it's own version of any particular parser.

Having said all that, there is probably only really two fairly common parsers in use, either the in-built Xerces/Xalan or the fairly popular Saxon, and so I would say that you are likely to be using one of the two. And after looking at the details, the comment I made earlier about things varyin widely is a bit off the mark because it isn't terribly different. Hence, what I have done is to get TWO solution, one for each version and you can then just try both and see which one works for you.

Firstly, with either version, calling of instance methods on objects is a little bit cumbersome because since XSLT isn't an OO language as such. Therefore, one way to make this a little bit more straightforward is to create a small helper class that has a static method that creates your object and calls the instance method on it. So, either of the below solution depend on this FileHelper class. (Note most of the details of this class are irrelevant as long as you match up those details with how this is called from the XSL file, it should be pretty self explanatory though)

FileHelper.java
package utils.files;
import java.io.File;

public class FileHelper {
    public static boolean isFileExists(String path) {
        return new File(path).exists();
    }
}

Open in new window


Also, both the below solution work based on the same input xml file (which is a little bit different to the example that I gave above, but hopefully it is closer to what you would already have in your input xml and so likely that you won't have to do any manipulation of the file path)
<filelist>
    <file path="C:\Temp\IMG_0146.JPG" />
    <file path="C:\Temp\IMG_0147.JPG" />
    <file path="C:\Temp\IMG_0148.JPG" />
    <file path="C:\Temp\test1.txt" />
    <file path="C:\Temp\test2.txt" />
    <file path="C:\Temp\test3.txt" />
</filelist>

Open in new window


Xerces/Xalan parser

The important points to note with the below;
Line 4 - the declaration of the "java" namespace prefix, which gives access to any Java class on the classpath
Line 5 - the exclude-result-prefixes (which is optional, it just cleans up the output if you are transforming to another xml file)
Line 11 - the format of the function call to call the static method on the FileHelper class
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" 
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
        xmlns:java="http://xml.apache.org/xalan/java" 
        exclude-result-prefixes="java">
<xsl:output method="text"/>
<xsl:template match="/">
    <xsl:for-each select="//file">
        <xsl:value-of select="@path" />
        <xsl:text>&#x09;&#x09;</xsl:text>
        <xsl:value-of select="java:utils.files.FileHelper.isFileExists(@path)" />
        <xsl:text>&#x0d;&#x0a;</xsl:text>
    </xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Open in new window


Saxon parser

The important points to note with the below;
Line 4 - the declaration of the "file" namespace prefix, which gives access to just that FileHelper class
Line 5 - the exclude-result-prefixes (which is optional, it just cleans up the output if you are transforming to another xml file)
Line 11 - the format of the function call to call the static method on the FileHelper class as defined in the namespace declaration
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" 
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
        xmlns:file="java:utils.files.FileHelper" 
        exclude-result-prefixes="file">
<xsl:output method="text"/>
<xsl:template match="/">
    <xsl:for-each select="//file">
        <xsl:value-of select="@path" />
        <xsl:text>&#x09;&#x09;</xsl:text>
        <xsl:value-of select="file:isFileExists(@path)" />
        <xsl:text>&#x0d;&#x0a;</xsl:text>
    </xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Open in new window



So they give two slightly different ways of calling Java code (and unfortunately they aren't compatible with each other). If neither of these two solutions work for you, can you post the full error messages/stack traces that you get and we can investigate further.
0
manajitAuthor Commented:
Thanks again for the detailed explanation.

However, I still continue with some issues.

I started with assuming that the engine is Xerces/Xalan parser.

We created the java code and compiled it.

Then I went on to change the declaration in my xsl to the following
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:lxslt="http://xml.apache.org/xslt"
    xmlns:redirect="http://xml.apache.org/xalan/redirect"
    xmlns:string="xalan://java.lang.String"
    extension-element-prefixes="redirect"
	xmlns:java="http://xml.apache.org/xalan/java"
	exclude-result-prefixes="java">
<xsl:output method="html" indent="yes" encoding="UTF-8"/>
<xsl:decimal-format decimal-separator="." grouping-separator=","/>

Open in new window


And made changes to the code as below
<xsl:when test="failure">	
			<xsl:if test="java:utils.files.FileHelper.isFileExists(string(concat('C:\ScreenShots\',@name,'.png')))">
				<td>
					<a title="Display Screen Shot" href="file://C:\ScreenShots\{@name}.png">
						<xsl:value-of select="@name" />
					</a>
				</td>
			</xsl:if>
        </xsl:when>

Open in new window


When I build it, I get the following error.
Buildfile: C:\Users\Nischitha\workspace\MediaGrid_TestSuite\build.xml

junitreport:
[junitreport] Processing C:\Users\Nischitha\workspace\MediaGrid_TestSuite\Report
s\TESTS-TestSuites.xml to C:\Users\NISCHI~1\AppData\Local\Temp\null112177962
[junitreport] Loading stylesheet C:\Users\Nischitha\workspace\MediaGrid_TestSuit
e\StyleDir\junit-frames.xsl
[junitreport] : Error! Cannot find class 'utils.files.FileHelper'.
[junitreport] : Error! Cannot find external method 'utils.files.FileHelper.isFil
eExists' (must be public).
[junitreport] : Error! Could not compile stylesheet
[junitreport] : Fatal Error! Could not compile stylesheet Cause: Cannot convert
data-type 'void' to 'boolean'.
[junitreport] Failed to process C:\Users\Nischitha\workspace\MediaGrid_TestSuite
\Reports\TESTS-TestSuites.xml

BUILD FAILED
C:\Users\Nischitha\workspace\MediaGrid_TestSuite\build.xml:120: Errors while app
lying transformations: Fatal error during transformation using C:\Users\Nischith
a\workspace\MediaGrid_TestSuite\StyleDir\junit-frames.xsl: Could not compile sty
lesheet

Open in new window


Can you please tell me, where is the problem and where does it actually look for the java file. Do let me know if you need any further information from my side.

Thanks.
0
manajitAuthor Commented:
Next, I also assumed that the engine may be Saxon parser.

The java code remained the same.

I changed the declaration to the following
<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:lxslt="http://xml.apache.org/xslt"
    xmlns:redirect="http://xml.apache.org/xalan/redirect"
    xmlns:string="xalan://java.lang.String"
    extension-element-prefixes="redirect"
    xmlns:file="java:utils.files.FileHelper"
    exclude-result-prefixes="file">
<xsl:output method="html" indent="yes" encoding="UTF-8"/>
<xsl:decimal-format decimal-separator="." grouping-separator=","/>

Open in new window


And changed the code to
        <xsl:when test="failure">   
            <xsl:if test="file:isFileExists(string(concat('c:\ScreenShots\',@name,'.png')">
                <td>
                    <a title="Display Screen Shot" href="file://C:\ScreenShots\{@name}.png">
                        <xsl:value-of select="@name" />
                    </a>
                </td>
            </xsl:if>
        </xsl:when>

Open in new window


However, I get an error
C:\Users\Nischitha\workspace\MediaGrid_TestSuite>ant junitreport
Buildfile: C:\Users\Nischitha\workspace\MediaGrid_TestSuite\build.xml

junitreport:
[junitreport] Processing C:\Users\Nischitha\workspace\MediaGrid_TestSuite\Report
s\TESTS-TestSuites.xml to C:\Users\NISCHI~1\AppData\Local\Temp\null1533298108
[junitreport] Loading stylesheet C:\Users\Nischitha\workspace\MediaGrid_TestSuit
e\StyleDir\junit-frames.xsl
[junitreport] : Error! The first argument to the non-static Java function 'isFil
eExists' is not a valid object reference.
[junitreport] : Error! Could not compile stylesheet
[junitreport] : Fatal Error! Could not compile stylesheet Cause: Cannot convert
data-type 'void' to 'boolean'.
[junitreport] Failed to process C:\Users\Nischitha\workspace\MediaGrid_TestSuite
\Reports\TESTS-TestSuites.xml

BUILD FAILED
C:\Users\Nischitha\workspace\MediaGrid_TestSuite\build.xml:120: Errors while app
lying transformations: Fatal error during transformation using C:\Users\Nischith
a\workspace\MediaGrid_TestSuite\StyleDir\junit-frames.xsl: Could not compile sty
lesheet

Total time: 0 seconds

Open in new window


Any further help will be appreciated. :)
0
mccarlIT Business Systems Analyst / Software DeveloperCommented:
Ok, so you are using the Xerces/Xalan parser and transformer. The error message in the first post is the clue... Error! Cannot find class 'utils.files.FileHelper'. As I mentioned, the compiled class file for that class needs to be on the classpath of the JVM that is running the tests. It is a bit hard to see from my limited view of your environment, but it looks as though you are using Ant to manage building/running of these tests, is that true? Also, do you have other Java code that is in this "MediaGrid_TestSuite" project or is it just files that drive the running of the Selenium tests?

If the code is already being compiled by Ant than maybe all you need is to add a directive inside Ant's build.xml file to add a required directory to the classpath for running these tests. Sorry, it is a little hard to be exact in my help because I don't have your whole setup in front of me. If the above instruction aren't of much help for you, you could start by sending me the directory/subdirectory layout of your project (so I can get a feel for what type of files are where) and if you can post your "build.xml" file (and any other files that it includes/imports) so that I can see how it is being executed.
0
manajitAuthor Commented:
Yes, we are using ant to build the tests.
The tests are a part of the MediaGridTest package and all the java files are in the same package.

We also tried to change the package of the FileHelper, however, the issue remains the same that the xsl is not able to find this class/method.

I am attaching the build.xml which is used by ant and the directory structure as well.

Hope it helps you help me. :-)
Build.xml
directory.txt
0
mccarlIT Business Systems Analyst / Software DeveloperCommented:
Ok, well I think the problem is that the "junitreport" task in that build.xml file doesn't get executed with the same classpath as the other tasks. I'm not a big user of Ant (I use Maven myself) so rather than funbling around to try and fix that here is another way. Remember that I mentioned how the FileHelper class would make things easier? It is probably making things harder now, so get rid of that (ie. you can delete all FileHelper.java and FileHelper.class files from your project) and then you can use the following XSLT file...
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" 
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
        xmlns:file="xalan://java.io.File" 
        exclude-result-prefixes="file">
<xsl:output method="text"/>
<xsl:template match="/">
    <xsl:for-each select="//file">
        <xsl:value-of select="@path" />
        <xsl:text>&#x09;&#x09;</xsl:text>
        <xsl:value-of select="file:exists(file:new(@path))" />
        <xsl:text>&#x0d;&#x0a;</xsl:text>
    </xsl:for-each>
</xsl:template>
</xsl:stylesheet>

Open in new window

Note the changes...
On line 4, I use a slightly different way of declaring the namespace (Xalan actually has a number of ways of doing this, and for whatever reason the way I first showed didn't work when I changed the next bit)
On line 11, we are now calling an instance method (rather than a static class method) and this is the syntax, the first parameter to the instance method call has to be a constructed object of that class. In this case the exists() method normally has NO parameters, so the one parameter here is the File object to call the method against. So, the inner part of that expression create a new java.io.File object that is constructed using the value of the @path attribute, and then the outer part of that expression calls the exists() method on that object.

(Actually, in the end this was a bit easier than I was expecting, I didn't know that you could combine those two function calls, new and exists, in the one expression. I learn something new everyday!)
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
manajitAuthor Commented:
One of the most patient and persistent expert I have come across.
0
mccarlIT Business Systems Analyst / Software DeveloperCommented:
Your welcome, and thank you for your kind comments, much appreciated! :)
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Programming

From novice to tech pro — start learning today.