xsl-list
[Top] [All Lists]

Re: [xsl] "Tunneling" a parameter in document order

2012-04-12 15:42:23
How do you go about such problems in general? Is there a best practice?

Post a small complete sample input covering the various possibilities,
along with the required output for that input.


Before going further: I do *not* want anyone to create an XSLT that transforms 
the sample source to the desired result below! That would be time well wasted. 
I'm merely interested in ideas on how to tackle such a kind (or class?) of 
problem.

Trying to describe the problem at a high level, that would essentially be: 
Keeping a (virtual) global variable's value current while doing a depth-first 
traversal of a document, where the variable's value is not scoped by either the 
document's element hierarchy, nor the nesting of XSLT template calls.

Hoping to have gotten them right :-), here are source and desired result:

-- source.xml --
<?xml version="1.0" encoding="UTF-8"?>
<document>
  <listdefs>
    <list id="list1" restart="none">
      <leveldef level="1" type="decimal"/>
      <leveldef level="2" type="lower-alpha"/>
      <leveldef level="3" type="lower-roman"/>
    </list>
    <list id="list2" restart="level">
      <leveldef level="1" type="decimal"/>
      <leveldef level="2" type="decimal"/>
      <leveldef level="3" type="decimal"/>
    </list>
  </listdefs>
  <listrefs>
    <ref id="ref1" idref="list1"/>
    <ref id="ref2" idref="list1">
      <override level="1" startat="5"/>
    </ref>
    <ref id="ref3" idref="list2"/>
  </listrefs>
  <body>
    <a>
      <b><item idref="ref1" level="1"/></b>
      <item idref="ref1" level="1"/>
      <c>
        <d><item idref="ref1" level="2"/></d>
      </c>
    </a>
    <item idref="ref1" level="3"/>
    <item idref="ref1" level="2"/>
    <e><item idref="ref1" level="3"/></e>
    <item idref="ref2" level="1"/>
    <item idref="ref2" level="2"/>
    <f>
      <item idref="ref3" level="1"/>
    </f>
    <item idref="ref3" level="2"/>
    <item idref="ref2" level="1"/>
    <g>
      <h><item idref="ref3" level="1"/></h>
    </g>
    <i><item idref="ref3" level="2"/></i>
    <item idref="ref2" level="3"/>
  </body>
</document>
--snip--

-- desired-result.xml --
<document>
  <body>
    <a>
      <b><item num="1" idref="ref1" level="1"/></b>
      <item num="2" idref="ref1" level="1"/>
      <c>
        <d><item num="2.a" idref="ref1" level="2"/></d>
      </c>
    </a>
    <item num="2.a.i" idref="ref1" level="3"/>
    <item num="2.b" idref="ref1" level="2"/>
    <e><item num="2.b.ii" idref="ref1" level="3"/></e>
    <item num="5" idref="ref2" level="1"/>
    <item num="5.c" idref="ref2" level="2"/>
    <f>
      <item num="1" idref="ref3" level="1"/>
    </f>
    <item num="1.1" idref="ref3" level="2"/>
    <item num="6" idref="ref2" level="1"/>
    <g>
      <h><item num="2" idref="ref3" level="1"/></h>
    </g>
    <i><item num="2.1" idref="ref3" level="2"/></i>
    <item num="6.c.iii" idref="ref2" level="3"/>
  </body>
</document>
--snip--


Think of each /document/listdefs/list representing the declaration of a global 
3-element array of counters holding the current item number at that level while 
traversing the document in document order, and /document/listrefs/ref each 
being an indirection to the referenced list, resetting some level of the 
counter array when first referenced. Any occurrence of an <item> increments the 
counter by 1 for the specified list+level combination unless there's some reset 
override defined in the referenced list <ref>, which must only be applied the 
first time a <ref> is referred from the document's body. (I know this is all 
not too easy to understand, but that is basically how list numbering in OOXML 
is spec'd.)

list1 is set to number each level continuously (restart="none"), list2 is set 
to restart numbering for a level when a lower level (or higher level - depends 
on how you name them...) is incremented (restart="level").

Here's what the 3-element array would look like at each element start during 
document traversal, resulting in the depicted numbering string (@num attribute) 
to be added to each <item> (see desired-result.xml):

element    list1         list2
-------------------------------
document   0 0 0         0 0 0
body       | | |         | | |
a          | | |         | | |
b          | | |         | | |
item       1 | |         | | |
item       2 | |         | | |
c          | | |         | | |
d          | | |         | | |
item       | 1 |         | | |
item       | | 1         | | |
item       | 2 |         | | |
e          | | |         | | |
item       | | 2         | | |
item       5 | |         | | |   <- new startat value for level 1
item       | 3 |         | | |
f          | | |         | | |
item       | | |         1 | |
item       | | |         | 1 |
item       6 | |         | | |   <- @startat only applies once; subsequent refs 
just increment as usual
g          | | |         | | |
h          | | |         | | |
item       | | |         2 0 |   <- level 2 is reset to "0" because a lower 
level was incremented
i          | | |         | | |
item       | | |         | 1 |
item       | | 3         | | |
-------------------------------


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