is there a way to define attributes based on other attributes from a node before? (excuse my terminology, i dont work often with xslt).
I got some soil layer data containing the end-depth of a layer. What is needed is the beginning-depth (the top) of an layer of an specific group.
My first attemps would be to give the first layer of an group the top = 0. The next layer gets a "DEPTHFROM" = DEPTHTO of the previous layer.
Maybe an example will clear up a bit:
A XML Datablock looking like that (some soil layer):
<ZONES>
<ZONE LAYER_DESC="Flysand unchained" DEPTHTO="0.30" GROUP="1"/>
<ZONE LAYER_DESC="Flysand unchained" DEPTHTO="1.10" GROUP="1"/>
<ZONE LAYER_DESC="Flysand unchained" DEPTHTO="1.40" GROUP="1"/>
<ZONE LAYER_DESC="Flysand unchained" DEPTHTO="1.70" GROUP="1"/>
<ZONE LAYER_DESC="Drifting sand" DEPTHTO="1.80" GROUP="1"/>
<ZONE LAYER_DESC="Drifting sand" DEPTHTO="2.20" GROUP="1"/>
<ZONE LAYER_DESC="Drifting sand" DEPTHTO="2.60" GROUP="1"/>
<ZONE LAYER_DESC="Sand unchained" DEPTHTO="0.30" GROUP="2"/>
<ZONE LAYER_DESC="Sand unchained" DEPTHTO="1.10" GROUP="2"/>
<ZONE LAYER_DESC="Sand unchained" DEPTHTO="1.40" GROUP="2"/>
<ZONE LAYER_DESC="Sand unchained" DEPTHTO="1.70" GROUP="2"/>
<ZONE LAYER_DESC="fine sand" DEPTHTO="1.80" GROUP="2"/>
<ZONE LAYER_DESC="fine sand" DEPTHTO="2.20" GROUP="2"/>
<ZONE LAYER_DESC="fine sand" DEPTHTO="2.60" GROUP="2"/>
</ZONES>
Using an xslt (stuck with xslt 1.0 engine) the desired output as a text could look like that:
(LAYER_DESC, 'DEPTHFROM'-> calculated from DEPTHTO from node above of specific layer group), quotes are not required
"Flysand unchained" "0.00"
"Flysand unchained" "0.30"
"Flysand unchained" "1.10"
"Flysand unchained" "1.40"
"Drifting sand" "1.70"
"Drifting sand" "1.80"
"Drifting sand" "2.20"
"Sand unchained" "0.00"
"Sand unchained" "0.30"
"Sand unchained" "1.10"
"Sand unchained" "1.40"
"fine sand" "1.80"
"fine sand" "2.20"
Im more used to database opeations and there I would probably use some row-counters for that task, that wouldnt be wild in there.
Kind regards and thanks for every idea, ill keep on searching.
CodePudding user response:
XSLT 1.0
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="text" encoding="utf-8"/>
<xsl:strip-space elements="*"/>
<xsl:template match="ZONE">
<xsl:value-of select="@LAYER_DESC"/>
<xsl:text> </xsl:text>
<xsl:variable name="groupId" select="@GROUP"/>
<xsl:variable name="precedingZone" select="preceding-sibling::ZONE[@GROUP = $groupId][1]"/>
<xsl:choose>
<xsl:when test="$precedingZone">
<xsl:value-of select="$precedingZone/@DEPTHTO"/>
</xsl:when>
<xsl:otherwise>0.00</xsl:otherwise>
</xsl:choose>
<xsl:text>
</xsl:text>
</xsl:template>
</xsl:stylesheet>
Output
Flysand unchained 0.00
Flysand unchained 0.30
Flysand unchained 1.10
Flysand unchained 1.40
Drifting sand 1.70
Drifting sand 1.80
Drifting sand 2.20
Sand unchained 0.00
Sand unchained 0.30
Sand unchained 1.10
Sand unchained 1.40
fine sand 1.70
fine sand 1.80
fine sand 2.20
CodePudding user response:
You want to find the first (nearest) element on the preceding-sibling axis, and from there, you want to read the DEPTHTO attribute.
So: preceding-sibling::ZONE[1]/@DEPTHTO
Think of these select expressions as directions on a pirate map: face the palm tree and take 20 paces, then face the jagged rock and take 10 paces, then dig down 6 feet to find the buried treasure.
<xsl:transform version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<xsl:apply-templates select="ZONES/ZONE" />
</xsl:template>
<xsl:template match="ZONE">
<xsl:text>"</xsl:text>
<xsl:value-of select="@LAYER_DESC" />
<xsl:text>" "</xsl:text>
<xsl:value-of select="preceding-sibling::ZONE[1][@GROUP=current()/@GROUP]/@DEPTHTO" />
<xsl:if test="not(preceding-sibling::ZONE[1][@GROUP=current()/@GROUP]/@DEPTHTO)">0.00</xsl:if>
<xsl:text>"
</xsl:text>
</xsl:template>
</xsl:transform>
Output:
"Flysand unchained" "0.00"
"Flysand unchained" "0.30"
"Flysand unchained" "1.10"
"Flysand unchained" "1.40"
"Drifting sand" "1.70"
"Drifting sand" "1.80"
"Drifting sand" "2.20"
"Sand unchained" "0.00"
"Sand unchained" "0.30"
"Sand unchained" "1.10"
"Sand unchained" "1.40"
"fine sand" "1.70"
"fine sand" "1.80"
"fine sand" "2.20"
I thought the original requested output didn't take @GROUP into account? Or maybe it was my error.
The answer above makes few assumptions about how regular the input is. It doesn't assume that each element will be a ZONE or that each ZONE will have all the expected attributes. If you are more certain of the input, then the coding can make assumptions. For example:
<xsl:choose>
<xsl:when test="@GROUP=preceding-sibling::*[1]/@GROUP">
<xsl:value-of select="preceding-sibling::*[1]/@DEPTHTO"/>
</xsl:when>
<xsl:otherwise>0.00</xsl:otherwise>
</xsl:choose>