XSLT Transform Vector to Array

Discussion in 'XML' started by Gary Huntress, Aug 13, 2004.

  1. Hi,

    I'm having trouble with an xslt transform. I'm trying to transform a
    vector into an array of width N. For example here is my vector:

    <data>
    <x id="1">1.2</x>
    <x id="2">.2</x>
    <x id="3">.87</x>
    <x id="4">.333</x>
    <x id="5">.4442</x>
    <x id="6">1.1</x>
    <x id="7">.8</x>
    <x id="8">.6543</x>
    <x id="9">.8761</x>
    <x id="10">1</x>
    <x id="11">.99</x>
    <x id="12">.2</x>
    </data>

    and given N=4 I want to transform it to

    <array>
    <row id="1">
    <x id="1">1.2</x>
    <x id="2">.2</x>
    <x id="3">.87</x>
    <x id="4">.333</x>
    </row>
    <row id="2">
    <x id="1">.4442</x>
    <x id="2">1.1</x>
    <x id="3">.8</x>
    <x id="4">.6543</x>
    </row>
    <row id="3">
    <x id="1">.8761</x>
    <x id="2">1</x>
    <x id="3">.99</x>
    <x id="4">.2</x>
    </row>
    </array>

    I can successfully use @id mod $N to identify each <row> but I have
    not found a way to properly create the output. Here is a failed
    attempt:

    <xsl:template match="x">
    <xsl:choose>
    <xsl:when test="(@id mod 4)=1">
    <row>
    <x><xsl:value-of select="."/></x>
    </row>
    </xsl:when>
    <xsl:eek:therwise>
    <x><xsl:value-of select="."/></x>
    </xsl:eek:therwise>
    </xsl:choose>
    </xsl:template>

    The "otherwise" <x> elements are not properly nested in the <row> and
    I don't know how to make them children of the newly created <row>.

    Should I be using an axis here? Or am I missing an obvious solution?

    Thx,

    Gary H.
    Gary Huntress, Aug 13, 2004
    #1
    1. Advertising

  2. > The "otherwise" <x> elements are not properly nested in the <row> and
    > I don't know how to make them children of the newly created <row>.


    I see two solutions :

    1/ The quick'n dirty one : use text output, and CDATA section

    Thus you will be able to <![CDATA[</row><row>]]> :

    <?xml version="1.0"?>
    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:eek:utput method = "text" indent="yes" />
    <xsl:strip-space elements="*" />

    <xsl:template match="/">
    <![CDATA[<row>]]>
    <xsl:apply-templates />
    <![CDATA[</row>]]>
    </xsl:template>

    <xsl:template match="x">
    <xsl:choose>
    <xsl:when test="(@id mod 4)=0">
    <!--<row> -->
    <![CDATA[<x>]]><xsl:value-of select="."/><![CDATA[</x>]]>
    <![CDATA[</row>
    <row>]]>
    </xsl:when>
    <xsl:eek:therwise>
    <![CDATA[<x>]]><xsl:value-of select="."/><![CDATA[</x>]]>
    </xsl:eek:therwise>
    </xsl:choose>
    </xsl:template>

    </xsl:stylesheet>

    Improvements should be done to remove the trailing <row></row> if it is
    unacceptable.


    2/ Another way, based on modes

    <?xml version="1.0"?>
    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:variable name="N">4</xsl:variable>

    <xsl:template match="/">
    <array>
    <xsl:apply-templates />
    </array>
    </xsl:template>

    <xsl:template match="x">
    <xsl:if test="(@id mod $N) = 1">
    <row>
    <!-- Use this for ordered contents, quicker
    <xsl:apply-templates select="current()" mode="display" />
    <xsl:apply-templates select="following-sibling::*[position() &lt;
    $N]" mode="display" />
    -->
    <!-- Use this for non-ordered contents -->
    <xsl:apply-templates select="../x[(@id &gt;=current()/@id) and (@id
    &lt; current()/@id + $N)]" mode="display" />
    </row>
    </xsl:if>
    </xsl:template>

    <xsl:template match="x" mode="display">
    <x><xsl:apply-templates /></x>
    </xsl:template>

    </xsl:stylesheet>

    Hth

    --
    Rémi Peyronnet
    =?ISO-8859-1?Q?R=E9mi_Peyronnet?=, Aug 13, 2004
    #2
    1. Advertising

  3. Gary Huntress

    Marrow Guest

    Hi Gary,

    Try something like...

    <?xml version="1.0"?>
    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:eek:utput method="xml" indent="yes"/>
    <xsl:param name="array_width" select="4"/>

    <xsl:template match="data">
    <array>
    <xsl:apply-templates select="x[(position() mod $array_width = 1) or
    ($array_width = 1)]" mode="row-start"/>
    </array>
    </xsl:template>

    <xsl:template match="x" mode="row-start">
    <row id="{position()}">
    <xsl:copy-of select=". | following-sibling::x[position() &lt;
    $array_width]"/>
    </row>
    </xsl:template>

    </xsl:stylesheet>


    HTH
    Marrow
    http://www.marrowsoft.com - home of Xselerator (XSLT IDE and debugger)
    http://www.topxml.com/Xselerator

    "Gary Huntress" <> wrote in message
    news:...
    > Hi,
    >
    > I'm having trouble with an xslt transform. I'm trying to transform a
    > vector into an array of width N. For example here is my vector:
    >
    > <data>
    > <x id="1">1.2</x>
    > <x id="2">.2</x>
    > <x id="3">.87</x>
    > <x id="4">.333</x>
    > <x id="5">.4442</x>
    > <x id="6">1.1</x>
    > <x id="7">.8</x>
    > <x id="8">.6543</x>
    > <x id="9">.8761</x>
    > <x id="10">1</x>
    > <x id="11">.99</x>
    > <x id="12">.2</x>
    > </data>
    >
    > and given N=4 I want to transform it to
    >
    > <array>
    > <row id="1">
    > <x id="1">1.2</x>
    > <x id="2">.2</x>
    > <x id="3">.87</x>
    > <x id="4">.333</x>
    > </row>
    > <row id="2">
    > <x id="1">.4442</x>
    > <x id="2">1.1</x>
    > <x id="3">.8</x>
    > <x id="4">.6543</x>
    > </row>
    > <row id="3">
    > <x id="1">.8761</x>
    > <x id="2">1</x>
    > <x id="3">.99</x>
    > <x id="4">.2</x>
    > </row>
    > </array>
    >
    > I can successfully use @id mod $N to identify each <row> but I have
    > not found a way to properly create the output. Here is a failed
    > attempt:
    >
    > <xsl:template match="x">
    > <xsl:choose>
    > <xsl:when test="(@id mod 4)=1">
    > <row>
    > <x><xsl:value-of select="."/></x>
    > </row>
    > </xsl:when>
    > <xsl:eek:therwise>
    > <x><xsl:value-of select="."/></x>
    > </xsl:eek:therwise>
    > </xsl:choose>
    > </xsl:template>
    >
    > The "otherwise" <x> elements are not properly nested in the <row> and
    > I don't know how to make them children of the newly created <row>.
    >
    > Should I be using an axis here? Or am I missing an obvious solution?
    >
    > Thx,
    >
    > Gary H.
    Marrow, Aug 14, 2004
    #3
  4. <xsl:variable name="N" select="4"/>

    <xsl:template match="data">
    <array>
    <xsl:for-each select="x[position() mod $N = 1]">
    <row>
    <xsl:for-each select=".|following-sibling::x[position() &lt; $N]">
    <x id="position()"><xsl:value-of select="."/></x>
    </xsl:for-each>
    </row>
    </xsl:for-each>
    </array>
    </xsl:template>
    David Carlisle, Aug 16, 2004
    #4
  5. Rémi Peyronnet <> wrote in message news:<cfiuo4$ue$>...
    > > The "otherwise" <x> elements are not properly nested in the <row> and
    > > I don't know how to make them children of the newly created <row>.

    >
    > I see two solutions :
    >
    > 1/ The quick'n dirty one : use text output, and CDATA section
    >
    > Thus you will be able to <![CDATA[</row><row>]]> :


    Sorry to slur your coding style, sir, but AAARGH! KILL IT!

    Use the mod operator to select every n'th <x> element, then sweep over
    "self::x|following-sibling::x[position() &lt; $n]" to produce each
    row.
    --
    Robin Johnson
    Lead Developer, enCircle Solutions Ltd.
    first initial last name at encircle dot co dot uk
    Robin Johnson, Aug 16, 2004
    #5
  6. Robin Johnson a écrit :

    >>1/ The quick'n dirty one : use text output, and CDATA section

    >
    > Sorry to slur your coding style, sir, but AAARGH! KILL IT!


    Of course, you're right ; that is why there was a second and recommended
    solution in my post :)

    > Use the mod operator to select every n'th <x> element, then sweep over
    > "self::x|following-sibling::x[position() &lt; $n]" to produce each
    > row.


    Does only work if elements are sorted, as stated in my second solution :
    "
    <!-- Use this for ordered contents, quicker
    <xsl:apply-templates select="current()" mode="display" />
    <xsl:apply-templates select="following-sibling::*[position() &lt;
    $N]" mode="display" />
    -->
    <!-- Use this for non-ordered contents -->
    <xsl:apply-templates select="../x[(@id &gt;=current()/@id) and (@id
    &lt; current()/@id + $N)]" mode="display" />
    "

    But I still think the first solution has to be thought for very special
    cases much more complicated with the second version, and for codes only
    used once. Wasn't the case here, I agree.

    --
    Rémi Peyronnet
    =?ISO-8859-1?Q?R=E9mi_Peyronnet?=, Aug 17, 2004
    #6
  7. On Tue, 17 Aug 2004 20:37:33 +0200, Rémi Peyronnet
    <> wrote:
    > Robin Johnson a écrit :
    >> Use the mod operator to select every n'th <x> element, then sweep over
    >> "self::x|following-sibling::x[position() &lt; $n]" to produce each
    >> row.

    >
    >Does only work if elements are sorted, as stated in my second solution :


    Noted.

    >But I still think the first solution has to be thought for very special
    >cases much more complicated with the second version, and for codes only
    >used once.


    Yes, I've done the same myself in a few cases (notably when
    suppressing output escaping in attribute values*), but I'm not proud.

    * There's a saxon extension for that now, of course.
    --
    Robin Johnson
    Lead Developer, enCircle Solutions Ltd.
    first initial last name at encircle dot co dot uk
    Robin Johnson, Aug 17, 2004
    #7
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Isambella  via DotNetMonster.com

    Transform XML string using XSLT file

    Isambella via DotNetMonster.com, Aug 1, 2005, in forum: ASP .Net
    Replies:
    4
    Views:
    9,735
    Isambella via DotNetMonster.com
    Aug 2, 2005
  2. pmatos
    Replies:
    6
    Views:
    23,769
  3. Replies:
    8
    Views:
    1,912
    Csaba
    Feb 18, 2006
  4. Javier
    Replies:
    2
    Views:
    558
    James Kanze
    Sep 4, 2007
  5. Rushikesh Joshi
    Replies:
    0
    Views:
    355
    Rushikesh Joshi
    Jul 10, 2004
Loading...

Share This Page