2011-05-25 50 views
7

He creado un archivo XSLT que puede transformar un solo archivo XML. Sin embargo, tengo varios cientos de directorios con múltiples archivos xml. ¿Hay alguna forma en XSLT para transformar todos estos archivos? Estoy usando la función de recopilación para obtener una lista de todos los archivos. Pero no estoy seguro de cómo aplicar la transformación ahora.XSLT Transformar varios archivos desde el subdirectorio

Aquí está mi ejemplo de archivo XSLT. Básicamente, quiero recorrer todos los archivos xml y aplicar la tabla de plantillas en el archivo individual. El resultado de todas estas transformaciones debe estar en un solo archivo de texto plano.

<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> 
+0

¿Qué tipo de procesador XSLT está utilizando? Si está usando Saxon, puede hacerlo directamente desde la línea de comando. Saxon puede transformar lotes de archivos para los cuales desea aplicar la misma transformación. –

+0

Estaba usando un editor XSLT llamado EditX para construir mi XSLT y pensé que quizás podría ejecutarlo desde allí. Pero parece que necesito ejecutar esto desde otro lugar. Vi una tarea de hormiga para XSLT. ¿Eso funcionará? – user320587

+0

¿Con qué sistema operativo estás corriendo? –

Respuesta

7

Aquí es probablemente el ejemplo más simple la forma de procesar todos los archivos XML en un sub-árbol del sistema de archivos (utilizando la función collection() como se aplica en 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> 

cuando se aplica sobre cualquier documento XML (no utilizado, ignorado), esta transformación aplica la regla de identidad a cada documento XML contenido en cualquiera de los archivos *.xml en el subárbol C:/Temp del sistema de archivos.

Para hacer más procesamiento neaningful, hay que anular la plantilla de identidad - en el modo inFile.

En su caso específico Creo que se puede simplemente reemplazar:

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

con

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

y esto se aplica las plantillas deseadas en los nodos seleccionados de la corriente (documento) nodo.

+0

Recibo el error "La recopilación es una función xslt desconocida" cuando transformo esto en C#. Por favor, ayúdenme – shanmugharaj

+0

@shansfk, Sí, los motores XSLT que vienen con .NET no son compatibles con XSLT 2.0. La pregunta es cómo hacer esto en XSLT 2.0, como lo sugiere el código OP. Puede instalar y usar Saxon.NET y luego esta transformación producirá los resultados esperados. –

0

Solo quería agregar una versión liviana de la excelente respuesta de Dimitre. Si tiene <foo> documentos (nodo raíz) sentado en un directorio, y un programa de XSLT de trabajo para <foo>, simplemente que su plantilla de nivel superior como esto:

<xsl:template match="/"> 
    <xsl:apply-templates select="collection($my_url)/foo"/> 
</xsl:template> 

Eso suponiendo desea que la URL como un parámetro, <xsl:param name="my_url"/> , especificado en la línea de comando.

Cuestiones relacionadas