xsl-list
[Top] [All Lists]

Re: sequential navigation problem (long)

2002-12-05 09:30:54


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][(_at_)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][(_at_)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(_at_)jenitennison(_dot_)com>@lists.mulberrytech.com on 
12/05/2002
01:26:52 PM

Veuillez répondre à xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com

Envoyé par :   owner-xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com


Pour :    Jakob Fix/HO/VERITAS(_at_)VERITAS
cc :  xsl-list(_at_)lists(_dot_)mulberrytech(_dot_)com
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][(_at_)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][(_at_)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;][(_at_)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;][(_at_)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;][(_at_)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(.)][(_at_)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(.)][(_at_)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(.)][(_at_)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