xsl-list
[Top] [All Lists]

Re: [xsl] Count previous-siblings w/same attribute value up to attribute value - 1 possible?

2011-12-12 20:01:42
At 2011-12-12 16:54 -0800, Lou Argyres wrote:
I hope this makes sense.

I have "flat" outline list structures, the numbering of which is
controlled by a "level" attribute, that I renumber based on name-spaced
change tracking tags where I need to output Accept-All and Reject-All
versions to be redlined in other application formats after
transformations. (They're good for unsophisticated users who have
trouble editing embedded lists.)

The best I've come up with is a recursive template to count previous
same level items and stop at a lower level (skipping adds/deletes as
needed).

Is there an XPATH-2 select that can count preceding-siblings up to the
first preceding @level = $lvl-1?

 <xsl:variable name="lvl" select="@level"/>
 ...
 ... select="(count(preceding-sibling::section[@level=$lvl]) + 1) -
count(preceding-sibling::section[@level=$lvl][not(following-sibling::sec
tion[preceding-sibling::section[@level=number($lvl)-1][1]])])"

picks up all previous same-level items.

<flatOutline>
 <item numDisplay="I." level="1" />
 <item numDisplay="II." level="1" />
  <item numDisplay="A." level="2" />
  <item numDisplay="B." level="2" />
  <item numDisplay="C." level="2" />
 <item numDisplay="III." level="1"/>
  <item numDisplay="A." level="2"/>
   <item numDisplay="1." level="3" />
   <item numDisplay="2." level="3" />
   <item numDisplay="3." level="3" />
   <item numDisplay="4." level="3" />
  <item numDisplay="B." level="2"/>
   <item numDisplay="1." level="3" />
   <item numDisplay="2." level="3" />
   <item numDisplay="3." level="3" />
  <item numDisplay="C." level="2"/>
</flatOutline>

Lou Argyres
Continuing Education of the Bar - California
Oakland, CA
Lou(_dot_)Argyres(_at_)ceb(_dot_)ucla(_dot_)edu

If you are simply counting, then the following works in both XSLT 1 and XSLT 2, as it takes the difference between the count to the beginning and the count to the beginning from the last disqualifying entry (note the two-step location path in the second count() function call):

t:\ftemp>xslt lou.xml lou1.xsl
<?xml version="1.0" encoding="utf-8"?>
<item numDisplay="I." level="1">1</item>
<item numDisplay="II." level="1">2</item>
<item numDisplay="A." level="2">1</item>
<item numDisplay="B." level="2">2</item>
<item numDisplay="C." level="2">3</item>
<item numDisplay="III." level="1">3</item>
<item numDisplay="A." level="2">1</item>
<item numDisplay="1." level="3">1</item>
<item numDisplay="2." level="3">2</item>
<item numDisplay="3." level="3">3</item>
<item numDisplay="4." level="3">4</item>
<item numDisplay="B." level="2">2</item>
<item numDisplay="1." level="3">1</item>
<item numDisplay="2." level="3">2</item>
<item numDisplay="3." level="3">3</item>
<item numDisplay="C." level="2">3</item>
t:\ftemp>type lou1.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
  version="1.0">
<xsl:output indent="yes"/>

<xsl:template match="/">
  <xsl:for-each select="/*/item">
    <xsl:copy>
      <xsl:copy-of select="@*"/>
      <xsl:value-of
        select="count(preceding-sibling::item[@level=current()/@level]) -
                count(preceding-sibling::item[@level&lt;current()/@level][1]/
                      preceding-sibling::item[@level=current()/@level]) + 1"/>
    </xsl:copy>
  </xsl:for-each>
</xsl:template>

</xsl:stylesheet>
t:\ftemp>


If you actually want to do something with the groups at each level, then it is best to use XSLT 2:

t:\ftemp>xslt2 lou.xml lou2.xsl
<?xml version="1.0" encoding="UTF-8"?>
<section level="1">
   <item numDisplay="I." level="1"/>
</section>
<section level="1">
   <item numDisplay="II." level="1"/>
   <section level="2">
      <item numDisplay="A." level="2"/>
      <item numDisplay="B." level="2"/>
      <item numDisplay="C." level="2"/>
   </section>
</section>
<section level="1">
   <item numDisplay="III." level="1"/>
   <section level="2">
      <item numDisplay="A." level="2"/>
      <section level="3">
         <item numDisplay="1." level="3"/>
         <item numDisplay="2." level="3"/>
         <item numDisplay="3." level="3"/>
         <item numDisplay="4." level="3"/>
      </section>
   </section>
   <section level="2">
      <item numDisplay="B." level="2"/>
      <section level="3">
         <item numDisplay="1." level="3"/>
         <item numDisplay="2." level="3"/>
         <item numDisplay="3." level="3"/>
      </section>
   </section>
   <section level="2">
      <item numDisplay="C." level="2"/>
   </section>
</section>
t:\ftemp>type lou2.xsl
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
  version="2.0">
<xsl:output indent="yes"/>

<xsl:template match="/" name="do-next-group">
  <xsl:param name="group" select="/*/item"/>
  <xsl:param name="level" select="1"/>
  <xsl:choose>
    <xsl:when test="$group[@level!=$level]">
      <!--then more splitting of the group is necessary-->
      <xsl:for-each-group select="$group"
                          group-starting-with="item[@level=$level]">
        <section level="{$level}">
          <!--put the current level into this section-->
          <xsl:copy-of select="current-group()[@level=$level]"/>
          <!--only nest when this group has members from deeper levels-->
          <xsl:if test="current-group()[@level!=$level]">
            <xsl:call-template name="do-next-group">
              <xsl:with-param name="group"
                              select="current-group()[@level!=$level]"/>
              <xsl:with-param name="level" select="$level+1"/>
            </xsl:call-template>
          </xsl:if>
        </section>
      </xsl:for-each-group>
    </xsl:when>
    <xsl:otherwise>
      <!--no more splitting of the group is necessary-->
      <section level="{$level}">
        <xsl:copy-of select="$group"/>
      </section>
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

</xsl:stylesheet>
t:\ftemp>


I hope this helps.

. . . . . . . . . . Ken

--
Contact us for world-wide XML consulting and instructor-led training
Free 5-hour video lecture: XSLT/XPath 1.0 & 2.0 http://ude.my/t37DVX
Crane Softwrights Ltd.            http://www.CraneSoftwrights.com/s/
G. Ken Holman                   mailto:gkholman(_at_)CraneSoftwrights(_dot_)com
Google+ profile: https://plus.google.com/116832879756988317389/about
Legal business disclaimers:    http://www.CraneSoftwrights.com/legal


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