Reputation: 5694
Is there a function in XSLT that can takes in a directory path and gives back all the files in it??
I have a xml file now reads like this
<filelist>
<file>fileA.xml</file>
<file>fileB.xml</file>
</filelist>
Now, there's directory called dir
, has files fileX.xml
, fileY.xml
and a bunch of other xml files in it. I want to add these files on to the orginal xml file, so that I can get:
<filelist>
<file>fileA.xml</file>
<file>fileB.xml</file>
<file>fileX.xml</file>
<file>fileY.xml</file>
.... <!-- other files -->
</filelist>
Is there an XSLT way to do this?? something that takes in a dir root, and is able to iterator through all of the files in it?? And then I could just call something like:
<xsl:element name = file >
<xsl:copy> <!--whatever file name--> <xsl:copy>
</xsl:element>0
all of the answers were very helpful. I ended up finding an external solution (using saxon). I thought it may be helpful for other people to post my solution here, although it is very specific to my own situation.
I use Ant to build a java web app and need to translate some xml files before deployment. Hence, I was using the xslt
task to do the job by adding the "saxon9.jar" in the classpath. And in my xsl file, I just did something like this:
<xsl:for-each select="collection('../dir/?select=*.xml')" >
<xsl:element name='file'>
<xsl:value-of select="tokenize(document-uri(.), '/')[last()]"/>
</xsl:element>
</xsl:for-each>
Upvotes: 21
Views: 21920
Reputation: 91
If you use a commercial version of Saxon, you can use file:list()
. This is an extension function from the EXPath File Module. See https://www.saxonica.com/html/documentation11/functions/expath-file/list.html for details. file:list()
delivers a sequence of strings, and you can do something like
<xsl:for-each select="file:list($path-to-dir, false())">
<file><xsl:value-of select="."/></file>
</xsl:for-each>
Upvotes: 0
Reputation: 1531
The Q is six years old and answered. Just throwing my 2 cents in for those who land here again.
I've needed an XML file representing the filenames in a directory. I've done it three ways:
XSLT 2.0 document() as others have pointed out in this thread. Drawback is performance as it reads the file into the dom parser, when all you really wanted is the name. Also as LarsH pointed out in the OP comments, this works only with valid XML files. If you have a non-xml or malformed xml file in the recurse, it crashes the transform.
The tool xmlstarlet with the command xmlstarlet ls > filenames.xml
A crude bash script I made up (it could be optimized):
DIRECTORY=$1 RESULTFILE=$2 # put the directory listing into a temp file # modify the ls command for your needs ls -A1 $DIRECTORY > /tmp/zFiles.txt # remove detritus and wrap the lines in <file> elements sed -i -e's/^[^$]*$/ <file filename="&"\/>/' /tmp/zFiles.txt # build the file echo '<?xml version="1.0" encoding="UTF-8"?>' > $RESULTFILE echo "<files>" >> $RESULTFILE cat /tmp/zFiles.txt >> $RESULTFILE echo "</files>" >> $RESULTFILE
I had used the bash script for a long time but now I use the xmlstarlet method exclusively. The result starlet file contains specific file attributes such as permissions and dates, I have found that helpful.
Upvotes: 1
Reputation: 338416
XSLT has nothing built-in for this task. XSLT is a transformation language - for dynamic output you generally need a transformation source that contains everything already (just in a different form) – you cannot create XML from nothing.
The three ways you can tackle the problem are:
It boils down to this:
Ergo: Don't use XSL for this.
Upvotes: 4
Reputation: 13772
You should be able to use the document() function to read the XML files in. I'm not sure how well it is supported on various XSLT engines though.
This is a good example showing it in use.
But that doesn't address the problem of reading in the names of the files from the directory. The other answer gives a way of doing that side of it.
Upvotes: 0
Reputation: 9816
You can't do that in native XSLT, but various implementations allow you to add extensions to the functionality.
For example, in C# you can add a user defined URN:
<xsl:stylesheet {snipped the usual xmlns stuff}
xmlns:user="urn:user" >
then use the functions within "user"
<xsl:value-of select="user:getdirectory( @mydir )" />
within the C# you associate "user" to a C# class:
XSLThelper xslthelper = new XSLThelper( ); // your class here
xslArgs.AddExtensionObject( "urn:user", xslthelper );
and your class defines the "getdirectory" function:
public class XSLThelper
{
public string getdirectory(System.Xml.XPath.XPathNavigator xml, string strXPath, string strNULL)
{
//blah
}
}
Hugh amount of homework left here! MSDN Resource
Upvotes: 1