Welcome to WebmasterWorld Guest from 23.20.110.176

Forum Moderators: httpwebwitch

Message Too Old, No Replies

Sorting Out Elements, Based on Position, Relative to Siblings

An annoying XSLT conundrum

     
5:45 pm on Jun 10, 2008 (gmt 0)

Senior Member

WebmasterWorld Senior Member 10+ Year Member

joined:Feb 21, 2005
posts: 1526
votes: 0


I'm running into an annoying wall, parsing MS Project XML. When exported from Project itself, no problem. However, I have another app that exports project files, and it isn't so easy to transform. This isn't urgent, as all I need to do is open and re-save from Project, but I'd shore like to be able to transform it all.

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?

7:37 pm on June 10, 2008 (gmt 0)

Moderator This Forum from CA 

WebmasterWorld Administrator httpwebwitch is a WebmasterWorld Top Contributor of All Time 10+ Year Member

joined:Aug 29, 2003
posts:4059
votes: 0


oy, cm! you can't just post a simple one can you? :P

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

well that's a good thing.
I'll give it a shot... and I'll probably have to ask around among some other XSLT cogniscienti
7:42 pm on June 10, 2008 (gmt 0)

Senior Member

WebmasterWorld Senior Member 10+ Year Member

joined:Feb 21, 2005
posts: 1526
votes: 0


this seems like something XSLT should be able to do.

I know that feeling. I may have my head stuck too far up my procedural programming space. That tends to be my biggest blocker with XSLT.

Thanks for any help.

12:30 am on June 11, 2008 (gmt 0)

New User

5+ Year Member

joined:June 10, 2008
posts:2
votes: 0


What a beautiful problem! 3 hours of playing and viola!

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)&gt;$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]

12:57 am on June 11, 2008 (gmt 0)

Senior Member

WebmasterWorld Senior Member 10+ Year Member

joined:Feb 21, 2005
posts: 1526
votes: 0


Looks like it makes sense. I'll give it a whack, and see what happens.

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!

5:27 am on June 11, 2008 (gmt 0)

Moderator This Forum from CA 

WebmasterWorld Administrator httpwebwitch is a WebmasterWorld Top Contributor of All Time 10+ Year Member

joined:Aug 29, 2003
posts:4059
votes: 0


Welcome to WebmasterWorld, mrVano!
It's great to have another XSLT expert aboard. Go into the Control Panel, click "Forum Watch List", and subscribe to this forum (and others, if you like). Then you'll get an email alert whenever a new topic is started here.

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

2:05 pm on June 11, 2008 (gmt 0)

Moderator This Forum from CA 

WebmasterWorld Administrator httpwebwitch is a WebmasterWorld Top Contributor of All Time 10+ Year Member

joined:Aug 29, 2003
posts:4059
votes: 0


cm: I tried mrVano's solution in oXygen, and indeed - it works!
3:20 pm on June 11, 2008 (gmt 0)

Senior Member

WebmasterWorld Senior Member 10+ Year Member

joined:Feb 21, 2005
posts: 1526
votes: 0


It works.

I had to mangle it a bit to fit the real world implementation, but the stylesheet works.

Thanks, Ivan!