xsl-list
[Top] [All Lists]

[xsl] Flattening, grouping & ordering elements

2010-04-26 07:15:05
Hi,

Given the following (simplified) input:
<a>
  <b id="b1">
    <c>c1</c>
  </b>
  <b id="b2">
    <c>c2</c>
  </b>
  <b id="b3" special="true">
    <c>c3</c>
  </b>
  <d>d1</d>
  <d>d2</d>
  <e>e1</e>
  <e>e2</e>
  <f id="f1">
    <c>c4</c>
  </f>
  <f id="f2">
    <c>c5</c>
  </f>
  <f id="f3">
    <c>c6</c>
  </f>
  <c>c7</c>
</a>

I need to produce the following output:

x: f1
-----
   c4
-----
   f2
-----
   c5
-----
   f3
-----
   c6
-----
   b1
-----
   c1
-----
   b2
-----
   c2
-----
   b3
-----
   special
-----
   c3
-----
   c7
-----
   e1
-----
   e2
-----
   d1
-----
   d2

Where x is a fixed label that needs to be output on the first line.
Any of the elements could be missing, so x could just as well have to be output 
in front of "d1". Outputting the data could be as easy as nesting the necessary 
for loops, but the problems I'm facing is how to output the x without having 
countless checks to see if elements are missing and how to find the last line 
that can't have a border (in reality all of the above is outputted in a table, 
where the style of the last line needs to be different, the label is in a first 
column & the data in a second column). For example: the following outputs the 
elements in the correct order contains no lines. It will also be hard to 
maintain if at one point the order of the data should be output differently due 
to the if tests to output the label.

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="1.0">
  <xsl:output method="text" encoding="ASCII"/>
  <xsl:template match="/">
    <xsl:apply-templates select="a"/>
  </xsl:template>
  <xsl:template match="a">
    <xsl:if test="count(f) > 0">
      <xsl:text>x: </xsl:text>
    </xsl:if>
    <xsl:for-each select="f">
      <xsl:apply-templates select="."/>
      <xsl:for-each select="c">
        <xsl:apply-templates select="."/>
      </xsl:for-each>
    </xsl:for-each>
    <xsl:if test="(count(f) = 0) and (count(b) > 0)">
      <xsl:text>x: </xsl:text>
    </xsl:if>
    <xsl:for-each select="b">
      <xsl:apply-templates select="."/>
      <xsl:for-each select="c">
        <xsl:apply-templates select="."/>
      </xsl:for-each>
    </xsl:for-each>
    <xsl:if test="(count(f) = 0) and (count(b) = 0) and (count(c) > 0)">
      <xsl:text>x: </xsl:text>
    </xsl:if>
    <xsl:apply-templates select="c"/>
    <xsl:if test="(count(f) = 0) and (count(b) = 0) and (count(c) = 0) and 
(count(e) > 0)">
      <xsl:text>x: </xsl:text>
    </xsl:if>
    <xsl:apply-templates select="e"/>
    <xsl:if test="(count(f) = 0) and (count(b) = 0) and (count(c) = 0) and 
(count(e) = 0) and (count(d) > 0)">
      <xsl:text>x: </xsl:text>
    </xsl:if>
    <xsl:apply-templates select="d"/>
  </xsl:template>
  <xsl:template match="b|f">
    <xsl:value-of select="@id"/>
    <xsl:text>&#10;</xsl:text>
    <xsl:if test="@special = 'true'">
      <xsl:text>special&#10;</xsl:text>
    </xsl:if>
  </xsl:template>
  <xsl:template match="c|d|e">
    <xsl:value-of select="."/>
    <xsl:text>&#10;</xsl:text>
  </xsl:template>
</xsl:stylesheet>

My second thought was to group everything in one large for-each, in which case 
it would be easy to find the first & last line. But then I have no clue on how 
to get the order of the elements in the output right:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="1.0">
  <xsl:output method="text" encoding="ASCII"/>
  <xsl:template match="/">
    <xsl:apply-templates select="a"/>
  </xsl:template>
  <xsl:template match="a">
    <xsl:for-each select="f|f/c|b|b/c|c|e|d">
      <xsl:if test="position() = 1">
        <xsl:text>x: </xsl:text>
      </xsl:if>
      <xsl:apply-templates select="."/>
      <xsl:if test="position() != last()">
        <xsl:text>-----&#10;</xsl:text>
      </xsl:if>
    </xsl:for-each>
  </xsl:template>
  <xsl:template match="b|f">
    <xsl:value-of select="@id"/>
    <xsl:text>&#10;</xsl:text>
    <xsl:if test="@special = 'true'">
      <xsl:text>-----&#10;</xsl:text>
      <xsl:text>special&#10;</xsl:text>
    </xsl:if>
  </xsl:template>
  <xsl:template match="c|d|e">
    <xsl:value-of select="."/>
    <xsl:text>&#10;</xsl:text>
  </xsl:template>
</xsl:stylesheet>

Any suggestions on how to order the set in the second one?

Thanks in advances,

Fjoerie



--~------------------------------------------------------------------
XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list
To unsubscribe, go to: http://lists.mulberrytech.com/xsl-list/
or e-mail: <mailto:xsl-list-unsubscribe(_at_)lists(_dot_)mulberrytech(_dot_)com>
--~--

<Prev in Thread] Current Thread [Next in Thread>
  • [xsl] Flattening, grouping & ordering elements, Fjoerie <=