XSLT para transformar un xml con hermanos repetidos en un archivo plano
-
29-10-2019 - |
Pregunta
Tengo un XML como el siguiente:
<?xml version="1.0" encoding="utf-8"?>
<GetSavedReportResponse>
<ResponseType>Success</ResponseType>
<FileModifiedDateTime>2012-01-03T17:05:04</FileModifiedDateTime>
<FileSizeBytes>7816</FileSizeBytes>
<FileDataFormat>XML</FileDataFormat>
<FileData>
<Zthes>
<term>
<termId>49555</termId>
<termUpdate>add</termUpdate>
<termName>Active Personnel</termName>
<termVocabulary>People Status Global</termVocabulary>
<termVocabulary>Global People Status</termVocabulary>
<termCategory>PDA</termCategory>
<termCategory>PDI</termCategory>
<termCategory>GLB</termCategory>
<relation weight="100">
<termId>49556</termId>
<relationType>EQ</relationType>
<termName>term name</termName>
<termVocabulary>term vocabulary</termVocabulary>
</relation>
<relation weight="100">
<termId>49557</termId>
<relationType>BT</relationType>
<termName>General Active Personnel</termName>
<termVocabulary>People Status Global Updated</termVocabulary>
</relation>
</term>
<term>
<termId>49556</termId>
<termUpdate>add</termUpdate>
<termName>Leave of Absence Personnel</termName>
<termVocabulary>People Status Global</termVocabulary>
<termCategory>GLB</termCategory>
<termCategory>PDI</termCategory>
<relation weight="100">
<relationType>BT</relationType>
<termId>49554</termId>
<termName>General Non-Active Personnel</termName>
<termVocabulary>People Status Global</termVocabulary>
</relation>
</term>
</Zthes>
</FileData>
</GetSavedReportResponse>
Necesito transformarlo en un archivo plano. Para eso, he escrito el siguiente xsl
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="text" />
<xsl:template match="Zthes">
<xsl:text> </xsl:text>
<xsl:for-each select="term">
<xsl:text>"</xsl:text>
<xsl:text>GL</xsl:text>
<xsl:text>"</xsl:text>
<xsl:text>;</xsl:text>
<xsl:text>"</xsl:text>
<xsl:for-each select="termCategory">
<xsl:value-of select="." />
</xsl:for-each>
<xsl:text>"</xsl:text>
<xsl:text>;</xsl:text>
<xsl:text>"</xsl:text>
<xsl:for-each select="termVocabulary">
<xsl:value-of select="." />
</xsl:for-each>
<xsl:text>"</xsl:text>
<xsl:text>;</xsl:text>
<xsl:text>"</xsl:text>
<xsl:for-each select="relation/termVocabulary">
<xsl:value-of select="." />
</xsl:for-each>
<xsl:text>"</xsl:text>
<xsl:text> </xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
entonces, la salida debería ser
"HDR"; "Texto"; "20120112045620"; "F"
"GL"; "PDA"; "People Status Global"; "vocabulario de términos"
"GL"; "PDA"; "Estado de personas global"; "Estado de personas global actualizado"
"GL"; "PDA"; "Estado global de las personas"; "vocabulario de términos"
"GL"; "PDA"; "Estado global de personas"; "Estado global de personas actualizado"
"GL"; "PDI"; "People Status Global"; "vocabulario de términos"
"GL"; "PDI"; "Estado de la gente global"; "Estado de la gente global actualizado"
"GL"; "PDI"; "Estado global de las personas"; "vocabulario de términos"
"GL"; "PDI"; "Estado global de personas"; "Estado global de personas actualizado"
"GL"; "GLB"; "People Status Global"; "vocabulario de términos"
"GL"; "GLB"; "Estado de personas global"; "Estado de personas global actualizado"
"GL"; "GLB"; "Estado global de personas"; "vocabulario de términos"
"GL"; "GLB"; "Estado global de personas"; "Estado global de personas actualizado"
"FTR"; 12
con mi xsl obtengo una sola fila:
"GL"; "PDAPDIGLB"; "Estado global de la gente Estado global de la gente"; "vocabulario de términos Estado global de la gente actualizado"
Y una fila de encabezado:
"HDR"; "PIGLSSTD"; "20120112045620"; "F":
debe agregarse al principio, junto con una fila de pie de página
"FTR";
en la parte inferior.
Solución
Quieres algo como esto :
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:my="my:my">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<my:defaults>
<termCat/>
<termVocab/>
</my:defaults>
<xsl:variable name="vDefaults" select="document('')/*/my:defaults"/>
<xsl:variable name="vQ">"</xsl:variable>
<xsl:template match="term">
<xsl:variable name="vTerm" select="."/>
<xsl:variable name="vRow1" select="'
"GL";'"/>
<xsl:for-each select=
"termCategory
|
$vDefaults/termCat[not($vTerm/termCategory)]">
<xsl:variable name="vRow2" select=
"concat($vRow1, $vQ, ., $vQ, ';')"/>
<xsl:for-each select=
"$vTerm/termVocabulary
|
$vDefaults/termCat[not($vTerm/termVocabulary)]
">
<xsl:variable name="vRow3" select=
"concat($vRow2, $vQ, ., $vQ, ';')"/>
<xsl:for-each select=
"$vTerm/relation/termVocabulary
|
$vDefaults/termCat[not($vTerm/relation/termVocabulary)]
">
<xsl:value-of select="concat($vRow3, $vQ, ., $vQ, ';')"/>
</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>
cuando esta transformación se aplica en el documento XML proporcionado :
<GetSavedReportResponse>
<ResponseType>Success</ResponseType>
<FileModifiedDateTime>2012-01-03T17:05:04</FileModifiedDateTime>
<FileSizeBytes>7816</FileSizeBytes>
<FileDataFormat>XML</FileDataFormat>
<FileData>
<Zthes>
<term>
<termId>49555</termId>
<termUpdate>add</termUpdate>
<termName>Active Personnel</termName>
<termVocabulary>People Status Global</termVocabulary>
<termVocabulary>Global People Status</termVocabulary>
<termCategory>PDA</termCategory>
<termCategory>PDI</termCategory>
<termCategory>GLB</termCategory>
<relation weight="100">
<termId>49556</termId>
<relationType>EQ</relationType>
<termName>term name</termName>
<termVocabulary>term vocabulary</termVocabulary>
</relation>
<relation weight="100">
<termId>49557</termId>
<relationType>BT</relationType>
<termName>General Active Personnel</termName>
<termVocabulary>People Status Global Updated</termVocabulary>
</relation>
</term>
<term>
<termId>49556</termId>
<termUpdate>add</termUpdate>
<termName>Leave of Absence Personnel</termName>
<termVocabulary>People Status Global</termVocabulary>
<termCategory>GLB</termCategory>
<termCategory>PDI</termCategory>
<relation weight="100">
<relationType>BT</relationType>
<termId>49554</termId>
<termName>General Non-Active Personnel</termName>
<termVocabulary>People Status Global</termVocabulary>
</relation>
</term>
</Zthes>
</FileData>
</GetSavedReportResponse>
Se produce el resultado deseado y correcto :
"GL";"PDA";"People Status Global";"term vocabulary";
"GL";"PDA";"People Status Global";"People Status Global Updated";
"GL";"PDA";"Global People Status";"term vocabulary";
"GL";"PDA";"Global People Status";"People Status Global Updated";
"GL";"PDI";"People Status Global";"term vocabulary";
"GL";"PDI";"People Status Global";"People Status Global Updated";
"GL";"PDI";"Global People Status";"term vocabulary";
"GL";"PDI";"Global People Status";"People Status Global Updated";
"GL";"GLB";"People Status Global";"term vocabulary";
"GL";"GLB";"People Status Global";"People Status Global Updated";
"GL";"GLB";"Global People Status";"term vocabulary";
"GL";"GLB";"Global People Status";"People Status Global Updated";
"GL";"GLB";"People Status Global";"People Status Global";
"GL";"PDI";"People Status Global";"People Status Global";
Explicación : desea generar resultados solo cuando se haya formado una línea completa, no antes.
Actualización : el OP funciona en un entorno donde la función document()
está desactivada.También quiere un encabezado y un pie de página.
En este caso, se puede usar una transformación ligeramente modificada (usando la función de extensión exslt:node-set()
) ahora:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:variable name="vrtfDefaults">
<termCat/>
<termVocab/>
</xsl:variable>
<xsl:variable name="vDefaults" select=
"ext:node-set($vrtfDefaults)"/>
<xsl:variable name="vQ">"</xsl:variable>
<xsl:template match="Zthes">
<xsl:text>HDR";"PIGLSSTD";"20120112045620";"F":</xsl:text>
<xsl:apply-templates/>
<xsl:text>
FTR</xsl:text>
</xsl:template>
<xsl:template match="term">
<xsl:variable name="vTerm" select="."/>
<xsl:variable name="vRow1" select="'
"GL";'"/>
<xsl:for-each select=
"termCategory
|
$vDefaults/termCat[not($vTerm/termCategory)]">
<xsl:variable name="vRow2" select=
"concat($vRow1, $vQ, ., $vQ, ';')"/>
<xsl:for-each select=
"$vTerm/termVocabulary
|
$vDefaults/termCat[not($vTerm/termVocabulary)]
">
<xsl:variable name="vRow3" select=
"concat($vRow2, $vQ, ., $vQ, ';')"/>
<xsl:for-each select=
"$vTerm/relation/termVocabulary
|
$vDefaults/termCat[not($vTerm/relation/termVocabulary)]
">
<xsl:value-of select="concat($vRow3, $vQ, ., $vQ, ';')"/>
</xsl:for-each>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
<xsl:template match="text()"/>
</xsl:stylesheet>