Home > Enterprise >  XSLT grouping siblings with conditions, part2?
XSLT grouping siblings with conditions, part2?

Time:05-06

i got a similar question already, but that one is a little more complicated.

I am trying to get a text result of some geological layer data from an XML using xslt.

The XML sample i got may look like that:

<LAYERS> 
    <LAYER DEPTHTO="1.00" PETRO="Sand" STRAT="geologiscal_formation_1" INTV="1"/>
    <LAYER DEPTHTO="94.00" PETRO="Sand" STRAT="geologiscal_formation_1" INTV="1"/>
    <LAYER DEPTHTO="94.20" INTV="1" INDEX_ZONE="-1" EGART="Lost_Data"/>
    <LAYER DEPTHTO="95.00" PETRO="Gravel" STRAT="geologiscal_formation_1" INTV="1"/>
    <LAYER DEPTHTO="100.00" PETRO="Sand" STRAT="geologiscal_formation_2" INTV="1"/>
    <LAYER DEPTHTO="100.50" PETRO="Mud" STRAT="geologiscal_formation_2" INTV="1"/>
    <LAYER DEPTHTO="101.50" PETRO="Sand" STRAT="geologiscal_formation_2" INTV="1"/>
    <LAYER DEPTHTO="101.80" PETRO="Mud" STRAT="geologiscal_formation_2" INTV="1"/>
    <LAYER DEPTHTO="102.90" PETRO="Mud" STRAT="geologiscal_formation_3" INTV="1"/>
    <LAYER DEPTHTO="103.00" PETRO="Sand" STRAT="geologiscal_formation_3" INTV="1"/>
    <LAYER DEPTHTO="103.25" INTV="1" INDEX_ZONE="-1" EGART="Lost_Data"/>
    <LAYER DEPTHTO="103.69" PETRO="Sand" STRAT="geologiscal_formation_3" INTV="1"/>
    <LAYER DEPTHTO="104.00" PETRO="Mud" STRAT="geologiscal_formation_3" INTV="1"/>
    <LAYER DEPTHTO="1.00" PETRO="Sand" STRAT="geologiscal_formation_1" INTV="2"/>
    <LAYER DEPTHTO="94.00" PETRO="Sand" STRAT="geologiscal_formation_1" INTV="2"/>
    <LAYER DEPTHTO="94.20" INTV="2" INDEX_ZONE="-1" EGART="Lost_Data"/>
    <LAYER DEPTHTO="95.00" PETRO="Gravel" STRAT="geologiscal_formation_2" INTV="2"/>
    <LAYER DEPTHTO="100.00" PETRO="Sand" STRAT="geologiscal_formation_2" INTV="2"/>
    <LAYER DEPTHTO="100.50" PETRO="Mud" STRAT="geologiscal_formation_4" INTV="2"/>
    <LAYER DEPTHTO="101.50" PETRO="Sand" STRAT="geologiscal_formation_4" INTV="2"/>
    <LAYER DEPTHTO="101.80" PETRO="Mud" STRAT="geologiscal_formation_5" INTV="2"/>
    <LAYER DEPTHTO="102.90" PETRO="Mud" STRAT="geologiscal_formation_3" INTV="2"/>
    <LAYER DEPTHTO="103.00" PETRO="Sand" STRAT="geologiscal_formation_3" INTV="2"/>
    <LAYER DEPTHTO="103.25" INTV="2" INDEX_ZONE="-1" EGART="Lost_Data"/>
    <LAYER DEPTHTO="103.69" PETRO="Sand" STRAT="geologiscal_formation_2" INTV="2"/>
    <LAYER DEPTHTO="104.00" PETRO="Mud" STRAT="geologiscal_formation_2" INTV="2"/>



</LAYERS> 

its like 2 layer descriptions, which only differ in the INTV attribute value.

Im looking for a way to group by attribute STRAT of specific INTV and a result should look like that (lets say from INTV= 1 dataset):

ZONE "geologiscal_formation_1" 0.00 95.00
ZONE "geologiscal_formation_2" 95.00 101.80 
ZONE "geologiscal_formation_3" 101.80 104.00  

The tricky part is to "ignore" the data with EGART="Lost_Data" in the grouping.

Since that question got partly answered here: XSLT grouping siblings with conditions?

but i made a mistake in my example, i did a new question for that new scanrio.

I hope my idea gets throu and ill keep searching.

Thanks for all help.

CodePudding user response:

To get the result you show, you could make a rather simple adjustment to the answer from your previous question:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="UTF-8"/>

<xsl:key name="layer-by-strat" match="LAYER[@INTV=1]" use="@STRAT" />

<xsl:template match="LAYERS" >
    <xsl:call-template name="generate-rows">
        <xsl:with-param name="layers" select="LAYER[@INTV=1 and not(@EGART='Lost_Data')][count(. | key('layer-by-strat', @STRAT)[1]) = 1]"/>
    </xsl:call-template>
</xsl:template>

<xsl:template name="generate-rows">
    <xsl:param name="layers" select="/.."/>
    <xsl:param name="accumulated-depth" select="'0.00'"/>
    <xsl:if test="$layers">
        <xsl:variable name="strat" select="$layers[1]/@STRAT" />
        <xsl:variable name="max-depth" select="key('layer-by-strat', $strat)[last()]/@DEPTHTO" />
        <!-- output -->
        <xsl:text>ZONE "</xsl:text>
        <xsl:value-of select="$strat" />
        <xsl:text>" </xsl:text>
        <xsl:value-of select="$accumulated-depth" />
        <xsl:text> </xsl:text>
        <xsl:value-of select="$max-depth" />
        <xsl:text>&#10;</xsl:text>
        <!-- recursive call -->
        <xsl:call-template name="generate-rows">
            <xsl:with-param name="layers" select="$layers[position() > 1]"/>
            <xsl:with-param name="accumulated-depth" select="$max-depth"/>
        </xsl:call-template>
    </xsl:if>
</xsl:template>

</xsl:stylesheet>

Note that we are assuming here that a LAYER with @EGART='Lost_Data' does not have a STRAT attribute - so this condition can be skipped in the key definition.

--
P.S. It seems you would want to parametrize the choice of INTV - however, that's not possible (at least not if you want to use the Muenchian grouping method) because in XSLT 1.0 you are not allowed to use a variable in a match pattern .

  • Related