xsl-list
[Top] [All Lists]

Re: [xsl] Nodes get new IDs in function?

2010-04-09 04:17:17
Thanks all for pointing out the xsl:copy-of, now it works like a charm.

As for the grouping approach, I'm considering it, but I can't see why
it's so much better? Performance wise? But it's using recursion as
well?
I think after I introduced parent-heading() function, my solution
became quite elegant. It's also convenient to have this function in
other situations.

Another question is, what is the desired output. You start at level 1,
what if there are no h1 elements?
Also, in your solution <li class="level4"><p>Attribution</p></li> gets
nested in an additional <ul>, which I think is unnecessary. In my
version, it gets flattened to the same level as <li class="level3">.

I'm using the same approach not only for <ul> list in XHTML, but NCX
table of contents as well. In Adobe Digital Editions, all top-level
headings are collapsed by default (children not shown until clicked),
so having empty nesting elements is not really a good idea.

Martynas

On Fri, Apr 9, 2010 at 3:29 AM, Imsieke, Gerrit, le-tex
<gerrit(_dot_)imsieke(_at_)le-tex(_dot_)de> wrote:
As Ken Holman (and I, http://markmail.org/message/4kneb3v2y6d4jlur) recently
suggested: this problem is probably better solved by a grouping approach.

XSLT:
======8<----------------------------------
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
 xmlns:xs="http://www.w3.org/2001/XMLSchema";
 xmlns:my="URN:my"
 version="2.0"
 exclude-result-prefixes="my xs"
 >

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

 <xsl:template match="/">
   <xsl:apply-templates/>
 </xsl:template>

 <xsl:template match="body">
   <xsl:copy>
     <xsl:sequence select="my:hierarchize(*,1)" />
   </xsl:copy>
 </xsl:template>

 <xsl:function name="my:hierarchize" as="element(*)*">
   <xsl:param name="nodes" as="element(*)*" />
   <xsl:param name="outline-level" as="xs:double?" />
   <xsl:choose>
     <xsl:when test="empty($outline-level)">
<!-- no output for non-headings, as we are creating the ToC: -->
<!--         <xsl:sequence select="$nodes" /> -->
     </xsl:when>
     <xsl:otherwise>
       <ul>
         <xsl:for-each-group select="$nodes"
           group-starting-with="*[matches(name(), '^h\d$')]
                                 [my:hlevel(.) = $outline-level]">
           <xsl:choose>
             <xsl:when test="my:hlevel(current-group()[1])
                             = $outline-level">
               <li class="level{$outline-level}">
                 <p>
                   <xsl:copy-of select="current-group()[1]/node()" />
                 </p>
                 <xsl:variable
                   name="new-nodes"
                   select="current-group()[position() gt 1]"
                   as="node()*" />
                 <xsl:sequence select="my:hierarchize(
                                         $new-nodes,
                                         min(
                                           for $n in $new-nodes[
                                             matches(name(), '^h\d$')
                                           ]
                                             return my:hlevel($n)
                                         )
                                       )" />
               </li>
             </xsl:when>
             <xsl:otherwise>
               <xsl:sequence select="my:hierarchize(
                                       current-group(),
                                       min(
                                         for $n in current-group()[
                                           matches(name(), '^h\d$')
                                         ]
                                           return my:hlevel($n)
                                       )
                                     )" />
             </xsl:otherwise>
           </xsl:choose>
         </xsl:for-each-group>
       </ul>
     </xsl:otherwise>
   </xsl:choose>
 </xsl:function>

 <xsl:function name="my:hlevel" as="xs:double">
   <xsl:param name="elt" as="element(*)" />
   <xsl:value-of select="number(replace(name($elt), '^h(\d)$', '$1'))" />
 </xsl:function>

</xsl:stylesheet>
======8<----------------------------------


Input:
======8<----------------------------------
<?xml version="1.0" encoding="utf-8"?>
<body>
<h1 class="Heading_20_1 ">Free Culture - How Big Media Uses Technology
and the Law to Lock Down Culture and Control Creativity,Lawrence
Lessig</h1>
<h4 class="Heading_20_4 ">Attribution</h4>
<p>...</p>
<h3 class="Heading_20_3 ">Preface</h3>
<h4 class="Heading_20_4 ">[Preface]</h4>
<p>...</p>
<h3 class="Heading_20_3 ">INTRODUCTION</h3>
<p>...</p>
</body>
======8<----------------------------------


Output:
======8<----------------------------------
<?xml version="1.0" encoding="UTF-8"?>
<body>
  <ul>
     <li class="level1">
        <p>Free Culture - How Big Media Uses Technology
and the Law to Lock Down Culture and Control Creativity,Lawrence
Lessig</p>
        <ul>
           <ul>
              <li class="level4">
                 <p>Attribution</p>
              </li>
           </ul>
           <li class="level3">
              <p>Preface</p>
              <ul>
                 <li class="level4">
                    <p>[Preface]</p>
                 </li>
              </ul>
           </li>
           <li class="level3">
              <p>INTRODUCTION</p>
           </li>
        </ul>
     </li>
  </ul>
</body>
======8<----------------------------------


De rien.

Gerrit



On 09.04.2010 02:15, Martynas Jusevicius wrote:

Hey list,

still struggling with the level gap-infested ToC, but I think I
introduced a couple of functions, I'm now on the finish line:

<xsl:function name="o2e:heading-level" as="xs:integer">
    <xsl:param name="heading" as="element()"/>
    <xsl:value-of select="number(substring-after(local-name($heading),
'h'))"/>
</xsl:function>

<xsl:function name="o2e:parent-heading" as="element()*">
    <xsl:param name="heading" as="element()"/>
    <xsl:copy-of select="$heading/preceding-sibling::h:*[self::h:h1 or
self::h:h2 or self::h:h3 or self::h:h4 or self::h:h5 or
self::h:h6][o2e:heading-level(.)&lt;
o2e:heading-level($heading)][1]"/>
</xsl:function>

The problem is, it seems that nodes returned from the parent-heading()
function get different IDs than identical nodes in the source
document. Is this the specified behavior, i.e. functions construct new
nodes, which get new IDs?

For that reason this expression won't work:

following-sibling::h:*[self::h:h1 or self::h:h2 or self::h:h3 or
self::h:h4 or self::h:h5 or self::h:h6][o2e:parent-heading(.) is
current()]

Because the IDs won't match in the 'is' operator, even though I can
see the nodes are (look) identical. If I change the operator to '=' it
starts giving the expected results, but it is not good enough, as
there can be several heading elements with the same string value. Is
it possible to retain the original ID value somehow?

As for the source document, it could be any XHTML with any number and
order of headings, for example:

<h1 class="Heading_20_1 ">Free Culture - How Big Media Uses Technology
and the Law to Lock Down Culture and Control Creativity,Lawrence
Lessig</h1>
<h4 class="Heading_20_4 ">Attribution</h4>
<p>...</p>
<h3 class="Heading_20_3 ">Preface</h3>
<h4 class="Heading_20_4 ">[Preface]</h4>
<p>...</p>
<h3 class="Heading_20_3 ">INTRODUCTION</h3>
<p>...</p>

and so on

Martynas
odt2epub.com

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


--
Gerrit Imsieke
Geschäftsführer / Managing Director
le-tex publishing services GmbH
Weissenfelser Str. 84, 04229 Leipzig, Germany
Phone +49 341 355356 110, Fax +49 341 355356 510
gerrit(_dot_)imsieke(_at_)le-tex(_dot_)de, http://www.le-tex.de

Registergericht / Commercial Register: Amtsgericht Leipzig
Registernummer / Registration Number: HRB 24930

Geschäftsführer: Gerrit Imsieke, Svea Jelonek,
Thomas Schmidt, Dr. Reinhard Vöckler

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



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

<Prev in Thread] Current Thread [Next in Thread>