<?xml version="1.0" encoding="UTF-8"?>
<?xml-model href="../../../_utils/schema/yaps.rnc" type="application/relax-ng-compact-syntax"?>
<?xml-model href="../../../_utils/schema/yaps.isosch" type="application/xml" schematypens="http://purl.oclc.org/dsdl/schematron"?>
<?xml-stylesheet type="text/xsl" href="yaps2slidy1.xslt"?>
<!-- $Id: mdh_keys.xml 51709 2026-05-28 23:29:13Z syd $ -->
<TEI xmlns="http://www.wwp.northeastern.edu/ns/yaps" version="5.0"
     xmlns:y="http://www.wwp.northeastern.edu/ns/yaps"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
  <teiHeader>
    <fileDesc>
      <titleStmt>
        <title>XSLT Keys</title>
        <author>Martin Holmes</author>
      </titleStmt>
      <editionStmt>
        <edition/>
      </editionStmt>
      <publicationStmt>
        <distributor>Women Writers Project (via website)</distributor>
        <address>
          <addrLine>url:mailto:wwp@northeastern.edu</addrLine>
        </address>
        <date when="2011-03-29"/>
        </publicationStmt>
      <sourceDesc>
          <p>Born digital</p>
      </sourceDesc>
    </fileDesc>
    <revisionDesc>
     <change when="2011-03-29" who="mdh">Started work on this file.</change> 
    </revisionDesc>
  </teiHeader>
  <text>
    <presentation>
      <section>
        <head>XSLT Keys</head>
        <slide>
          <list>
            <item>As your XSLT transformations get more complicated, they'll also start to take a little longer to run.</item>
            <item>This can become a problem when (for instance) you're generating content on-the-fly for a website.</item>
            <item>Time is often wasted because the same template performs the same expensive operation many times.</item>
            <item><gi>xsl:key</gi> can help make your templates more efficient.</item>
          </list>
        </slide>
      </section>
      
      <section>
        <head>The nature of the problem</head>
        <slide>
          <p>Imagine that we want to transform our Hamlet file
          (again). This time, we want to add a copy of the speaker's
          <gi>roleDesc</gi> immediately following the character's name
          at the beginning of every speech. This template would do it:
            <egMarkup scheme="XSLT" type="valid">
              <xsl:template match="speaker">
                <xsl:apply-templates select="@* | node()"/>
                <xsl:text y:interest="start content end"> (</xsl:text>
                <xsl:variable y:interest="start content end" name="thisSpeaker" select="parent::sp/@who"/>
                <xsl:value-of y:interest="start content end" select="//castItem[role/@xml:id = $thisSpeaker]/roleDesc"/>
                <xsl:text y:interest="start content end">)</xsl:text>
              </xsl:template>
            </egMarkup>
          <list>
            <item>Open parenthesis.</item>
            <item>Get the <att>xml:id</att> of the role from the <att>who</att> attribute of the parent <gi>sp</gi> element and stash it in a variable.</item>
            <item>Retrieve the matching <gi>castItem</gi> element in the cast list, and output its <gi>roleDesc</gi> content.</item>
            <item>Close parenthesis.</item>
          </list>
          </p>
        </slide>
      </section>
      
      <section>
        <head>Inefficiencies in the previous template</head>
        <slide>
          <p>
          Look again at this line:
          <egMarkup scheme="XSLT" type="valid">
            <xsl:value-of select="//castItem[role/@xml:id = $thisSpeaker]/roleDesc"/>
          </egMarkup>
          Every time this is executed, the XSLT processor has to look
          through all the <gi>castItem</gi> elements to find the
          matching one. This happens for every <gi>speaker</gi>
          element matched by the template.</p>
        </slide>
      </section>
      
      <section>
        <head><gi>xsl:key</gi> to the rescue</head>
        <slide>
          <list>
            <item>To avoid repeating the same lookup operation every time a template is invoked, we can use <gi>xsl:key</gi>.</item>
            <item><gi>xsl:key</gi> builds an index to a specific node.</item>
            <item>It builds the index once, and keeps it available for quick lookups during the rest of the transformation.</item>
            <item>The index works like an <emph>associative array</emph>.</item>
          </list>
        </slide>
      </section>
      
      <section>
        <head>Building an <gi>xsl:key</gi> index</head>
        <slide>
          <p>An <gi>xsl:key</gi> index is built using a single command. The command appears at the top level of your stylesheet, usually near the beginning of the file. It looks like this:
          <egMarkup scheme="XSLT" type="valid">
            <xsl:key name="roles" match="castItem[@type='role']" use="role/@xml:id"/>
          </egMarkup>
          </p>
          <list>
            <item>This builds a key index named <val>roles</val>.</item>
            <item>The <att>match</att> attribute specifies the nodes which will be indexed. In this case, it's indexing all <gi>castItem</gi> elements whose <att>type</att> attribute is <val>role</val>.</item>
            <item>The last attribute, <att>use</att>, specifies what we use to look up a particular item in the index.</item>
            <item>Here, we use the <att>xml:id</att> attribute on the <gi>role</gi> child of the target <gi>castItem</gi> node.</item>
          </list>
        </slide>
      </section>
      
      <section>
        <head>Using an <gi>xsl:key</gi> index</head>
        <slide>
          <p>Here's our index:
            <egMarkup scheme="XSLT" type="valid">
              <xsl:key name="roles" match="castItem[@type='role']" use="role/@xml:id"/>
            </egMarkup>
          </p>
          <p>
            Here's how we can use it to accomplish the same job as before:
            <egMarkup scheme="XSLT" type="valid">
              <xsl:template match="speaker">
                <xsl:apply-templates select="@* | node()"/>
                <xsl:text y:interest="start content end"> (</xsl:text>
                <xsl:value-of y:interest="start content end" select="key('roles', parent::sp/@who)/roleDesc"/>
                <xsl:text y:interest="start content end">)</xsl:text>
              </xsl:template>
            </egMarkup>
          </p>
        </slide>
      </section>
      
      <section>
        <head><gi>xsl:key</gi> Task (and review of identity transforms and <gi>xsl:copy</gi>)</head>
        <slide>
          <p>Using the <emph>eventDemo.xml</emph> file: </p>
          <list>
            <item>Create an identity transform.</item>
            <item>Add an <gi>xsl:key</gi> like this:
            <list>
              <item><att>name</att> <val>demoPlaces</val></item>
              <item><att>match</att> <val>place/placeName/orgName</val></item>
              <item><att>use</att> <val>ancestor::place/@xml:id</val></item>
            </list></item>
            <item>Use the key to add the location of the meeting to the end of the <gi>label</gi> element, so that this:
              <egMarkup scheme="TEI" type="valid">
                <label>TEI MM 2004</label>
              </egMarkup>
              becomes this:
              <egMarkup scheme="TEI" type="valid">
                <label>TEI MM 2004 (Johns Hopkins University)</label>
              </egMarkup>
            </item>
          </list>
        </slide>
      </section>
      
      <section>
        <head><gi>xsl:key</gi> Task: creating the key</head>
        <slide>
          <p>The key constructor will look like this:
          <egMarkup scheme="XSLT" type="valid">
            <xsl:key name="meetingPlaces" match="place/placeName/orgName" use="ancestor::place/@xml:id"/>
          </egMarkup>
          </p>
        </slide>
      </section>
      
      <section>
        <head><gi>xsl:key</gi> Task: invoking the key in a template</head>
        <slide>
          <p>This is one way to use the key to accomplish the task:
            <egMarkup scheme="XSLT" type="valid">
              <xsl:template match="event/label">
                <xsl:copy>
                  <xsl:apply-templates select="@* | node()"/>
                  <xsl:text y:interest="start content end"> (</xsl:text>
                  <xsl:value-of y:interest="start content end" select="key('meetingPlaces', replace(parent::event/@where, '#', ''))"/>
                  <xsl:text y:interest="start content end">)</xsl:text>
                </xsl:copy>
              </xsl:template>
            </egMarkup>
          </p>
          <list>
            <item>What is the call to "replace()" doing?</item>
            <item>Are there other ways of doing that?</item>
          </list>
        </slide>
        <lectureNote><p>Among the other ways of handling the hash problem in the <att>where</att> attribute would be translate(), substring-after(), and prepending the hash to the <att>use</att> attribute with concat() when creating the key, so the <att>where</att> attribute can be used directly.</p></lectureNote>
        <tutorial><p>Among the other ways of handling the hash problem in the <att>where</att> attribute would be translate(), substring-after(), and prepending the hash to the <att>use</att> attribute with concat() when creating the key, so the <att>where</att> attribute can be used directly.</p></tutorial>
      </section>
      
    </presentation>
  </text>
</TEI>
