homepage Welcome to WebmasterWorld Guest from 54.145.191.14
register, free tools, login, search, pro membership, help, library, announcements, recent posts, open posts,
Become a Pro Member
Home / Forums Index / Code, Content, and Presentation / XML Development
Forum Library, Charter, Moderators: httpwebwitch

XML Development Forum

    
Sorting Out Elements, Based on Position, Relative to Siblings
An annoying XSLT conundrum
cmarshall

WebmasterWorld Senior Member 5+ Year Member



 
Msg#: 3671431 posted 5:45 pm on Jun 10, 2008 (gmt 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?

 

httpwebwitch

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



 
Msg#: 3671431 posted 7:37 pm on Jun 10, 2008 (gmt 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

cmarshall

WebmasterWorld Senior Member 5+ Year Member



 
Msg#: 3671431 posted 7:42 pm on Jun 10, 2008 (gmt 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.

mrVano

5+ Year Member



 
Msg#: 3671431 posted 12:30 am on Jun 11, 2008 (gmt 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]

cmarshall

WebmasterWorld Senior Member 5+ Year Member



 
Msg#: 3671431 posted 12:57 am on Jun 11, 2008 (gmt 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!

httpwebwitch

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



 
Msg#: 3671431 posted 5:27 am on Jun 11, 2008 (gmt 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

httpwebwitch

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



 
Msg#: 3671431 posted 2:05 pm on Jun 11, 2008 (gmt 0)

cm: I tried mrVano's solution in oXygen, and indeed - it works!

cmarshall

WebmasterWorld Senior Member 5+ Year Member



 
Msg#: 3671431 posted 3:20 pm on Jun 11, 2008 (gmt 0)

It works.

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

Thanks, Ivan!

Global Options:
 top home search open messages active posts  
 

Home / Forums Index / Code, Content, and Presentation / XML Development
rss feed

All trademarks and copyrights held by respective owners. Member comments are owned by the poster.
Home ¦ Free Tools ¦ Terms of Service ¦ Privacy Policy ¦ Report Problem ¦ About ¦ Library ¦ Newsletter
WebmasterWorld is a Developer Shed Community owned by Jim Boykin.
© Webmaster World 1996-2014 all rights reserved