tags:

views:

67

answers:

3

Need some help with this problem in implementing with XSLT, I had already implemented a Java code of this one using SAX parser, but it is a troublesome due to customer request to change something.

So we are doing it now using an XSLT with doesn't need to be compiled and deployed to a web server. I have XML like below.

Example 1:

<ShotRows>
  <ShotRow row="3" col="3" bit="1" position="1"/>
  <ShotRow row="3" col="4" bit="1" position="2"/>
  <ShotRow row="3" col="5" bit="1" position="3"/>
  <ShotRow row="3" col="6" bit="1" position="4"/>
  <ShotRow row="3" col="7" bit="1" position="5"/>
  <ShotRow row="3" col="8" bit="1" position="6"/>
  <ShotRow row="3" col="9" bit="1" position="7"/>
  <ShotRow row="3" col="10" bit="1" position="8"/>
  <ShotRow row="3" col="11" bit="1" position="9"/>
</ShotRows>

Output 1:

<ShotRows>
  <ShotRow row="3" colStart="3" colEnd="11" />
</ShotRows>
<!-- because the col is continuous from 3 to 11 -->

Example 2:

<ShotRows>
  <ShotRow row="3" col="3" bit="1" position="1"/>
  <ShotRow row="3" col="4" bit="1" position="2"/>
  <ShotRow row="3" col="6" bit="1" position="3"/>
  <ShotRow row="3" col="7" bit="1" position="4"/>
  <ShotRow row="3" col="8" bit="1" position="5"/>
  <ShotRow row="3" col="10" bit="1" position="6"/>
  <ShotRow row="3" col="11" bit="1" position="7"/>
  <ShotRow row="3" col="15" bit="1" position="8"/>
  <ShotRow row="3" col="19" bit="1" position="9"/>
</ShotRows>

Output 2:

<ShotRows>
  <ShotRow row="3" colStart="3" colEnd="4" />
  <ShotRow row="3" colStart="6" colEnd="8" />
  <ShotRow row="3" colStart="10" colEnd="11" />
  <ShotRow row="3" colStart="15" colEnd="15" />
  <ShotRow row="3" colStart="19" colEnd="19" />
</ShotRows>

The basic idea is to group any continuous col into one element, like the col 3 to 4, col 6 to 8, col 10 to 11, col 15 is only one, and col 19 is only one. Thanks in advance.

A: 

This feels a little messy, as iterative processing often does in XSLT.

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"&gt;

    <xsl:output method="xml" indent="yes" />

    <xsl:template match="ShotRows">
        <xsl:copy>
            <xsl:apply-templates select="ShotRow[1]" />
        </xsl:copy>
    </xsl:template>

    <xsl:template match="ShotRow">
        <xsl:call-template name="ShotRow">
            <xsl:with-param name="start" select="@col" />
            <xsl:with-param name="shotrow" select="." />
        </xsl:call-template>
    </xsl:template>

    <xsl:template name="ShotRow">
        <xsl:param name="start" />
        <xsl:param name="shotrow" />

        <xsl:choose>
            <xsl:when test="$shotrow/@row = $shotrow/following-sibling::ShotRow[1]/@row and 1 + number($shotrow/@col) = number($shotrow/following-sibling::ShotRow[1]/@col)">
                <xsl:call-template name="ShotRow">
                    <xsl:with-param name="start" select="$start" />
                    <xsl:with-param name="shotrow" select="$shotrow/following-sibling::ShotRow[1]" />
                </xsl:call-template>

            </xsl:when>
            <xsl:otherwise>
                <ShotRow row="{$shotrow/@row}" colStart="{$start}" colEnd="{$shotrow/@col}" />
                <xsl:apply-templates select="$shotrow/following-sibling::ShotRow[1]" />

            </xsl:otherwise>
        </xsl:choose>

    </xsl:template>

</xsl:stylesheet>
Lachlan Roche
@Gerald: Have a look at the alternative I posted.
Tomalak
+1  A: 
Tomalak
Guys thanks for the answers, we appreciate it. Here's one concern the xml that I post is just a small subset of the actual xml. We are expecting about 1000 rows and 1000 columns. In terms of performance what should we take into consideration?
Gerald
@Gerald: Just test it. My guess is that my solution is faster and more stable than @Lachlan's. This solution does not use recursion, so you will never hit a "stack overflow" error (no pun intended). I can give a little thought to improving this solution with XSL keys.
Tomalak
@Gerald: I would appreciate if you posted some real-life numbers with the performance of each solution.
Tomalak
@Tomalak: I will do that currently i'm using Oxygen for developing our xslt.
Gerald
+1 for elegance
Lachlan Roche
+2  A: 

With Java you could use Saxon 9 and XSLT 2.0 as follows:

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

  <xsl:output indent="yes"/>

  <xsl:template match="ShotRows">
    <xsl:copy>
      <xsl:for-each-group select="ShotRow" group-adjacent="number(@col) - position()">
        <ShotRow row="{@row}" colStart="{@col}" colEnd="{@col + count(current-group()) - 1}"/>
      </xsl:for-each-group>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>
Martin Honnen
Simple and elegant, +1. :)
Tomalak
XSLT 2.0 is also available in .NET via Saxon.NET.
Lachlan Roche
We are using Saxon 9.1 in java
Gerald
If you are already using Saxon 9 with Java then you can certainly use an XSLT 2.0 solution.
Martin Honnen
@Martin: Oh damn it, and I've put so much effort into an XSLT 1.0 solution. ;)
Tomalak