[xsl] ReqursivelySplittingNode_Set

Subject: [xsl] ReqursivelySplittingNode_Set
From: mankar@xxxxxxxxxxxxxxx
Date: Sun, 8 Aug 2004 18:30:39 +0300
Hallo,

I need to split the ORDINATES_ITEM node set of the following source xml
into three different node sets based on the positions of the ORDINATE_ITEM
elements.

So far i have come up with the xslt code that does this, considering the
source xml to be static.The problem is that it is not, because it is
generated dynamically each time.

The splitting positions are extracted from the number content of each
ELEM_INFO_ITEM[position() mod 3 = 1] which are for this
particular example 1, 3 and 8.Based on these values which will serve as
splitting positions for the
ORDINATES_ITEM node set, i would like to select ORDINATE_ITEM elements from
position 1
to position 2 in a node-set and then select ORDINATE_ITEM elements from
position 3
to position 7 in another node-set and finally select ORDINATE_ITEM elements
from position 8
to the last position in another node-set.

source xml

<?xml version="1.0" encoding="ISO-8859-7"?>
<ROWSET>
      <ROW num="1">
            <SHAPE>
                  <ELEM_INFO>
                        <ELEM_INFO_ITEM>1</ELEM_INFO_ITEM>
                        <ELEM_INFO_ITEM>1003</ELEM_INFO_ITEM>
                        <ELEM_INFO_ITEM>50</ELEM_INFO_ITEM>

                        <ELEM_INFO_ITEM>3</ELEM_INFO_ITEM>
                        <ELEM_INFO_ITEM>2003</ELEM_INFO_ITEM>
                        <ELEM_INFO_ITEM>50</ELEM_INFO_ITEM>

                        <ELEM_INFO_ITEM>8</ELEM_INFO_ITEM>
                        <ELEM_INFO_ITEM>2003</ELEM_INFO_ITEM>
                        <ELEM_INFO_ITEM>50</ELEM_INFO_ITEM>
                  </ELEM_INFO>
                  <ORDINATES>
                        <ORDINATES_ITEM>52</ORDINATES_ITEM>
                        <ORDINATES_ITEM>45</ORDINATES_ITEM>
                        <ORDINATES_ITEM>54</ORDINATES_ITEM>
                        <ORDINATES_ITEM>57</ORDINATES_ITEM>
                        <ORDINATES_ITEM>76</ORDINATES_ITEM>
                        <ORDINATES_ITEM>78</ORDINATES_ITEM>
                        <ORDINATES_ITEM>56</ORDINATES_ITEM>
                        <ORDINATES_ITEM>23</ORDINATES_ITEM>
                        <ORDINATES_ITEM>32</ORDINATES_ITEM>
                  </ORDINATES>
            </SHAPE>
      </ROW>
</ROWSET>


The xslt code i 've come up with  so far, produces the desired output for
this particular source xml!

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform";>
      <xsl:output indent="yes"/>
      <xsl:template match="/">
            <PolygonSet>
                  <xsl:for-each select="ROWSET/ROW">
                        <polygon>
                              <exterior>
                                    <xsl:for-each
select="SHAPE/ORDINATES/ORDINATES_ITEM">
                                          <xsl:choose>
                                                <xsl:when test="position()
&lt;
ancestor::SHAPE/ELEM_INFO/ELEM_INFO_ITEM[position() mod 3=1][2]">
                                                      <xsl:value-of
select="."/>
                                                      <xsl:text>
</xsl:text>
                                                </xsl:when>
                                          </xsl:choose>
                                    </xsl:for-each>
                              </exterior>
                              <interior>
                                    <xsl:for-each
select="SHAPE/ORDINATES/ORDINATES_ITEM">
                                          <xsl:choose>
                                                <xsl:when test="(position()
&gt;= ancestor::SHAPE/ELEM_INFO/ELEM_INFO_ITEM[position() mod 3=1][2]) and
(position() &lt; ancestor::SHAPE/ELEM_INFO/ELEM_INFO_ITEM[position() mod
3=1][3])">
                                                      <xsl:value-of
select="."/>
                                                      <xsl:text>
</xsl:text>
                                                </xsl:when>
                                          </xsl:choose>
                                    </xsl:for-each>
                              </interior>
                              <interior>
                                    <xsl:for-each
select="SHAPE/ORDINATES/ORDINATES_ITEM">
                                          <xsl:choose>
                                                <xsl:when test="position()
&gt;= ancestor::SHAPE/ELEM_INFO/ELEM_INFO_ITEM[position() mod 3=1][3] ">
                                                      <xsl:value-of
select="."/>
                                                      <xsl:text>
</xsl:text>
                                                </xsl:when>
                                          </xsl:choose>
                                    </xsl:for-each>
                              </interior>
                        </polygon>
                  </xsl:for-each>
            </PolygonSet>
      </xsl:template>
</xsl:stylesheet>

As you can see i am selecting the content of ORDINATE_ITEM elements with
positions position() &lt;ELEM_INFO_ITEM[position() mod 3 =1][2] which is
number 3 in this particular example as string content of an exterior
element, the content of ORDINATE_ITEM elements with positions
3=<position()<8 as string content of an interior element and the content of
ORDINATE_ITEM elements with positions 8=<position() as string content of
another exterior element.

<?xml version="1.0" encoding="UTF-16"?>
<PolygonSet>
      <polygon>
            <exterior>52 45 </exterior>
            <interior>54 57 76 78 56 </interior>
            <interior>23 32 </interior>
      </polygon>
</PolygonSet>


The problem is that the source xml is generated dynamically.This means that
i don't know from
the first place the exact number of splitting positions which is determined
by the
ELEM_INFO_ITEM[position() mod 3 = 1].This source xml has exactly nine
ELEM_INFO_ITEM elements,
while another may have 6 or 12 etch.The sure thing is that every source
will contain
six ELEM_INFO_ITEM elements or more and always the total number will be
multiple of three.

If the source xml for example, had 12 ELEM_INFO_ITEM elements, then i would
have 4
splitting positions and the desired output should contain one exterior
element and
three interior elements.If i have a source with six ELEM_INFO_ITEM
elements, then the output should have one exterior plus
one interior elements.


So, for each source i want to create exactly one exterior element which
will contain all
ORDINATE_ITEM element's content that their position is less than
ELEM_INFO_ITEM[position() mod 3 =1][2]
and as many interior elements as the ELEM_INFO_ITEM[position() mod3=1] are,
minus 1.

I already handle the first issue in my xsl with :

<exterior>
                                    <xsl:for-each
select="SHAPE/ORDINATES/ORDINATES_ITEM">
                                          <xsl:choose>
                                                <xsl:when test="position()
&lt;
ancestor::SHAPE/ELEM_INFO/ELEM_INFO_ITEM[position() mod 3=1][2]">
                                                      <xsl:value-of
select="."/>
                                                      <xsl:text>
</xsl:text>
                                                </xsl:when>
                                          </xsl:choose>
                                    </xsl:for-each>
                              </exterior>


I could also handle the automatic creation of as many interior elements as
the
ELEM_INFO_ITEM[position() mod3=1] are, minus 1, by incorporating in my code
something like:

<xsl:for-each
select="SHAPE/ELEM_INFO/ELEM_INFO_ITEM[position()mod3=1][position()
&gt;1]">
<interior>...</interior>
</xsl:for-each>

My big problem is how to recursively apply the relevant ORDINATES_ITEM
element's content to each interior.

I mean the first interior (because there always be at least one interior)
should contain ORDINATES_ITEM content whose position is always greater than
or equal to ELEM_INFO_ITEM[position() mod 3=1][2]and less than
ELEM_INFO_ITEM[position() mod 3=1][3], if there is such position. Otherwise
it should just contain ORDINATES_ITEM content whose position is always
greater than or equal to ELEM_INFO_ITEM[position() mod 3=1][2].

Similarly the second interior element, if one exists, should contain
ORDINATES_ITEM content whose position is always greater than or equal to
ELEM_INFO_ITEM[position() mod 3=1][3] and less than
ELEM_INFO_ITEM[position() mod 3=1][4], if there is such position etc.

And the last interior element should exactly contain ORDINATES_ITEM content
whose position is always greater than or equal to ELEM_INFO_ITEM[position()
mod 3=1][last()].

How can i recursively apply the relevant ORDINATE_ITEM contents to the each
interior element?

Regards
Manousos
Athens

Current Thread