XSL to create folders based on attribute
I am using XSL to transform XML to KML to be viewed in Google Earth. I would to be able to create folders for each "IT_Type" in the XML sample below
Currently, the XML is being transformed into a folder structure like this:
- Point
- VSS1
- VSS2
- Cab1
- Cab2
- DMS1
- DMS2
- Line
- From:To:
- From:To:
- From:To:
It needs to be structured into folders like this, with a folder for each IT_Type under the Point and Line parent folders.
- Point
- VSS
- VSS1
- VSS2
- Cabinet
- Cab1
- Cab2
- DMS
- DMS1
- DMS2
- VSS
- Line
- Handhole
- From:To:
- Cabinet
- From:To:
- Other
- From:To:
- Handhole
What is the best way to go about setting up the XSL for this? Will performance be an issue on large data sets?
Any advice or code sample is appreciated.
Thank you.
Please see below for sample XML
<Parents>
<Point>
<Row IT_ID="116" IT_Name="VSS1" IT_Type="VSS" GPSLat="43.953000000000" GPSLong="-85.671800000000" />
<Row IT_ID="117" IT_Name="VSS2" IT_Type="VSS" GPSLat="43.966900000000" GPSLong="-85.678900000000" />
<Row IT_ID="122" IT_Name="Cab1" IT_Type="Cabinet" GPSLat="43.903100000000" GPSLong="-85.677100000000" />
<Row IT_ID="123" IT_Name="Cab2" IT_Type="Cabinet" GPSLat="43.913500000000" GPSLong="-85.677300000000" />
<Row IT_ID="254" IT_Name="DMS1" IT_Type="DMS" GPSLat="43.903100000000" GPSLong="-85.677100000000" />
<Row IT_ID="255" IT_Name="DMS2" IT_Type="DMS" GPSLat="43.989400000000" GPSLong="-85.676800000000" />
</Point>
<Line>
<Row LINE_ID="1117" IT_Type="Handhole" FROM_SYSTEM_ID="2127" TO_SYSTEM_ID="1947" FromLat="43.438474034300" FromLong="-83.195331982500" ToLat="43.437072542900" ToLong="-83.193657308800">
<Row2 LINE_ID="1117" CONDUIT_NUMBER="1" CONDUIT_TYPE="Fiber" FIBER_NUMBER="1" FIBER_TYPE="Trunk" STRANDS="96" />
<Row2 LINE_ID="1117" CONDUIT_NUMBER="2" CONDUIT_TYPE="Empty" FIBER_NUMBER="" FIBER_TYPE="" STRANDS="" />
<Row2 LINE_ID="1117" CONDUIT_NUMBER="3" CONDUIT_TYPE="Empty" FIBER_NUMBER="" FIBER_TYPE="" STRANDS="" />
<Row2 LINE_ID="1117" CONDUIT_NUMBER="4" CONDUIT_TYPE="Empty" FIBER_NUMBER="" FIBER_TYPE="" STRANDS="" />
</Row>
<Row LINE_ID="997" IT_Type="Cabinet" FROM_SYSTEM_ID="2011" TO_SYSTEM_ID="2012" FromLat="43.482705558800" FromLong="-83.260130135400" ToLat="43.482694479700" ToLong="-83.260107590500">
<Row2 LINE_ID="997" CONDUIT_NUMBER="1" CONDUIT_TYPE="Other" FIBER_NUMBER="" FIBER_TYPE="" STRANDS="" />
</Row>
<Row LINE_ID="1220" IT_Type="Other" FROM_SYSTEM_ID="2415" TO_SYSTEM_ID="2413" FromLat="43.624664303600" FromLong="-83.086848805700" ToLat="43.624645615600" ToLong="-83.086770805500">
<Row2 LINE_ID="1220" CONDUIT_NUMBER="1" CONDUIT_TYPE="Fiber" FIBER_NUMBER="1" FIBER_TYPE="Dist" STRANDS="12" />
<Row2 LINE_ID="1220" CONDUIT_NUMBER="2" CONDUIT_TYPE="Electric" FIBER_NUMBER="" FIBER_TYPE="" STRANDS="" />
</Row>
</Line>
</Parents>
Please see below for my XSL:
<xsl:template match="Parents">
<Folder>
<name>
Point
</name>
<xsl:for-each select="Point/Row">
<Placemark>
<name>
<xsl:value-of select="@IT_Name"/>
</name>
<description>
<xsl:value-of select="@Location"/>
</description>
<styleUrl>
<xsl:value-of select="concat($hash,@IT_Type)"/>
</styleUrl>
<Point>
<c开发者_如何学运维oordinates>
<xsl:value-of select="@GPSLong"/>,
<xsl:value-of select="@GPSLat"/>
</coordinates>
</Point>
</Placemark>
</xsl:for-each>
</Folder>
<Folder>
<name>
Line
</name>
<xsl:for-each select="Line/Row">
<Placemark>
<name>
From: <xsl:value-of select="@FROM_SYSTEM_ID"/> to: <xsl:value-of select="@TO_SYSTEM_ID"/>
</name>
<description>
<xsl:value-of select="@CONDUIT_NUMBER"/>
</description>
<styleUrl>
<xsl:value-of select="concat($hash,@IT_Type)"/>
</styleUrl>
<LineString>
<tessellate>1</tessellate>
<coordinates>
<xsl:value-of select="@FromLong"/>,<xsl:value-of select="@FromLat"/>,0 <xsl:value-of select="@ToLong"/>,<xsl:value-of select="@ToLat"/>,0
</coordinates>
</LineString>
</Placemark>
</xsl:for-each>
</Folder>
</xsl:template>
Sorry for having completely revised your initial template, but the common way to do this (in XSLT 1.0) is by applying Meunchian's method on a multi-level grouping. In your specific case, you can create a xsl:key
based on concatenation of @IT_Type
and the parent element of Row
.
For instance, this XSLT 1.0 (tested under Saxon 6.5)
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kIT_Type"
match="Row"
use="concat(
name(parent::node()),@IT_Type
)"/>
<xsl:template match="Parents/*">
<Folder>
<name><xsl:value-of select="name()"/></name>
<xsl:apply-templates select="Row[
generate-id(.)
=
generate-id(key('kIT_Type',
concat(name(parent::node()),@IT_Type))[1])
]"/>
</Folder>
</xsl:template>
<xsl:template match="Row">
<Folder>
<name><xsl:value-of select="@IT_Type"/></name>
<xsl:apply-templates select="key('kIT_Type',
concat(name(parent::node()),@IT_Type))"
mode="placemark"/>
</Folder>
</xsl:template>
<xsl:template match="Row[parent::Point]" mode="placemark">
<Placemark>
<name>
<xsl:value-of select="@IT_Name"/>
</name>
<description>
<!--xsl:value-of select="@Location"/-->
</description>
<styleUrl>
<!--xsl:value-of select="concat($hash,@IT_Type)"/-->
</styleUrl>
<Point>
<coordinates>
<xsl:value-of select="@GPSLong"/>,
<xsl:value-of select="@GPSLat"/>
</coordinates>
</Point>
</Placemark>
</xsl:template>
<xsl:template match="Row[parent::Line]" mode="placemark">
<Placemark>
<name>
From: <xsl:value-of select="@FROM_SYSTEM_ID"/> to: <xsl:value-of select="@TO_SYSTEM_ID"/>
</name>
<description>
<xsl:value-of select="@CONDUIT_NUMBER"/>
</description>
<styleUrl>
<!-- xsl:value-of select="concat($hash,@IT_Type)"/-->
</styleUrl>
<LineString>
<tessellate>1</tessellate>
<coordinates>
<xsl:value-of select="@FromLong"/>,<xsl:value-of select="@FromLat"/>,0 <xsl:value-of select="@ToLong"/>,<xsl:value-of select="@ToLat"/>,0
</coordinates>
</LineString>
</Placemark>
</xsl:template>
<xsl:template match="Row2"/>
</xsl:stylesheet>
Applied on your input, produces the RTF:
<Folder>
<name>Point</name>
<Folder>
<name>VSS</name>
<Placemark>
<name>VSS1</name>
<description/>
<styleUrl/>
<Point>
<coordinates>-85.671800000000,
43.953000000000</coordinates>
</Point>
</Placemark>
<Placemark>
<name>VSS2</name>
<description/>
<styleUrl/>
<Point>
<coordinates>-85.678900000000,
43.966900000000</coordinates>
</Point>
</Placemark>
</Folder>
<Folder>
<name>Cabinet</name>
<Placemark>
<name>Cab1</name>
<description/>
<styleUrl/>
<Point>
<coordinates>-85.677100000000,
43.903100000000</coordinates>
</Point>
</Placemark>
<Placemark>
<name>Cab2</name>
<description/>
<styleUrl/>
<Point>
<coordinates>-85.677300000000,
43.913500000000</coordinates>
</Point>
</Placemark>
</Folder>
<Folder>
<name>DMS</name>
<Placemark>
<name>DMS1</name>
<description/>
<styleUrl/>
<Point>
<coordinates>-85.677100000000,
43.903100000000</coordinates>
</Point>
</Placemark>
<Placemark>
<name>DMS2</name>
<description/>
<styleUrl/>
<Point>
<coordinates>-85.676800000000,
43.989400000000</coordinates>
</Point>
</Placemark>
</Folder>
</Folder>
<Folder>
<name>Line</name>
<Folder>
<name>Handhole</name>
<Placemark>
<name>
From: 2127 to: 1947</name>
<description/>
<styleUrl/>
<LineString>
<tessellate>1</tessellate>
<coordinates>-83.195331982500,43.438474034300,0 -83.193657308800,43.437072542900,0
</coordinates>
</LineString>
</Placemark>
</Folder>
<Folder>
<name>Cabinet</name>
<Placemark>
<name>
From: 2011 to: 2012</name>
<description/>
<styleUrl/>
<LineString>
<tessellate>1</tessellate>
<coordinates>-83.260130135400,43.482705558800,0 -83.260107590500,43.482694479700,0
</coordinates>
</LineString>
</Placemark>
</Folder>
<Folder>
<name>Other</name>
<Placemark>
<name>
From: 2415 to: 2413</name>
<description/>
<styleUrl/>
<LineString>
<tessellate>1</tessellate>
<coordinates>-83.086848805700,43.624664303600,0 -83.086770805500,43.624645615600,0
</coordinates>
</LineString>
</Placemark>
</Folder>
</Folder>
精彩评论