This is the mail archive of the xsl-list@mulberrytech.com mailing list .


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: generating a repeatable unique id


Hi Sebastian,

>> Of course you should use different separators to make it a valid ID
>> so that it can be an HTML anchor, e.g.:
>>
>>   chapter1.section2.div3
>
> thats fine, I can see that nicely. I still have the problem, though,
> of turning that back into the value for a <xsl:apply-templates>
> select attribute, don't I, when I reenter the document?

Oh, it depends on how you're doing the linking. I was imagining that
you were creating something an index.html document with the links in,
containing things like:

  <p><a href="doc.html#chapter1.section2.div3">...</a></p>

And then had a doc.html document with the anchors for the links,
containing things like:

  <h3 id="chapter1.section2.div3">...</h3>

In other words, that you were creating the links by having the IDs
that you refer to in index.html be the same as the IDs that you use
within doc.html. You can make sure that they're the same by having a
module containing a moded template like:

<xsl:template match="*" mode="id">
  <xsl:for-each select="ancestor-or-self::*">...</xsl:for-each>
</xsl:template>

Import that module into the stylesheet for index.html and for
doc.html. In the stylesheet generating index.html have:

  <a>
    <xsl:attribute name="href">
      <xsl:text>doc.html#</xsl:text>
      <xsl:apply-templates select="." mode="id" />
    </xsl:attribute>
    ...
  </a>

In the stylesheet generating doc.html, have:

  <h3>
    <xsl:attribute name="id">
      <xsl:apply-templates select="." mode="id" />
    </xsl:attribute>
    ...
  </h3>

i.e. the same ID value is used in both because you use the same
template to generate them both.

But perhaps you were meaning that you wanted to only display the part
of the document that you were linking to? Of course in the future all
you'd need to do is generate:

<p><a href="doc.xml#xpointer(/chapter[1]/section[2]/div[3])">...</a></p>

But for now I guess you would generate a link that looked something
like:

<p><a href="doc.xml?xpath=/chapter[1]/section[2]/div[3]">...</a></p>

With some magic on the server end, you'd get an $xpath parameter in
your stylesheet.

You could step through the $xpath parameter to locate and apply
templates to the relevant part of the document, something like:

<xsl:template match="*" mode="xpath">
  <xsl:param name="xpath" />
  <xsl:choose>
    <!-- if there is a path -->
    <xsl:when test="$xpath">
      <!-- step is the part before the '/' (if there is one) -->
      <xsl:variable name="step">
        <xsl:choose>
          <xsl:when test="contains($xpath, '/')">
            <xsl:value-of select="substring-before($xpath, '/')" />
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="$xpath" />
          </xsl:otherwise>
        </xsl:choose>
      </xsl:variable>
      <!-- the child's name is the part before the '[' -->
      <xsl:variable name="childName"
                    select="substring-before($step, '[')" />
      <!-- and its index is the part between the []s -->
      <xsl:variable name="childIndex"
                    select="substring-before(
                              substring-after($step, '['), ']'))" />
      <!-- so apply templates to that child, passing in the $xpath
           left after the first step -->
      <xsl:apply-templates select="*[name() = $childName]
                                    [number($childIndex)]">
         <xsl:with-param name="xpath"
                         select="substring-after($xpath, '/')" />
      </xsl:apply-templates>
    </xsl:when>
    <!-- if there's no path left, then this is the element we want -->
    <xsl:otherwise>
      <!-- apply templates to it (or do something else) -->
      <xsl:apply-templates select="." />
    </xsl:otherwise>
  </xsl:choose>
</xsl:template>

You could kick it off with something like:

<xsl:template match="/">
  <xsl:apply-templates select="*" mode="xpath">
    <xsl:with-param name="xpath"
                    select="substring-after($xpath, '/')" />
  </xsl:apply-templates>
</xsl:template>

Your other option, the one that you were referring to, would be to
generate an XSLT stylesheet that used the XPath. The generator
stylesheet would contain something like:

<xsl:template match="/">
  <oxsl:template match="/">
    <oxsl:apply-templates select="{$xpath}" />
  </oxsl:template>
</xsl:template>

And you might want to pass the URL for the document in there as well,
to make things easier.

Cheers,

Jeni

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


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]