XSLT Transform multiple files from subdirectory

16,846

Here is probably the simplest example how to process all the xml files in a file system subtree (using the collection() function as implemented in Saxon):

<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:template match="node()|@*" mode="inFile">
     <xsl:copy>
       <xsl:apply-templates mode="inFile" select="node()|@*"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match="/">
   <xsl:apply-templates mode="inFile" select=
   "collection('file:///C:/temp?select=*.xml;recurse=yes')"/>
 </xsl:template>
</xsl:stylesheet>

When applied on any XML document (not used, ignored), this transformation applies the identity rule to every XML document contained in any of the *.xml files in the C:/Temp subtree of the file system.

To do more neaningful processing, one needs to override the identity template -- in the inFile mode.

In your specific case I believe you can simply replace:

            <xsl:apply-templates select="/testResults/result/tables/table[14]">     

with

            <xsl:apply-templates select="./testResults/result/tables/table[14]">    

and this applies the desired templates on the nodes selected off the current (document) node.

Share:
16,846
user320587
Author by

user320587

Updated on July 20, 2022

Comments

  • user320587
    user320587 almost 2 years

    I have created a XSLT file that can transform a single XML file. However, I have several hundred directories with multiple xml files. Is there a way in XSLT to transform all these files. I am using the collection function to get a list of all files. But, not sure how to apply the transform now.

    Here is my example XSLT file. Basically, I want to loop through all the xml files and apply the template table on the individual file. The output of all these transforms needs to be in one single flat text file.

    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:foo="http://whatever">
    
    <xsl:output method="text" encoding="ISO-8859-1"/>
        <xsl:template name="process">
            <xsl:variable name="files" select="collection('file:///C:/files/testResults?select=*.xml;recurse=yes')"/>
            <xsl:for-each select="$files">
                <xsl:if test="(not(contains(document-uri(.), 'SuiteSetUp'))) and (not(contains(document-uri(.), 'SuiteTearDown')))">
                    <xsl:value-of select="tokenize(document-uri(.), '/')[last()]"></xsl:value-of>
                    <xsl:apply-templates select="/testResults/result/tables/table[14]">
                        <xsl:with-param name="title" select="/testResults/rootPath"></xsl:with-param>
                    </xsl:apply-templates>
                    <xsl:apply-templates select="/testResults/result/tables/table[15]"/>
                </xsl:if>
            </xsl:for-each>
        </xsl:template>
    
        <xsl:template match="table">
        <xsl:param name="testName"></xsl:param>
            <xsl:for-each select="row">
                <xsl:if test="position() > 2">
                    <xsl:variable name="choices" select="col[2]"></xsl:variable>
                    <xsl:if test="contains($choices, 'fail')">
                        <xsl:value-of  select="$testName"></xsl:value-of>
                        <xsl:text>|</xsl:text>
                        <xsl:value-of select="col[1]"></xsl:value-of>
                        <xsl:text>|</xsl:text>
                        <xsl:value-of select="foo:getCorrectChoices(col[2])"></xsl:value-of>
                        <xsl:text>|</xsl:text>
                        <xsl:value-of select="foo:getExpectedChoices(col[2])"></xsl:value-of>
                        <xsl:text>|</xsl:text>
                        <xsl:call-template name="NewLine"/>
                    </xsl:if>
                </xsl:if>
            </xsl:for-each>
        </xsl:template>
    
        <xsl:template name="NewLine">
            <xsl:text>&#xA;</xsl:text>
        </xsl:template>
    
        <xsl:function name="foo:getCorrectChoices">
            <xsl:param name="content"></xsl:param>
            <xsl:analyze-string select="$content" regex="\[(\[.+?\])\] fail">
                <xsl:matching-substring>
                    <xsl:value-of select="regex-group(1)"></xsl:value-of>
                </xsl:matching-substring>
            </xsl:analyze-string>
        </xsl:function>
        <xsl:function name="foo:getExpectedChoices">
            <xsl:param name="content"></xsl:param>
            <xsl:analyze-string select="$content" regex="fail\(expected \[(\[.+?\])\]">
                <xsl:matching-substring>
                    <xsl:value-of select="regex-group(1)"></xsl:value-of>
                </xsl:matching-substring>
            </xsl:analyze-string>
        </xsl:function>
    </xsl:stylesheet>
    
  • shanmugharaj
    shanmugharaj almost 8 years
    I am getting error "Collection is an unknown xslt function" when I Transform this in C#. Please help me
  • Dimitre Novatchev
    Dimitre Novatchev almost 8 years
    @shansfk, Yes, the XSLT engines that come with .NET don't support XSLT 2.0. The question is how to do this in XSLT 2.0 -- as the provided by the OP code suggests. You can install and use Saxon.NET and then this transformation will produce the expected results.