[XSL-LIST Mailing List Archive Home] [By Thread] [By Date]

Re: [xsl] sequential navigation problem (long)


Subject: Re: [xsl] sequential navigation problem (long)
From: Jakob.Fix@xxxxxxxxxxxxxxxxx
Date: Thu, 5 Dec 2002 17:30:54 +0100


Jeni, David,

Thanks for your responses.  Thanks for pointing out the error in my logic.

I am currently using the catch-all expressions, which works ok,

  (ancestor::* | preceding::*)
    [self::PART or self::CHAP or self::SECT or self::ART or
     self::SYMBOLS or self::APPENDIX or self::SART][@ID][last()]
and
  (descendant::* | following::*)
    [self::PART or self::CHAP or self::SECT or self::ART or
     self::SYMBOLS or self::APPENDIX or self::SART][@ID][1]

However, as you indicated, this slows down the processing enormously:
normally, to fragment my 15 MB file into about 1800 fragments, it takes
about 8 minutes.  Currently, I am at 1040 fragments processed in 90 minutes
... another 800 to go ...
An occasion to optimize ...

I will also look into the function extension to modularize the stylesheet.

Again, thanks for your quick replies!

Jakob.







Jeni Tennison <jeni@xxxxxxxxxxxxxxxx>@... on 12/05/2002
01:26:52 PM

Veuillez répondre à xsl-list@xxxxxxxxxxxxxxxxxxxxxx

Envoyé par :   owner-xsl-list@xxxxxxxxxxxxxxxxxxxxxx


Pour :    Jakob Fix/HO/VERITAS@VERITAS
cc :  xsl-list@xxxxxxxxxxxxxxxxxxxxxx
Objet :   Re: [xsl] sequential navigation problem (long)

Ref. Message:

Hi Jakob,

> In addition to the parent/next/prev sibling navigation, I want to add
> sequential (in the book, page flicker sense) navigation as well, so that
it
> becomes possible to navigate the complete document only using "Next
> fragment" or "Previous fragment" buttons.  So, basically every fragment
> must know the ID of the sequentially preceding and following fragment.
>
> For this I have defined the following algorithms:
>
> for previous fragment:
> 1) test:      node's left sibling has a last child with a known GI and an
> ID
>               attr
> 2) else test: node has a left sibling with a known GI and an ID attr
> 3) else test: node has a parent with a known GI and an ID attr
>
> for next fragment:
> 1) test:      node has a first child with a known GI and an ID attr
> 2) else test: node has sibling with a known GI and an ID attr
> 3) else test: node's parent has a sibling with a known GI and an ID attr

These tests miss out situations where, for example, you want the next
fragment from a fragment whose parent doesn't have a following
sibling but whose grandparent (or other ancestor) does.

Rather than going through these separate tests, you might find it
better to use the ancestor/descendant and preceding/following axes.
For the previous fragment, you could use:

  (ancestor::* | preceding::*)
    [self::PART or self::CHAP or self::SECT or self::ART or
     self::SYMBOLS or self::APPENDIX or self::SART][@ID][last()]

and for the next fragment, you could similarly use:

  (descendant::* | following::*)
    [self::PART or self::CHAP or self::SECT or self::ART or
     self::SYMBOLS or self::APPENDIX or self::SART][@ID][1]

Using preceding and following will probably have an impact on the
speed of the transformation, but you said you don't care too much
about that -- try it and see.

> where a "known GI" is one in this list (this is to avoid fragmenting
> items such as notes and subsections which won't have their own
> fragment, but have an ID nevertheless): "PART, CHAP, SECT, ART,
> SYMBOLS, APPENDIX, SART"
>
> I have defined two named templates "tpl.next.fragment" and
> "tpl.prev.fragment" which are called from the template responsible for
> fragmenting, and are supposed to "return" the ID.  Thus, the current node
> is available in these templates.  Please note, these templates are not
yet
> tested.
>
> My problem now is that I am not sure how to efficiently and
> concisely write the XPath test expression of what is defined in the
> algorithms. The following shows my approach, not tested.

Your approach won't work, unfortunately, because you're holding the
list of known GIs in a *string* and then trying to evaluate that
string as part of an XPath expression. Actually, even if that did
work, the expression that it would create wouldn't be a legal one...

The easiest way to make your list of known.gis extensible with XSLT
1.0 is to store it in an entity:

<!DOCTYPE xsl:stylesheet [
<!ENTITY known.gis
         'self::PART or self::CHAP or self::SECT or self::ART or
          self::SYMBOLS or self::APPENDIX or self::SART'>
]>
<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
...
<xsl:template name="tpl.next.fragment">
  <xsl:choose>
    <!-- does this node have  a FIRST CHILD
         with an ID value and
one of the GIs above? -->

    <xsl:when test="child::*[&known.gis;][@ID][1]">

    </xsl:when>

    <!-- does this node have a FOLLOWING SIBLING
         with an ID value
and one of the GIs above? -->
    <xsl:when test="following-sibling::*[&known.gis;][@ID][1]">

    </xsl:when>

    <!-- does this node's PARENT DOES HAVE A NEXT SIBLING
         with an
ID value and one of the GIs above? -->
    <xsl:when test="../following-sibling::*[&known.gis;][@ID]">

    </xsl:when>

    <!-- not interested -->
    <xsl:otherwise/>
  </xsl:choose>
</xsl:template>
...
</xsl:stylesheet>

If you're using a processor that supports func:function from EXSLT
(e.g. Saxon or Xalan) and you're happy to use it, then I'd recommend
writing a function that tests whether a given node is one of your
known GIs or not, and then calling that function, as follows:

<func:function name="my:is-known-GI">
  <xsl:param name="n" />
  <func:result
    select="$n/self::PART or $n/self::CHAP or $n/self::SECT or
            $n/self::ART or $n/self::SYMBOLS or $n/self::APPENDIX or
            $n/self::SART" />
</func:function>

<xsl:template name="tpl.next.fragment">
  <xsl:choose>
    <!-- does this node have  a FIRST CHILD
         with an ID value and
one of the GIs above? -->

    <xsl:when test="child::*[my:is-known-GI(.)][@ID][1]">

    </xsl:when>

    <!-- does this node have a FOLLOWING SIBLING
         with an ID value
and one of the GIs above? -->
    <xsl:when test="following-sibling::*[my:is-known-GI(.)][@ID][1]">

    </xsl:when>

    <!-- does this node's PARENT DOES HAVE A NEXT SIBLING
         with an
ID value and one of the GIs above? -->
    <xsl:when test="../following-sibling::*[my:is-known-GI(.)][@ID]">

    </xsl:when>

    <!-- not interested -->
    <xsl:otherwise/>
  </xsl:choose>
</xsl:template>

I hope that gives you some ideas.

Cheers,

Jeni

---
Jeni Tennison
http://www.jenitennison.com/


 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list







 XSL-List info and archive:  http://www.mulberrytech.com/xsl/xsl-list



Current Thread
Keywords