Forum Moderators: open
Here's a simplified example of the type of (non-Project) XML I'd like to transform:
<sibling level="1"></sibling>
<sibling level="1"></sibling>
<sibling level="2"></sibling>
<sibling level="2"></sibling>
<sibling level="3"></sibling>
<sibling level="1"></sibling>
<sibling level="1"></sibling>
<sibling level="2"></sibling>
<sibling level="1"></sibling>
Level 2 siblings actually belong inside the preceding Level 1 sibling, and Level 3 ones go inside Level 2, etc:
<sibling level="1"></sibling>
<sibling level="1">
<sibling level="2"></sibling>
<sibling level="2">
<sibling level="3"></sibling>
</sibling>
</sibling>
<sibling level="1"></sibling>
<sibling level="1">
<sibling level="2"></sibling>
</sibling>
<sibling level="1"></sibling>
Now, XSLT doesn't have a way to break a for-each loop, which totally scrags the way I'd do it in C++ or PHP (Keep going until you hit a higher level), so that means that I should use XPath to create appropriate nodesets.
The problem is that I can't actually figure out a way to do this easily. I'm using a recursive template to create the nested XHTML from the XML, but the darn thing keeps getting ALL of the Level 2 siblings, when I only want the first ones to be considered.
Any ideas?
intuitively, this seems like something XSLT should be able to do. I don't know how, but my gut feeling is this problem isn't "way out there" like trying to translate from English to Swahili using array keys, or drawing trigonometry graphs using ascii art.
This isn't urgent
XML File:
<?xml version="1.0" encoding="utf-8" ?>
<siblings>
<sibling level="1"></sibling>
<sibling level="1"></sibling>
<sibling level="2"></sibling>
<sibling level="2"></sibling>
<sibling level="3"></sibling>
<sibling level="2"></sibling>
<sibling level="1"></sibling>
<sibling level="1"></sibling>
<sibling level="2"></sibling>
<sibling level="1"></sibling>
</siblings>
XSL File:
[1]
<?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" omit-xml-declaration="no" encoding="utf-8"/>
<xsl:template match="/">
<siblings>
<xsl:apply-templates select="siblings/sibling[1]" mode="list-item"/>
</siblings>
</xsl:template>
<xsl:template match="sibling" mode="list-item">
<xsl:param name="level" select="1"/>
<xsl:param name="position" select="1"/>
<xsl:if test="number(@level)=$level">
<sibling>
<xsl:for-each select="@*">
<xsl:attribute name="{name()}">
<xsl:value-of select="."/>
</xsl:attribute>
</xsl:for-each>
<xsl:apply-templates select="following-sibling::sibling[1]" mode="list-item">
<xsl:with-param name="level" select="$level+1"/>
<xsl:with-param name="position" select="$position+1"/>
</xsl:apply-templates>
</sibling>
<xsl:apply-templates select="following-sibling::sibling[1]" mode="list-sibling">
<xsl:with-param name="level" select="$level"/>
<xsl:with-param name="position" select="$position+1"/>
</xsl:apply-templates>
</xsl:if>
</xsl:template>
<xsl:template match="sibling" mode="list-sibling">
<xsl:param name="level" select="1"/>
<xsl:param name="position" select="1"/>
<xsl:choose>
<xsl:when test="number(@level)>$level">
<xsl:apply-templates select="following-sibling::sibling[1]" mode="list-sibling">
<xsl:with-param name="level" select="$level"/>
<xsl:with-param name="position" select="$position+1"/>
</xsl:apply-templates>
</xsl:when>
<xsl:when test="number(@level)=$level">
<xsl:apply-templates select="." mode="list-item">
<xsl:with-param name="level" select="$level"/>
<xsl:with-param name="position" select="$position"/>
</xsl:apply-templates>
</xsl:when>
<xsl:otherwise><!-- Terminate recursion --></xsl:otherwise>
</xsl:choose>
</xsl:template>
</xsl:stylesheet>
Really enjoyed it! Thanks! I hope my solution is adequate and on par with your standards.
Cheers,
Ivan
[edited by: httpwebwitch at 12:15 pm (utc) on June 11, 2008]
[edit reason] added formatting to prevent text formatt - I'll sticky you with explanation [/edit]
My standards? Right now, it's hacking at something until it looks roughly akin to what I want.
I don't think it will be a problem.
I'll post any tweaks or improvements here.
Thanks!
By the way, what a great inaugural post!
Welcome to WebmasterWorld!
XML is a quiet topic compared to others like PHP and Javascript. But still, when someone needs help with XML, XSLT, XPATH, etc., this is the place.
Before diving in too far, stop and actually read the TOS (we do take it seriously, to the letter, and it is enforced - link is in the footer)
Cheers
Ian