XSLT Transform Vector to Array

G

Gary Huntress

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.
 
?

=?ISO-8859-1?Q?R=E9mi_Peyronnet?=

The "otherwise said:
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
 
M

Marrow

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
 
D

David Carlisle

<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>
 
R

Robin Johnson

Rémi Peyronnet said:
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.
 
?

=?ISO-8859-1?Q?R=E9mi_Peyronnet?=

Robin Johnson a écrit :
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

Robin Johnson

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.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top