ebene Struktur in Baumstruktur
Alex Schneider
- xsl
Hallo,
ich weiß, ich habe schon so einen Artikel gesehen -ich finde ihn nur nicht.
Es handelt sich um diese Struktur:
<verzeichnis>
<object level="1"/>
<object level="2"/>
<object level="3"/>
<object level="1"/>
<object level="2"/>
<object level="2"/>
<object level="1"/>
<object level="2"/>
<object level="3"/>
<object level="2"/>
</verzeichnis>
Als Baum sollte das dann so Aussehen:
<verzeichnis>
<object level="1">
<object level="2">
<object level="3"/>
</objekt>
</objekt>
<object level="1">
<object level="2"/>
<object level="2"/>
<objekt>
<object level="1">
<object level="2">
<object level="3"/>
</objekt>
<object level="2"/>
<object>
</verzeichnis>
Die Objekte haben selbstverständlich weitere Kindelemente und die Objekttiefe sollte nicht beschränkt sein.
Ich bin bis hierhin gelangt:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<verzeichnis>
<xsl:apply-templates select="verzeichnis/object[attribute::level=1]"/>
</verzeichnis>
</xsl:template>
<xsl:template match="verzeichnis/object">
<object>
<xsl:attribute name="level">
<xsl:value-of select="./@level"/>
</xsl:attribute>
<xsl:variable name="descendant">
<xsl:value-of select="./@level + 1"/>
</xsl:variable>
<xsl:if test="$descendant = following-sibling::object[1]/@level">
<xsl:apply-templates select="following-sibling::object[attribute::level=$descendant]"/>
<xsl:for-each select="following-sibling::object[attribute::level=$descendant]">
<xsl:apply-templates select="following-sibling::object[attribute::level=$descendant]"/>
</xsl:for-each>
</xsl:if>
</object>
</xsl:template>
</xsl:stylesheet>
Gruß Alex
Ich habe es nun doch selber lösen können.
Hier das XSLT-Skript:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
<xsl:template match="/">
<VERZEICHNIS>
<xsl:apply-templates select="//object[attribute::level=1]" mode="NEXT">
<!-- This selects ALL elements <object level="1"> -->
<xsl:with-param name="LIMES" select="number(1)"/>
<!-- start-value of the parameter $LIMES is 1 -->
</xsl:apply-templates>
</VERZEICHNIS>
</xsl:template>
<xsl:template match="object" mode="NEXT">
<xsl:param name="LIMES"/>
<xsl:if test="@level = $LIMES">
<!-- These are the searched elements -->
<xsl:element name="DING">
<xsl:attribute name="EBENE">
<xsl:value-of select="./@level"/>
</xsl:attribute>
<xsl:if test="$LIMES + 1 = following-sibling::object[1]/@level">
<!-- Is the next object-element one level higher? -->
<xsl:apply-templates select="following-sibling::object[1]" mode="NEXT">
<!-- recursion, search on -->
<xsl:with-param name="LIMES" select="$LIMES + 1"/>
<!-- In XSL, the variables are only valid inside their frame, C++ like! -->
</xsl:apply-templates>
</xsl:if>
</xsl:element>
</xsl:if>
<xsl:if test="$LIMES <= following-sibling::object[1]/@level">
<!-- Is the next object-element on the same level? -->
<xsl:apply-templates select="following-sibling::object[1]" mode="NEXT">
<!-- recursion, search on -->
<xsl:with-param name="LIMES" select="$LIMES"/>
</xsl:apply-templates>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
Nur noch eine kleine Korrektur.
Am Anfang muss es so aussehen. Es muss "object[1]" stehen. Im vorherigen Skript wählt er alle aus.
<xsl:template match="/">
<VERZEICHNIS>
<xsl:apply-templates select="//object[1][attribute::level=1]" mode="NEXT">
<xsl:with-param name="LIMES" select="number(1)"/>
<!-- start-value of the parameter $LIMES is 1 -->
</xsl:apply-templates>
</VERZEICHNIS>
</xsl:template>