I need to sort a node by the value of a grand-grand-child. For this I found different examples, but the child G_SG16 appears several times and I need to add a qualifier (here DOC). It could also be that the qualifier DOC does not exits.
Here the line item node G_SG15 that should be sorted including all sub notes:
<?xml version="1.0" encoding="UTF-8"?>
<ns0:DESADV96A xmlns:ns0="urn:DESADV">
<DifferentNodes/>
<G_SG10>
<G_SG15>
<S_LIN>
<D_1082>10</D_1082>
</S_LIN>
<G_SG16>
<S_RFF>
<C_C506>
<D_1153>DOC</D_1153>
<D_1154>333</D_1154>
</C_C506>
</S_RFF>
</G_SG16>
<G_SG16>
<S_RFF>
<C_C506>
<D_1153>WE</D_1153>
<D_1154>Customer</D_1154>
<D_1156/>
<D_4000/>
</C_C506>
</S_RFF>
</G_SG16>
</G_SG15>
<G_SG15>
<S_LIN>
<D_1082>20</D_1082>
</S_LIN>
<G_SG16>
<S_RFF>
<C_C506>
<D_1153>DOC</D_1153>
<D_1154>111</D_1154>
</C_C506>
</S_RFF>
</G_SG16>
<G_SG16>
<S_RFF>
<C_C506>
<D_1153>WE</D_1153>
<D_1154>Customer</D_1154>
<D_1156/>
<D_4000/>
</C_C506>
</S_RFF>
</G_SG16>
</G_SG15>
<G_SG15>
<S_LIN>
<D_1082>30</D_1082>
</S_LIN>
<G_SG16>
<S_RFF>
<C_C506>
<D_1153>DOC</D_1153>
<D_1154>222</D_1154>
</C_C506>
</S_RFF>
</G_SG16>
<G_SG16>
<S_RFF>
<C_C506>
<D_1153>WE</D_1153>
<D_1154>Customer</D_1154>
<D_1156/>
<D_4000/>
</C_C506>
</S_RFF>
</G_SG16>
</G_SG15>
<G_SG15>
<S_LIN>
<D_1082>40</D_1082>
</S_LIN>
<G_SG16>
<S_RFF>
<C_C506>
<D_1153>WE</D_1153>
<D_1154>Customer</D_1154>
<D_1156/>
<D_4000/>
</C_C506>
</S_RFF>
</G_SG16>
</G_SG15>
</G_SG10>
</ns0:DESADV96A>
Result should look like this. It is not important if the node without DOC appears at begining or end of the sorted list.
result
<?xml version="1.0" encoding="UTF-8"?>
<ns0:DESADV96A xmlns:ns0="urn:DESADV">
<DifferentNodes/>
<G_SG10>
<G_SG15>
<S_LIN>
<D_1082>20</D_1082>
</S_LIN>
<G_SG16>
<S_RFF>
<C_C506>
<D_1153>DOC</D_1153>
<D_1154>111</D_1154>
</C_C506>
</S_RFF>
</G_SG16>
<G_SG16>
<S_RFF>
<C_C506>
<D_1153>WE</D_1153>
<D_1154>Customer</D_1154>
<D_1156/>
<D_4000/>
</C_C506>
</S_RFF>
</G_SG16>
</G_SG15>
<G_SG15>
<S_LIN>
<D_1082>30</D_1082>
</S_LIN>
<G_SG16>
<S_RFF>
<C_C506>
<D_1153>DOC</D_1153>
<D_1154>222</D_1154>
</C_C506>
</S_RFF>
</G_SG16>
<G_SG16>
<S_RFF>
<C_C506>
<D_1153>WE</D_1153>
<D_1154>Customer</D_1154>
<D_1156/>
<D_4000/>
</C_C506>
</S_RFF>
</G_SG16>
</G_SG15>
<G_SG15>
<S_LIN>
<D_1082>10</D_1082>
</S_LIN>
<G_SG16>
<S_RFF>
<C_C506>
<D_1153>DOC</D_1153>
<D_1154>333</D_1154>
</C_C506>
</S_RFF>
</G_SG16>
<G_SG16>
<S_RFF>
<C_C506>
<D_1153>WE</D_1153>
<D_1154>Customer</D_1154>
<D_1156/>
<D_4000/>
</C_C506>
</S_RFF>
</G_SG16>
</G_SG15>
<G_SG15>
<S_LIN>
<D_1082>40</D_1082>
</S_LIN>
<G_SG16>
<S_RFF>
<C_C506>
<D_1153>WE</D_1153>
<D_1154>Customer</D_1154>
<D_1156/>
<D_4000/>
</C_C506>
</S_RFF>
</G_SG16>
</G_SG15>
</G_SG10>
</ns0:DESADV96A>
I tested this one, but it just gives back the source text as it is:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="node()|#*">
<xsl:copy>
<xsl:apply-templates select="node()|#*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="G_SG15">
<xsl:copy>
<xsl:apply-templates select="node()|#*">
<xsl:sort select="/G_SG16/S_RFF/C_C506/D_1154" order="ascending" data-type="text"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Of course the qualifier is still missing, but I hoped that he starts sorting somehow.
I am using an online editor for this. Does anyone know a good (free) debugger for XSLT? Especially why my rule is not used I could not see with a simple editor.
Thanks for your support :-)
Chris
took me a little while, but I figure out with try and error:
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="G_SG10">
<xsl:copy>
<xsl:apply-templates select="*[not(contains(name(), 'G_SG15'))]"/>
<xsl:apply-templates select="G_SG15">
<xsl:sort select="G_SG16/S_RFF/C_C506[D_1153='DOC']/D_1154" data-type="text" order="ascending"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
My first fault was not to select G_SG10 but G_SG15 to sort the G_SG15 which did not worked. Also adding all subnodes next to G_SG15 with [not(contains(name(), 'G_SG15'))] was a little bit try and error. Main problem is if you don't have XMLSpy or something like this to debug a XSL.
Regards
Chris
Related
I trying to group several nodes that have the same contexts inside a existing nodes, by example my case is try to group node Desglose within Detalle, so by example one Node Detalle could have N nodes Desglose.
My Actual XML
<?xml version="1.0" encoding="UTF-8"?>
<MT_Request_Respuesta_plano>
<Cabecera>
<TipoRegistro>C</TipoRegistro>
<TipoFichero>Facturas</TipoFichero>
<CCAA>12</CCAA>
<FechaFichero>20221124</FechaFichero>
<DescripProceso>DESCARGAS DEL FICHERO DE FACTURAS DEL SERMAS </DescripProceso>
<CodigoResultado/>
<DescripResultado/>
<espacios/>
</Cabecera>
<Certificacion>
<TipoRegistro>R</TipoRegistro>
<NroCertificacion>121100</NroCertificacion>
<NombreSPS>SERVICIO MADRILEÑO DE SALUD </NombreSPS>
<DireccionSPS>PLAZA DE CARLOS TRÍAS BERTRÁN, Nº 7, EDIFICIO SOLLUBE </DireccionSPS>
<LocalidadSPS>MADRID </LocalidadSPS>
<CodPostalSPS>28020 </CodPostalSPS>
<FecDesdeLiquidacion>20210316</FecDesdeLiquidacion>
<FecHastaLiquidacion>20210330</FecHastaLiquidacion>
<NroLiquidacionDesde>000000000000000</NroLiquidacionDesde>
<NroLiquidacionHasta>999999999999999</NroLiquidacionHasta>
<TotalLiquidacionesMes>0000075</TotalLiquidacionesMes>
<ImporteTotal>000000001498200</ImporteTotal>
<Observaciones/>
<Libre>914555222 </Libre>
</Certificacion>
<Detalle>
<TipoRegistro>D</TipoRegistro>
<ProvinciaOrigen>28</ProvinciaOrigen>
<CodCentroGrabacion>2803 </CodCentroGrabacion>
<CodCentroAsistencia/>
<NumeroFactura> 2110100556</NumeroFactura>
<ProvinciaDestino>28</ProvinciaDestino>
<FechaGrabacion>20210316</FechaGrabacion>
<Nombre>AURORA </Nombre>
<PrimerApellido>DE </PrimerApellido>
<SegundoApellido>BLAS GUTIERREZ </SegundoApellido>
<NSS>390050482793</NSS>
<IPF>113740356H </IPF>
<IndicadorRecaida>N</IndicadorRecaida>
<FechaAccidente>20171107</FechaAccidente>
<FechaInicioAs>20171107</FechaInicioAs>
<FechaFinAs>20171107</FechaFinAs>
<TipoContingencia>AT</TipoContingencia>
<CodigoContingencia>3</CodigoContingencia>
<espacios/>
</Detalle>
<Desglose>
<TipoRegistro>T</TipoRegistro>
<CodigoPrestaciones>0</CodigoPrestaciones>
<CodConceptoCargo>E03.1.1.2.2.1.1 </CodConceptoCargo>
<FechaTecnica>20171107</FechaTecnica>
<CodHospitalizacion>0</CodHospitalizacion>
<CodTipoTarifa/>
<Unidades>001</Unidades>
<PrecioConcepto>00017500</PrecioConcepto>
<ImporteTotal>0000000017500</ImporteTotal>
<FechaPublicacionBOCA>20170821</FechaPublicacionBOCA>
<espacios/>
</Desglose>
<Desglose>
<TipoRegistro>T</TipoRegistro>
<CodigoPrestaciones>0</CodigoPrestaciones>
<CodConceptoCargo>E03.1.1.2.1.1 </CodConceptoCargo>
<FechaTecnica>20171108</FechaTecnica>
<CodHospitalizacion>0</CodHospitalizacion>
<CodTipoTarifa/>
<Unidades>001</Unidades>
<PrecioConcepto>00011500</PrecioConcepto>
<ImporteTotal>0000000011500</ImporteTotal>
<FechaPublicacionBOCA>20170821</FechaPublicacionBOCA>
<espacios/>
</Desglose>
<Detalle>
<TipoRegistro>D</TipoRegistro>
<ProvinciaOrigen>28</ProvinciaOrigen>
<CodCentroGrabacion>2803 </CodCentroGrabacion>
<CodCentroAsistencia/>
<NumeroFactura> 2110100559</NumeroFactura>
<ProvinciaDestino>28</ProvinciaDestino>
<FechaGrabacion>20210316</FechaGrabacion>
<Nombre>CLAUDIA </Nombre>
<PrimerApellido>JIMENEZ </PrimerApellido>
<SegundoApellido>TORIJA </SegundoApellido>
<NSS>281208193843</NSS>
<IPF>111862836B </IPF>
<IndicadorRecaida>N</IndicadorRecaida>
<FechaAccidente>20171213</FechaAccidente>
<FechaInicioAs>20171213</FechaInicioAs>
<FechaFinAs>20171214</FechaFinAs>
<TipoContingencia>AT</TipoContingencia>
<CodigoContingencia>3</CodigoContingencia>
<espacios/>
</Detalle>
<Desglose>
<TipoRegistro>T</TipoRegistro>
<CodigoPrestaciones>0</CodigoPrestaciones>
<CodConceptoCargo>E03.1.1.2.2.1.1 </CodConceptoCargo>
<FechaTecnica>20171213</FechaTecnica>
<CodHospitalizacion>0</CodHospitalizacion>
<CodTipoTarifa/>
<Unidades>001</Unidades>
<PrecioConcepto>00017500</PrecioConcepto>
<ImporteTotal>0000000017500</ImporteTotal>
<FechaPublicacionBOCA>20170821</FechaPublicacionBOCA>
<espacios/>
</Desglose>
<Detalle>
<TipoRegistro>D</TipoRegistro>
<ProvinciaOrigen>28</ProvinciaOrigen>
<CodCentroGrabacion>2803 </CodCentroGrabacion>
<CodCentroAsistencia/>
<NumeroFactura> 2110100562</NumeroFactura>
<ProvinciaDestino>28</ProvinciaDestino>
<FechaGrabacion>20210316</FechaGrabacion>
<Nombre>SUSANA SARA </Nombre>
<PrimerApellido>MACHO </PrimerApellido>
<SegundoApellido>LOPEZ </SegundoApellido>
<NSS>280343142847</NSS>
<IPF>170164060F </IPF>
<IndicadorRecaida>N</IndicadorRecaida>
<FechaAccidente>20171030</FechaAccidente>
<FechaInicioAs>20171030</FechaInicioAs>
<FechaFinAs>20171031</FechaFinAs>
<TipoContingencia>AT</TipoContingencia>
<CodigoContingencia>3</CodigoContingencia>
<espacios/>
</Detalle>
<Desglose>
<TipoRegistro>T</TipoRegistro>
<CodigoPrestaciones>0</CodigoPrestaciones>
<CodConceptoCargo>E03.1.1.2.2.1.1 </CodConceptoCargo>
<FechaTecnica>20171030</FechaTecnica>
<CodHospitalizacion>0</CodHospitalizacion>
<CodTipoTarifa/>
<Unidades>001</Unidades>
<PrecioConcepto>00017500</PrecioConcepto>
<ImporteTotal>0000000017500</ImporteTotal>
<FechaPublicacionBOCA>20170821</FechaPublicacionBOCA>
<espacios/>
</Desglose>
<Desglose>
<TipoRegistro>T</TipoRegistro>
<CodigoPrestaciones>0</CodigoPrestaciones>
<CodConceptoCargo>E03.1.1.2.1.1 </CodConceptoCargo>
<FechaTecnica>20171102</FechaTecnica>
<CodHospitalizacion>0</CodHospitalizacion>
<CodTipoTarifa/>
<Unidades>001</Unidades>
<PrecioConcepto>00011500</PrecioConcepto>
<ImporteTotal>0000000011500</ImporteTotal>
<FechaPublicacionBOCA>20170821</FechaPublicacionBOCA>
<espacios/>
</Desglose>
<Totales>
<TipoRegistro>X</TipoRegistro>
<TotalRegGrabados>0000184</TotalRegGrabados>
<espacios/>
</Totales>
</MT_Request_Respuesta_plano>
The result I expect is to be able to group the "Desglose" nodes inside the "Detalle" nodes, assuming the sequence in which the "Desglose" nodes arrive to me, after each "Detail" node, could be N "Detalle" with M "Desglose" associated
<?xml version="1.0" encoding="UTF-8"?>
<MT_Request_Respuesta_plano>
<Cabecera>
<TipoRegistro>C</TipoRegistro>
<TipoFichero>Facturas</TipoFichero>
<CCAA>12</CCAA>
<FechaFichero>20221124</FechaFichero>
<DescripProceso>DESCARGAS DEL FICHERO DE FACTURAS DEL SERMA</DescripProceso>
<CodigoResultado/>
<DescripResultado/>
<espacios/>
</Cabecera>
<Certificacion>
<TipoRegistro>R</TipoRegistro>
<NroCertificacion>121100</NroCertificacion>
<NombreSPS>SERVICIO MADRILEÑO DE SALUD </NombreSPS>
<DireccionSPS>PLAZA DE CARLOS TRÍAS BERTRÁN, Nº 7, EDIFICIO SOLLUBE</DireccionSPS>
<LocalidadSPS>MADRID </LocalidadSPS>
<CodPostalSPS>28020 </CodPostalSPS>
<FecDesdeLiquidacion>20210316</FecDesdeLiquidacion>
<FecHastaLiquidacion>20210330</FecHastaLiquidacion>
<NroLiquidacionDesde>000000000000000</NroLiquidacionDesde>
<NroLiquidacionHasta>999999999999999</NroLiquidacionHasta>
<TotalLiquidacionesMes>0000075</TotalLiquidacionesMes>
<ImporteTotal>000000001498200</ImporteTotal>
<Observaciones/>
<Libre>914555222 </Libre>
</Certificacion>
<Detalle>
<TipoRegistro>D</TipoRegistro>
<ProvinciaOrigen>28</ProvinciaOrigen>
<CodCentroGrabacion>2803 </CodCentroGrabacion>
<CodCentroAsistencia/>
<NumeroFactura> 2110100556</NumeroFactura>
<ProvinciaDestino>28</ProvinciaDestino>
<FechaGrabacion>20210316</FechaGrabacion>
<Nombre>AURORA </Nombre>
<PrimerApellido>DE </PrimerApellido>
<SegundoApellido>BLAS GUTIERREZ </SegundoApellido>
<NSS>390050482793</NSS>
<IPF>113740356H </IPF>
<IndicadorRecaida>N</IndicadorRecaida>
<FechaAccidente>20171107</FechaAccidente>
<FechaInicioAs>20171107</FechaInicioAs>
<FechaFinAs>20171107</FechaFinAs>
<TipoContingencia>AT</TipoContingencia>
<CodigoContingencia>3</CodigoContingencia>
<espacios/>
<Desglose>
<TipoRegistro>T</TipoRegistro>
<CodigoPrestaciones>0</CodigoPrestaciones>
<CodConceptoCargo>E03.1.1.2.2.1.1 </CodConceptoCargo>
<FechaTecnica>20171107</FechaTecnica>
<CodHospitalizacion>0</CodHospitalizacion>
<CodTipoTarifa/>
<Unidades>001</Unidades>
<PrecioConcepto>00017500</PrecioConcepto>
<ImporteTotal>0000000017500</ImporteTotal>
<FechaPublicacionBOCA>20170821</FechaPublicacionBOCA>
<espacios/>
</Desglose>
<Desglose>
<TipoRegistro>T</TipoRegistro>
<CodigoPrestaciones>0</CodigoPrestaciones>
<CodConceptoCargo>E03.1.1.2.1.1 </CodConceptoCargo>
<FechaTecnica>20171108</FechaTecnica>
<CodHospitalizacion>0</CodHospitalizacion>
<CodTipoTarifa/>
<Unidades>001</Unidades>
<PrecioConcepto>00011500</PrecioConcepto>
<ImporteTotal>0000000011500</ImporteTotal>
<FechaPublicacionBOCA>20170821</FechaPublicacionBOCA>
<espacios/>
</Desglose>
</Detalle>
<Detalle>
<TipoRegistro>D</TipoRegistro>
<ProvinciaOrigen>28</ProvinciaOrigen>
<CodCentroGrabacion>2803 </CodCentroGrabacion>
<CodCentroAsistencia/>
<NumeroFactura> 2110100559</NumeroFactura>
<ProvinciaDestino>28</ProvinciaDestino>
<FechaGrabacion>20210316</FechaGrabacion>
<Nombre>CLAUDIA </Nombre>
<PrimerApellido>JIMENEZ </PrimerApellido>
<SegundoApellido>TORIJA </SegundoApellido>
<NSS>281208193843</NSS>
<IPF>111862836B </IPF>
<IndicadorRecaida>N</IndicadorRecaida>
<FechaAccidente>20171213</FechaAccidente>
<FechaInicioAs>20171213</FechaInicioAs>
<FechaFinAs>20171214</FechaFinAs>
<TipoContingencia>AT</TipoContingencia>
<CodigoContingencia>3</CodigoContingencia>
<espacios/>
<Desglose>
<TipoRegistro>T</TipoRegistro>
<CodigoPrestaciones>0</CodigoPrestaciones>
<CodConceptoCargo>E03.1.1.2.2.1.1 </CodConceptoCargo>
<FechaTecnica>20171213</FechaTecnica>
<CodHospitalizacion>0</CodHospitalizacion>
<CodTipoTarifa/>
<Unidades>001</Unidades>
<PrecioConcepto>00017500</PrecioConcepto>
<ImporteTotal>0000000017500</ImporteTotal>
<FechaPublicacionBOCA>20170821</FechaPublicacionBOCA>
<espacios/>
</Desglose>
</Detalle>
<Detalle>
<TipoRegistro>D</TipoRegistro>
<ProvinciaOrigen>28</ProvinciaOrigen>
<CodCentroGrabacion>2803 </CodCentroGrabacion>
<CodCentroAsistencia/>
<NumeroFactura> 2110100562</NumeroFactura>
<ProvinciaDestino>28</ProvinciaDestino>
<FechaGrabacion>20210316</FechaGrabacion>
<Nombre>SUSANA SARA </Nombre>
<PrimerApellido>MACHO </PrimerApellido>
<SegundoApellido>LOPEZ </SegundoApellido>
<NSS>280343142847</NSS>
<IPF>170164060F </IPF>
<IndicadorRecaida>N</IndicadorRecaida>
<FechaAccidente>20171030</FechaAccidente>
<FechaInicioAs>20171030</FechaInicioAs>
<FechaFinAs>20171031</FechaFinAs>
<TipoContingencia>AT</TipoContingencia>
<CodigoContingencia>3</CodigoContingencia>
<espacios/>
<Desglose>
<TipoRegistro>T</TipoRegistro>
<CodigoPrestaciones>0</CodigoPrestaciones>
<CodConceptoCargo>E03.1.1.2.2.1.1 </CodConceptoCargo>
<FechaTecnica>20171030</FechaTecnica>
<CodHospitalizacion>0</CodHospitalizacion>
<CodTipoTarifa/>
<Unidades>001</Unidades>
<PrecioConcepto>00017500</PrecioConcepto>
<ImporteTotal>0000000017500</ImporteTotal>
<FechaPublicacionBOCA>20170821</FechaPublicacionBOCA>
<espacios/>
</Desglose>
<Desglose>
<TipoRegistro>T</TipoRegistro>
<CodigoPrestaciones>0</CodigoPrestaciones>
<CodConceptoCargo>E03.1.1.2.1.1 </CodConceptoCargo>
<FechaTecnica>20171102</FechaTecnica>
<CodHospitalizacion>0</CodHospitalizacion>
<CodTipoTarifa/>
<Unidades>001</Unidades>
<PrecioConcepto>00011500</PrecioConcepto>
<ImporteTotal>0000000011500</ImporteTotal>
<FechaPublicacionBOCA>20170821</FechaPublicacionBOCA>
<espacios/>
</Desglose>
</Detalle>
<Totales>
<TipoRegistro>X</TipoRegistro>
<TotalRegGrabados>0000184</TotalRegGrabados>
<espacios/>
</Totales>
</MT_Request_Respuesta_plano>
I've tried this XSLT, one with for-each-group, but no result.
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml"
version="1.0"
encoding="UTF-8"
indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Detalle">
<xsl:for-each-group select="Detalle | Desglose" group-by="#Detalle">
<Detalle>
<xsl:copy-of select="node()"/>
<xsl:for-each-group select="current-group()" group-by="#Desglose">
<Desglose>
<xsl:for-each select="current-group()">
<xsl:copy-of select="node()"/>
</xsl:for-each>
</Desglose>
</xsl:for-each-group>
</Detalle>
</xsl:for-each-group>
</xsl:template>
</xsl:stylesheet>
I also have tried this another XSLT, more nice, but just result with values without label...
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:key name="Kgrupo" match="Desglose" use="generate-id(preceding-sibling::Detalle[NumeroFactura][1])" />
<xsl:template match="Detalle">
<xsl:copy>
<xsl:for-each select="Desglose">
<xsl:for-each select="key('Kgrupo', generate-id())" >
<Desglose>
<xsl:value-of select="normalize-space(main)" />
</Desglose>
</xsl:for-each>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
I would really appreciate any help to solve this transformation that seems easy, but it is not, at least for me =)
The xsl:for-each-group instruction requires XSLT 2.0 or higher. To do the equivalent of group-starting-with in XSLT 1.0 you need a different method. Your 2nd attempt is close, but it should be:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="Kgrupo" match="Desglose" use="generate-id(preceding-sibling::Detalle[1])" />
<xsl:template match="/MT_Request_Respuesta_plano">
<xsl:copy>
<xsl:copy-of select="Cabecera | Certificacion"/>
<xsl:for-each select="Detalle">
<xsl:copy>
<xsl:copy-of select="*"/>
<xsl:copy-of select="key('Kgrupo', generate-id())"/>
</xsl:copy>
</xsl:for-each>
<xsl:copy-of select="Totales"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
This XSLT 2.0 answer creates the required output with a recursive named template 'iterate-elements'. The recursive template calls will be 'tail-call-optimised' by an XSLT processor such as Saxon.
I would generally recommend the accepted answer's approach using xsl:for-each and xsl:key as it it simpler and more concise. This alternate approach is a bit more generic however and may be useful if you find the grouping logic becomes more complex later on.
This XSLT template uses 'recursive-sibling` approach to iterate child element of the root element.
Details on the state that is tracked when iterating each element:
$currentElement the current element for each iteration
$targetElement the last previous instance of the Detalle element in the iteration
$sourceElements the Desglose elements following the $targetElement - later injected into $targetElement with the fn:injectElements function
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:fn="com.group-elements.sample"
exclude-result-prefixes="#all"
version="1.0">
<xsl:strip-space elements="*"/>
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/*">
<xsl:copy>
<xsl:apply-templates select="#*" mode="#current"/>
<xsl:call-template name="iterate-elements"/>
</xsl:copy>
</xsl:template>
<xsl:template name="iterate-elements">
<xsl:param name="elements" as="element()*" select="*"/>
<xsl:param name="currentElement" select="$elements[1]"/>
<xsl:param name="targetElement" as="element()?" select="()"/>
<xsl:param name="sourceElements" as="element()*"/>
<xsl:choose>
<xsl:when test="empty($currentElement)">
<!-- in case there are any source elements left over: -->
<xsl:sequence select="fn:injectElements($targetElement, $sourceElements)"/>
</xsl:when>
<xsl:when test="fn:isTarget($currentElement)">
<!-- on a new target element so process previous target element and set the new target element -->
<xsl:sequence select="fn:injectElements($targetElement, $sourceElements)"/>
<xsl:call-template name="iterate-elements">
<xsl:with-param name="currentElement" select="$currentElement/following-sibling::*[1]"/>
<xsl:with-param name="sourceElements" select="()"/>
<xsl:with-param name="targetElement" select="$currentElement"/>
</xsl:call-template>
</xsl:when>
<!-- on a new source element so concatanate to the sequence of source elements -->
<xsl:when test="fn:isSource($currentElement)">
<xsl:call-template name="iterate-elements">
<xsl:with-param name="currentElement" select="$currentElement/following-sibling::*[1]"/>
<xsl:with-param name="sourceElements" select="$sourceElements, $currentElement"/>
<xsl:with-param name="targetElement" select="$targetElement"/>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<!-- not on source/target element - process any target element then emit current element -->
<xsl:sequence select="fn:injectElements($targetElement, $sourceElements), $currentElement"/>
<xsl:call-template name="iterate-elements">
<xsl:with-param name="currentElement" select="$currentElement/following-sibling::*[1]"/>
<xsl:with-param name="sourceElements" select="()"/>
<xsl:with-param name="targetElement" select="()"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:function name="fn:isTarget" as="xs:boolean">
<xsl:param name="element" as="element()"/>
<xsl:sequence select="exists($element[self::Detalle])"/>
</xsl:function>
<xsl:function name="fn:isSource" as="xs:boolean">
<xsl:param name="element" as="element()"/>
<xsl:sequence select="exists($element[self::Desglose])"/>
</xsl:function>
<xsl:function name="fn:injectElements" as="element()?">
<xsl:param name="target" as="element()?"/>
<xsl:param name="sourceElements" as="element()*"/>
<xsl:if test="exists($target)">
<xsl:copy select="$target">
<xsl:copy-of select="$target/#*, $target/node()"/>
<xsl:copy-of select="$sourceElements"/>
</xsl:copy>
</xsl:if>
</xsl:function>
</xsl:stylesheet>[enter link description here][1]
I am pulling clob data from a JDBC server and the below is the sample format of the xml
1
<?xml version="1.0" encoding="utf-8"?>
<Sales_Posting>
<row>
<ORGANIZATION_ID>1</ORGANIZATION_ID>
<RTL_LOC_ID>269</RTL_LOC_ID>
<POSLOG_DATA><?xml version="1.0" encoding="UTF-8"?>
<POSLog xmlns="http://www.nrf-arts.org/IXRetail/namespace/"
xmlns:dtv="http://www.datavantagecorp.com/xstore/"
xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
xs:schemaLocation="http://www.nrf-arts.org/IXRetail/namespace/ POSLog.xsd" >
<Transaction xmlns:dtv="http://www.datavantagecorp.com/xstore/" CancelFlag="true" OfflineFlag="false" TrainingModeFlag="false" dtv:AppVersion="17.0.0.0.716 - 0.0.0 - 0.0" dtv:TransactionType="RETAIL_SALE" >
<dtv:OrganizationID><![CDATA[1]]></dtv:OrganizationID>
<RetailStoreID><![CDATA[269]]></RetailStoreID>
<WorkstationID><![CDATA[2]]></WorkstationID>
</Transaction>
</POSLog></POSLOG_DATA>
<CREATE_DATE>2019-07-17 20:57:56.536</CREATE_DATE>
</row>
<row>
<ORGANIZATION_ID>1</ORGANIZATION_ID>
<RTL_LOC_ID>269</RTL_LOC_ID>
<POSLOG_DATA><?xml version="1.0" encoding="UTF-8"?>
<POSLog xmlns="http://www.nrf-arts.org/IXRetail/namespace/"
xmlns:dtv="http://www.datavantagecorp.com/xstore/"
xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
xs:schemaLocation="http://www.nrf-arts.org/IXRetail/namespace/ POSLog.xsd" >
<Transaction xmlns:dtv="http://www.datavantagecorp.com/xstore/" CancelFlag="false" OfflineFlag="false" TrainingModeFlag="false" dtv:AppVersion="17.0.0.0.716 - 0.0.0 - 0.0" dtv:TransactionType="RETAIL_SALE" >
<dtv:OrganizationID><![CDATA[1]]></dtv:OrganizationID>
<RetailStoreID><![CDATA[269]]></RetailStoreID>
<WorkstationID><![CDATA[2]]></WorkstationID>
</Transaction>
</POSLog></POSLOG_DATA>
<CREATE_DATE>2019-07-18 06:20:38.014</CREATE_DATE>
</row>
</Sales_Posting>
I need to pull the xml inside the tag .
For a single record I am able to pull the data using the below code
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" indent="yes"/>
<xsl:template match="/">
<xsl:value-of select="/Sales_Posting/row/POSLOG_DATA"/>
</xsl:template>
</xsl:stylesheet>
But I require it for multiple records.
XSLT 1.0 is preferable. If the result is possible via multiple xslt mappings then that is also fine for me.
Expected Output is :-
2
<?xml version="1.0" encoding="utf-8"?>
<Sales_Posting>
<row>
<POSLog xmlns="http://www.nrf-arts.org/IXRetail/namespace/"
xmlns:dtv="http://www.datavantagecorp.com/xstore/"
xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
xs:schemaLocation="http://www.nrf-arts.org/IXRetail/namespace/ POSLog.xsd">
<Transaction CancelFlag="true"
OfflineFlag="false"
TrainingModeFlag="false"
dtv:AppVersion="17.0.0.0.716 - 0.0.0 - 0.0"
dtv:TransactionType="RETAIL_SALE">
<dtv:OrganizationID>1</dtv:OrganizationID>
<RetailStoreID>269</RetailStoreID>
<WorkstationID>2</WorkstationID>
</Transaction>
</POSLog>
</row>
<row>
<POSLog xmlns="http://www.nrf-arts.org/IXRetail/namespace/"
xmlns:dtv="http://www.datavantagecorp.com/xstore/"
xmlns:xs="http://www.w3.org/2001/XMLSchema-instance"
xs:schemaLocation="http://www.nrf-arts.org/IXRetail/namespace/ POSLog.xsd">
<Transaction CancelFlag="true"
OfflineFlag="false"
TrainingModeFlag="false"
dtv:AppVersion="17.0.0.0.716 - 0.0.0 - 0.0"
dtv:TransactionType="RETAIL_SALE">
<dtv:OrganizationID>1</dtv:OrganizationID>
<RetailStoreID>269</RetailStoreID>
<WorkstationID>2</WorkstationID>
</Transaction>
</POSLog>
</row>
</Sales_Posting>
I am sharing the image of source structure as well as the expected target structure. Kindly help.
Try:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/Sales_Posting">
<xsl:copy>
<xsl:for-each select="row">
<xsl:copy>
<xsl:value-of select="substring-after(POSLOG_DATA, '?>')" disable-output-escaping="yes"/>
</xsl:copy>
</xsl:for-each>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
The result must be saved to file before processed further. This is assuming your processor supports disable-output-escaping.
I'm looking for kind of a break statement in XSLT.
Below is my input:
<ListOfCrnEstimates>
<CrnEstimates>
<CRNEstimatePackage>Mobile Claims</CRNEstimatePackage>
<CRNEstimateAssignStatus>Pending</CRNEstimateAssignStatus>
</CrnEstimates>
<CrnEstimates>
<CRNEstimatePackage>Adjuster</CRNEstimatePackage>
<CRNEstimateAssignStatus>Pending1</CRNEstimateAssignStatus>
</CrnEstimates>
<CrnEstimates>
<CRNEstimatePackage>Inside Adjuster</CRNEstimatePackage>
<CRNEstimateAssignStatus>Moved to Mobile Claims</CRNEstimateAssignStatus>
</CrnEstimates>
<CrnEstimates>
<CRNEstimatePackage>Mobile Claims</CRNEstimatePackage>
<CRNEstimateAssignStatus>Completed</CRNEstimateAssignStatus> <CRNEstimateAssignStatus>Completed</CRNEstimateAssignStatus>
</CrnEstimates>
</ListOfCrnEstimates>
Note: CRNEstimateAssignStatus values may differ...
I have to check for CRNEstimatePackage = Mobile Claims and have to create a request to backend with retaining that particular <CrnEstimates> and remove other <CrnEstimates>.
For the above request, I should generate 2 backend requests as below:
Output1:
<ListOfCrnEstimates>
<CrnEstimates>
<CRNEstimatePackage>Mobile Claims</CRNEstimatePackage>
<CRNEstimateAssignStatus>Pending</CRNEstimateAssignStatus>
</CrnEstimates>
</ListOfCrnEstimates>
Output2:
<ListOfCrnEstimates>
<CrnEstimates>
<CRNEstimatePackage>Mobile Claims</CRNEstimatePackage>
<CRNEstimateAssignStatus>Completed</CRNEstimateAssignStatus>
</CrnEstimates>
</ListOfCrnEstimates>
Currently I'm using below xslt:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<xsl:output method="xml" encoding="UTF-8" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="#* | node()">
<xsl:copy>
<xsl:apply-templates select="#* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="*:CrnEstimates[descendant::*:CRNEstimatePackage[. != 'Mobile Claims']]"/>
</xsl:stylesheet>
and Im getting below response:
<?xml version="1.0" encoding="UTF-8"?>
<ListOfCrnEstimates>
<CrnEstimates>
<CRNEstimatePackage>Mobile Claims</CRNEstimatePackage>
<CRNEstimateAssignStatus>Pending</CRNEstimateAssignStatus>
</CrnEstimates>
<CrnEstimates>
<CRNEstimatePackage>Mobile Claims</CRNEstimatePackage>
<CRNEstimateAssignStatus>Completed</CRNEstimateAssignStatus>
</CrnEstimates>
</ListOfCrnEstimates>
As i think you want to do nothing when CRNEstimatePackage[. != 'Mobile Claims'] that what it is dropping all CrnEstimates that descendant//CRNEstimatePackage values are not 'Mobile Claims'.
I am fighting a pretty extreme case of transforming a flat XML into a hierarchical one. I'm also stuck with using XSLT 1.0. My actual case is pretty convoluted, but I think I can reduce it down to something like this:
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header/>
<env:Body>
<tns:getDataRS xmlns:tns="http://www.myco.com/DataService">
<tns:Acknowledgement>Process completed successfully.</tns:Acknowledgement>
<tns:customer>
<tns:customerID>210</tns:customerID>
<tns:visitID>12</tns:visitID>
<tns:storeID>1</tns:storeID>
<tns:storeOrder>28</tns:storeOrder>
<tns:itemID>1</tns:itemID>
<tns:customerSalesDate>2014-09-26</tns:customerSalesDate>
</tns:customer>
<tns:customer>
<tns:customerID>210</tns:customerID>
<tns:visitID>12</tns:visitID>
<tns:storeID>1</tns:storeID>
<tns:storeOrder>28</tns:storeOrder>
<tns:itemID>3</tns:itemID>
<tns:customerSalesDate>2014-09-26</tns:customerSalesDate>
</tns:customer>
<tns:customer>
<tns:customerID>211</tns:customerID>
<tns:visitID>31</tns:visitID>
<tns:storeID>2</tns:storeID>
<tns:storeOrder>48</tns:storeOrder>
<tns:itemID>2</tns:itemID>
<tns:customerSalesDate>2014-09-26</tns:customerSalesDate>
</tns:customer>
<tns:customer>
<tns:customerID>211</tns:customerID>
<tns:visitID>31</tns:visitID>
<tns:storeID>2</tns:storeID>
<tns:storeOrder>48</tns:storeOrder>
<tns:itemID>4</tns:itemID>
<tns:customerSalesDate>2014-09-26</tns:customerSalesDate>
</tns:customer>
<tns:item>
<tns:customerID>210</tns:customerID>
<tns:visitID>12</tns:visitID>
<tns:storeID>1</tns:storeID>
<tns:itemID>1</tns:itemID>
<tns:unitPrice>2.95</tns:unitPrice>
<tns:quantity>4</tns:quantity>
</tns:item>
<tns:item>
<tns:customerID>211</tns:customerID>
<tns:visitID>31</tns:visitID>
<tns:storeID>1</tns:storeID>
<tns:itemID>2</tns:itemID>
<tns:unitPrice>3.29</tns:unitPrice>
<tns:quantity>2</tns:quantity>
</tns:item>
<tns:item>
<tns:customerID>210</tns:customerID>
<tns:visitID>12</tns:visitID>
<tns:storeID>2</tns:storeID>
<tns:itemID>3</tns:itemID>
<tns:unitPrice>4.99</tns:unitPrice>
<tns:quantity>1</tns:quantity>
</tns:item>
<tns:item>
<tns:customerID>211</tns:customerID>
<tns:visitID>31</tns:visitID>
<tns:storeID>2</tns:storeID>
<tns:itemID>4</tns:itemID>
<tns:unitPrice>6.95</tns:unitPrice>
<tns:quantity>2</tns:quantity>
</tns:item>
</tns:getDataRS>
</env:Body>
</env:Envelope>
And it needs to become:
<?xml version="1.0" encoding="UTF-8"?>
<env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
<env:Header/>
<env:Body>
<tns:getDataRS xmlns:tns="http://www.myco.com/DataService">
<tns:Acknowledgement>Process completed successfully.</tns:Acknowledgement>
<tns:stores>
<tns:store>
<tns:storeID>1</tns:storeID>
<tns:orders>
<tns:order>28</tns:order>
<tns:salesDate>2014-09-26</tns:salesDate>
<tns:customers>
<tns:customer>
<tns:customerID>210</tns:customerID>
<tns:visitID>12</tns:visitID>
<tns:items>
<tns:item>
<tns:itemID>1</tns:itemID>
<tns:unitPrice>2.95</tns:unitPrice>
<tns:quantity>4</tns:quantity>
</tns:item>
<tns:item>
<tns:itemID>3</tns:itemID>
<tns:unitPrice>4.99</tns:unitPrice>
<tns:quantity>1</tns:quantity>
</tns:item>
</tns:items>
</tns:customer>
</tns:customers>
</tns:orders>
</tns:store>
<tns:store>
<tns:storeID>2</tns:storeID>
<tns:orders>
<tns:order>48</tns:order>
<tns:salesDate>2014-09-26</tns:salesDate>
<tns:customers>
<tns:customer>
<tns:customerID>211</tns:customerID>
<tns:visitID>31</tns:visitID>
<tns:items>
<tns:item>
<tns:itemID>2</tns:itemID>
<tns:unitPrice>3.29</tns:unitPrice>
<tns:quantity>2</tns:quantity>
</tns:item>
<tns:item>
<tns:itemID>4</tns:itemID>
<tns:unitPrice>6.95</tns:unitPrice>
<tns:quantity>2</tns:quantity>
</tns:item>
</tns:items>
</tns:customer>
</tns:customers>
</tns:orders>
</tns:store>
</tns:stores>
</tns:getDataRS>
</env:Body>
</env:Envelope>
And though I know I need to create a number of keys, I can't quite figure out the proper matching to extract and map the data.
I'd really like some help getting started.
I'd really like some help getting started.
Try this as your starting point:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:tns="http://www.myco.com/DataService">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="store" match="tns:storeID" use="." />
<xsl:key name="order-by-store" match="tns:storeOrder" use="../tns:storeID" />
<xsl:key name="order-by-id" match="tns:storeOrder" use="." />
<!-- identity transform -->
<xsl:template match="#*|node()">
<xsl:copy>
<xsl:apply-templates select="#*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="tns:getDataRS">
<xsl:copy>
<xsl:copy-of select="tns:Acknowledgement"/>
<tns:stores>
<xsl:apply-templates select="tns:customer/tns:storeID[count(. | key('store', .)[1]) = 1]"/>
</tns:stores>
</xsl:copy>
</xsl:template>
<xsl:template match="tns:storeID">
<tns:store>
<xsl:copy-of select="."/>
<tns:orders>
<xsl:apply-templates select="key('order-by-store', .)[count(. | key('order-by-id', .)[1]) = 1]"/>
</tns:orders>
</tns:store>
</xsl:template>
<xsl:template match="tns:storeOrder">
<tns:Order><xsl:value-of select="."/></tns:Order>
<tns:customers>
<!-- continue from here... -->
</tns:customers>
</xsl:template>
</xsl:stylesheet>
I am not sure how to continue from this point on, even if I wanted to: I don't see that you have multiple customers per order, and as I said in the comments, the relationship between orders and visits is not quite clear either.
I have an XML structure with an organization hierarchy. The <pkEntity> element is a parent ID of org and <entityParent> is the child of org. I don't know the depth of the parent/child combination. I need to transform in below mentioned state:
<EntityDimCollection>
<EntityDim>
<pkEntity>-9</pkEntity>
<entityParent>-7</entityParent>
<entityCode>Own_CP</entityCode>
<entityType>OT</entityType>
<essEntityCode>un.Own_CP</essEntityCode>
</EntityDim>
<EntityDim>
<pkEntity>-8</pkEntity>
<entityParent>-7</entityParent>
<entityCode>Alternatives</entityCode>
<entityType>OT</entityType>
<essEntityCode>un.Alternatives</essEntityCode>
</EntityDim>
<EntityDim>
<pkEntity>8555</pkEntity>
<entityParent>-8</entityParent>
<entityCode>Ex_BABRO</entityCode>
<entityType>CF</entityType>
<essEntityCode>un.Ex_BABRO</essEntityCode>
</EntityDim>
<EntityDim>
<pkEntity>8752</pkEntity>
<entityParent>-8</entityParent>
<entityCode>Ex_SY</entityCode>
<entityType>CF</entityType>
<essEntityCode>un.Ex_SY</essEntityCode>
</EntityDim>
<EntityDim>
<pkEntity>9731</pkEntity>
<entityParent>-8</entityParent>
<entityCode>NOR</entityCode>
<entityType>LE</entityType>
<essEntityCode>un.NOR</essEntityCode>
</EntityDim>
<EntityDim>
<pkEntity>1649940</pkEntity>
<entityParent>9731</entityParent>
<entityCode>NO</entityCode>
<entityType>CG</entityType>
<essEntityCode>un.NOR.NO</essEntityCode>
</EntityDim>
<EntityDim>
<pkEntity>1838293</pkEntity>
<entityParent>1649940</entityParent>
<entityCode>UKONORWAY</entityCode>
<entityType>CG</entityType>
<essEntityCode>un.NOR.UKONORWAY</essEntityCode>
</EntityDim>
<EntityDim>
<pkEntity>1127251</pkEntity>
<entityParent>1838293</entityParent>
<entityCode>2BUS</entityCode>
<entityType>CG</entityType>
<essEntityCode>un.NOR.2BUS</essEntityCode>
</EntityDim>
<EntityDim>
<pkEntity>1127274</pkEntity>
<entityParent>1127251</entityParent>
<entityCode>3BUS_B</entityCode>
<entityType>CG</entityType>
<essEntityCode>un.NOR.3BUS_B</essEntityCode>
</EntityDim>
<EntityDim>
<pkEntity>1988187</pkEntity>
<entityParent>1127274</entityParent>
<entityCode>4BUS_B</entityCode>
<entityType>CG</entityType>
<essEntityCode>un.NOR.4BUS_B</essEntityCode>
</EntityDim>
<EntityDim>
<pkEntity>1988188</pkEntity>
<entityParent>1988187</entityParent>
<entityCode>5ADM_B</entityCode>
<entityType>CG</entityType>
<essEntityCode>un.NOR.5ADM_B</essEntityCode>
</EntityDim>
<EntityDim>
<pkEntity>1988189</pkEntity>
<entityParent>1988187</entityParent>
<entityCode>5FVK_B</entityCode>
<entityType>CG</entityType>
<essEntityCode>un.NOR.5FVK_B</essEntityCode>
</EntityDim>
<EntityDim>
<pkEntity>1988190</pkEntity>
<entityParent>1988189</entityParent>
<entityCode>61_FVK_B</entityCode>
<entityType>CG</entityType>
<essEntityCode>un.NOR.61_FVK_B</essEntityCode>
</EntityDim>
</EntityDimCollection>
and with Mark Veenstra solution I got output like this
<?xml version="1.0" encoding="UTF-8"?>
<client:LMSDetails xmlns:client="http://foo/bar">
<client:ParentID>-9</client:ParentID>
<client:ChildID>-7</client:ChildID>
<client:name/>
<client:identifier>OT</client:identifier>
<client:isActive/>
<client:ParentID>-8</client:ParentID>
<client:ChildID>-7</client:ChildID>
<client:name/>
<client:identifier>OT</client:identifier>
<client:isActive/>
<client:children>
<client:ParentID>8555</client:ParentID>
<client:ChildID>-8</client:ChildID>
<client:name/>
<client:identifier>CF</client:identifier>
<client:isActive/>
</client:children>
<client:children>
<client:ParentID>8752</client:ParentID>
<client:ChildID>-8</client:ChildID>
<client:name/>
<client:identifier>CF</client:identifier>
<client:isActive/>
</client:children>
<client:children>
<client:ParentID>9731</client:ParentID>
<client:ChildID>-8</client:ChildID>
<client:name/>
<client:identifier>LE</client:identifier>
<client:isActive/>
<client:children>
<client:ParentID>1649940</client:ParentID>
<client:ChildID>9731</client:ChildID>
<client:name/>
<client:identifier>CG</client:identifier>
<client:isActive/>
<client:children>
<client:ParentID>1838293</client:ParentID>
<client:ChildID>1649940</client:ChildID>
<client:name/>
<client:identifier>CG</client:identifier>
<client:isActive/>
<client:children>
<client:ParentID>1127251</client:ParentID>
<client:ChildID>1838293</client:ChildID>
<client:name/>
<client:identifier>CG</client:identifier>
<client:isActive/>
<client:children>
<client:ParentID>1127274</client:ParentID>
<client:ChildID>1127251</client:ChildID>
<client:name/>
<client:identifier>CG</client:identifier>
<client:isActive/>
<client:children>
<client:ParentID>1988187</client:ParentID>
<client:ChildID>1127274</client:ChildID>
<client:name/>
<client:identifier>CG</client:identifier>
<client:isActive/>
<client:children>
<client:ParentID>1988188</client:ParentID>
<client:ChildID>1988187</client:ChildID>
<client:name/>
<client:identifier>CG</client:identifier>
<client:isActive/>
</client:children>
<client:children>
<client:ParentID>1988189</client:ParentID>
<client:ChildID>1988187</client:ChildID>
<client:name/>
<client:identifier>CG</client:identifier>
<client:isActive/>
<client:children>
<client:ParentID>1988190</client:ParentID>
<client:ChildID>1988189</client:ChildID>
<client:name/>
<client:identifier>CG</client:identifier>
<client:isActive/>
</client:children>
</client:children>
</client:children>
</client:children>
</client:children>
</client:children>
</client:children>
</client:children>
<client:ParentID>8555</client:ParentID>
<client:ChildID>-8</client:ChildID>
<client:name/>
<client:identifier>CF</client:identifier>
<client:isActive/>
<client:ParentID>8752</client:ParentID>
<client:ChildID>-8</client:ChildID>
<client:name/>
<client:identifier>CF</client:identifier>
<client:isActive/>
<client:ParentID>9731</client:ParentID>
<client:ChildID>-8</client:ChildID>
<client:name/>
<client:identifier>LE</client:identifier>
<client:isActive/>
<client:children>
<client:ParentID>1649940</client:ParentID>
<client:ChildID>9731</client:ChildID>
<client:name/>
<client:identifier>CG</client:identifier>
<client:isActive/>
<client:children>
<client:ParentID>1838293</client:ParentID>
<client:ChildID>1649940</client:ChildID>
<client:name/>
<client:identifier>CG</client:identifier>
<client:isActive/>
<client:children>
<client:ParentID>1127251</client:ParentID>
<client:ChildID>1838293</client:ChildID>
<client:name/>
<client:identifier>CG</client:identifier>
<client:isActive/>
<client:children>
<client:ParentID>1127274</client:ParentID>
<client:ChildID>1127251</client:ChildID>
<client:name/>
<client:identifier>CG</client:identifier>
<client:isActive/>
<client:children>
<client:ParentID>1988187</client:ParentID>
<client:ChildID>1127274</client:ChildID>
<client:name/>
<client:identifier>CG</client:identifier>
<client:isActive/>
<client:children>
<client:ParentID>1988188</client:ParentID>
<client:ChildID>1988187</client:ChildID>
<client:name/>
<client:identifier>CG</client:identifier>
<client:isActive/>
</client:children>
<client:children>
<client:ParentID>1988189</client:ParentID>
<client:ChildID>1988187</client:ChildID>
<client:name/>
<client:identifier>CG</client:identifier>
<client:isActive/>
<client:children>
<client:ParentID>1988190</client:ParentID>
<client:ChildID>1988189</client:ChildID>
<client:name/>
<client:identifier>CG</client:identifier>
<client:isActive/>
</client:children>
</client:children>
</client:children>
</client:children>
</client:children>
</client:children>
</client:children>
</client:LMSDetails>
XSLT 1.0 (and XSLT 2.0) solution
It is based on use the <xsl:key> to arrange the parents and children while boosting the performance of the solution.
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:client="http://client.org">
<xsl:output method="xml" indent="yes" />
<!-- Use keys to boost performance -->
<xsl:key name="entity-key" match="EntityDim" use="pkEntity" />
<xsl:key name="parent-key" match="EntityDim" use="entityParent" />
<!-- Process root element -->
<xsl:template match="EntityDimCollection">
<client:LMSDetails>
<!-- Apply template to root entities, i.e. entities with no parent nodes -->
<xsl:apply-templates select="EntityDim[not(key('entity-key', entityParent))]" />
</client:LMSDetails>
</xsl:template>
<!-- First one to use for the real parent -->
<xsl:template match="EntityDim">
<!-- Obtain the relevant information -->
<client:ParentID><xsl:value-of select="pkEntity" /></client:ParentID>
<client:ChildID><xsl:value-of select="entityParent" /></client:ChildID>
<client:name/>
<client:identifier><xsl:value-of select="entityType" /></client:identifier>
<client:isActive/>
<client:costCenter>
<!-- Obtain the expression after the last dot in essEntityCode -->
<xsl:call-template name="get-suffix">
<xsl:with-param name="text" select="essEntityCode" />
</xsl:call-template>
</client:costCenter>
<!-- Outputs the children for this node : we just search which entities have the
current pkEntity as their entityParent-->
<xsl:for-each select="key('parent-key', pkEntity)">
<client:children>
<xsl:apply-templates select="." />
</client:children>
</xsl:for-each>
</xsl:template>
<!-- Recursive template to obtain the suffix from essEntityCode (the part after
the last dot ) -->
<xsl:template name="get-suffix">
<xsl:param name="text" />
<!-- Check whether the current text contains a dot -->
<xsl:choose>
<!-- Case CONTAINS_DOT: recurse until there is not more dots in the string -->
<xsl:when test="contains($text, '.')">
<xsl:call-template name="get-suffix">
<xsl:with-param name="text" select="substring-after($text, '.')" />
</xsl:call-template>
</xsl:when>
<!-- Case WITHOUT_DOTS : output suffix -->
<xsl:otherwise>
<xsl:value-of select="$text" />
</xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
XSLT 2.0 only solution
The way of building the hierarchy is the same, the only difference is the way of obtaining the suffix from essEntityCode. In XSLT 1.0 we had to build a recursive template to detect the last dot and extract the suffix. However in XSLT 2.0 we can use the function tokenize which splits the given string using the given regular expresion.
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:client="http://client.org">
<xsl:output method="xml" indent="yes" />
<xsl:key name="entity-key" match="EntityDim" use="pkEntity" />
<xsl:key name="parent-key" match="EntityDim" use="entityParent" />
<xsl:template match="EntityDimCollection">
<client:LMSDetails>
<xsl:apply-templates select="EntityDim[not(key('entity-key', entityParent))]" />
</client:LMSDetails>
</xsl:template>
<xsl:template match="EntityDim">
<client:ParentID><xsl:value-of select="pkEntity" /></client:ParentID>
<client:ChildID><xsl:value-of select="entityParent" /></client:ChildID>
<client:name/>
<client:identifier><xsl:value-of select="entityType" /></client:identifier>
<client:isActive/>
<client:costCenter>
<!-- This is the only difference from the XSLT 1.0 solution, instead
of calling the recursive template we tokenize the expression and
obtain the last element (which is the suffix) -->
<xsl:value-of select="tokenize(essEntityCode, '\.')[last()]" />
</client:costCenter>
<xsl:for-each select="key('parent-key', pkEntity)">
<client:children>
<xsl:apply-templates select="." />
</client:children>
</xsl:for-each>
</xsl:template>
</xsl:stelesheet>
EDIT: I have assumed that for each children a new <client:children> is created, that behavior can be changed by adjusting the code in the <for-each> loop.