<?xml version="1.0"?>
<?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_xslt-constructors.xml 51700 2026-05-27 13:48:01Z syd $ -->
<TEI xmlns="http://www.wwp.northeastern.edu/ns/yaps" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="5.0">
  <teiHeader>
    <fileDesc>
      <titleStmt>
        <title>XSLT Constructors</title>
        <author>Martin Holmes</author>
      </titleStmt>
      <editionStmt>
        <edition>DHSI 2017, Victoria</edition>
      </editionStmt>
      <publicationStmt>
        <distributor>Women Writers Project (via website)</distributor>
        <address>
          <addrLine>mholmes@uvic.ca</addrLine>
        </address>
        <date when="2017-06"/>
        <availability status="restricted">
          <p>Copyright 2017 Syd Bauman, David Birnbaum, and Martin Holmes</p>
          <p>This TEI-encoded XML file is available under the terms of the <ref
          target="http://creativecommons.org/licenses/by-sa/3.0/">Creative Commons
          Attribution-ShareAlike 3.0 (Unported)</ref> license.</p>
        </availability>
      </publicationStmt>
      <sourceDesc>
        <p>Born digital</p>
      </sourceDesc>
    </fileDesc>
    <revisionDesc>
      <change when="2017-06-08" who="mdh">Updates and fixes.</change> 
      <change when="2011-03-25" who="mdh">Started work on this file.</change> 
    </revisionDesc>
  </teiHeader>
  <text>
    <presentation>
      <section>
        <head>XSLT Constructors</head>
        <slide>
          <list type="incremental">
            <item>Normally, to create a result element in your output, you just type it literally:
            <egMarkup scheme="TEI">
              <div class="chapter">
                [...]
              </div>
            </egMarkup>
            </item>
            <item>However, there are some circumstances when you can't do that. For instance, the name of the element you want to create may change based on the XML input. For instance:</item>
            <item>If you're processing a TEI <gi>list</gi> element, you may need to produce either <gi>ul</gi> or <gi>ol</gi> in your output, depending on whether it's a bulleted or numbered list:</item>
            <item><code>&lt;list rend="bulleted"> → &lt;ul></code>
            and
              <code>&lt;list rend="numbered"> → &lt;ol></code>
            </item>
            <item>We can handle this with the XSLT <term>element constructor</term>.</item>
          </list>
        </slide>
      </section>
      
      <section>
        <head>The element constructor</head>
        <slide>
          <egMarkup scheme="XSLT" type="valid">
            <xsl:element name="h2">
              [...contents of the h2 element...]
            </xsl:element>
          </egMarkup>
        </slide>
      </section>
      
      <section>
        <head>An example element constructor</head>
        <slide>
          <egMarkup scheme="XSLT" type="valid">
            <xsl:element name="{if (@rend='numbered') then 'ol' else 'ul'}">
              [...]
            </xsl:element>
          </egMarkup>
          <list type="incremental">
            <item>The XPath logic is contained in {curly braces}.</item>
            <item>Be careful with nested quotes!</item>
          </list>
        </slide>
      </section>
      
      <section>
        <head>The attribute constructor</head>
        <slide>
          <p>Just as you can create an element with a constructor, you can also create an attribute:
          <egMarkup scheme="XSLT" type="valid">
            <xsl:attribute name="class">
              [... value of the class attribute ...]
            </xsl:attribute>
          </egMarkup>
          </p>
          <p>You might do this if you need to generate the attribute
          value dynamically based on the content.</p>
          <p>Like <gi>xsl:variable</gi>, the value can be given as
          the value of a <att>select</att> attribute, or as the
          content.</p>
        </slide>
      </section>
      
      <section>
        <head>An example attribute constructor</head>
        <slide>
          <p>
            <egMarkup scheme="XSLT" type="valid">
              <xsl:template match="div | p | ab">
                <div>
                  <xsl:attribute name="class" select="local-name()"/>
                  <xsl:apply-templates/>
                </div>
              </xsl:template>
            </egMarkup>
            </p>
        </slide>
      </section>
      
      <section>
        <head>XSL constructors: Task 1</head>
        <slide>
         <p>Write a constructor for an element called <gi>div</gi> with an attribute called "class", whose value is "chapter".</p>
        </slide>
      </section>
      
      <section>
        <head>XSL constructors: Task 1 answer</head>
        <slide>
          <p>A constructor for an element <gi>div</gi> with a
          <att>class</att> attribute whose value is
          <val>chapter</val>:</p>
          <egMarkup scheme="XSLT" type="valid">
            <xsl:element name="div">
              <xsl:attribute name="class">chapter</xsl:attribute>
            </xsl:element>
          </egMarkup>
        </slide>
      </section>
      
      <section>
        <head>XSL constructors: Task 1 discussion</head>
        <slide>
          <p>A constructor for an element <gi>div</gi> with a
          <att>class</att> attribute whose value is
          <val>chapter</val>:</p>
          <egMarkup scheme="XSLT" type="valid">
            <xsl:element name="div">

              [What can go in this location?]
              
              <xsl:attribute name="class">chapter</xsl:attribute>

              [What can go in this location?]
    
            </xsl:element>
          </egMarkup>
        </slide>
      </section>
      
      <section>
        <head>XSL constructors: Task 1 discussion</head>
        <slide>
          <p>A constructor for an element <gi>div</gi> with a
          <att>class</att> attribute whose value is
          <val>chapter</val>:</p>
          <egMarkup scheme="XSLT" type="valid">
            <xsl:element name="div">

              [Only attribute constructors can go here.]
    
              <xsl:attribute name="class">chapter</xsl:attribute>

              [Lots of things can go here, including 
              &lt;xsl:apply-templates>, other attribute 
              constructors, and other element 
              constructors.]
    
            </xsl:element>
          </egMarkup>
        </slide>
      </section>

      <!--  -->
      <section>
        <head>Copy constructors: <gi>xsl:copy</gi> and <gi>xsl:copy-of</gi></head>
        <slide>
          <list>
            <item>Sometimes, you simply want to copy some of the XML in your tree to the output document.</item>
            <item>This is often the case when you're using XSLT to make small modifications to your XML files.</item>
            <item>You can use <gi>xsl:copy</gi> and <gi>xsl:copy-of</gi> to do this.</item>
            <item>Although they look similar, they have completely different effects.</item>
          </list>
        </slide>
      </section>
      
      <section>
        <head><gi>xsl:copy-of</gi></head>
        <slide>
          <list>
            <item><tag type="empty">xsl:copy-of </tag> is the simpler of the two copy constructors.</item>
            <item>It makes a complete copy of the node, including its attributes and descendants, in the output tree.</item>
            <item>For instance, if your input is this:
              <egMarkup scheme="XSLT" type="valid">
                <p xml:id='para_1'>
                  This is my first paragraph.
                </p>
              </egMarkup>
              and your template is this:
              <egMarkup scheme="XSLT" type="valid">
                <xsl:template match="p[@xml:id eq 'para_1']">
                  <xsl:copy-of select="." />
                </xsl:template>
              </egMarkup>
              then your output will be this:
              <egMarkup scheme="XSLT" type="valid">
                <p xml:id="para_1">
                  This is my first paragraph.
                </p>
              </egMarkup>
            </item>
          </list>
        </slide>
      </section>
      
      <section>
        <head><gi>xsl:copy</gi></head>
        <slide>
          <list>
            <item><gi>xsl:copy</gi> copies <emph>only the node itself,
            and not its descendants or attributes</emph> to the output
            tree.</item>
            <item>For instance, if your input is this:
            <egMarkup scheme="XSLT" type="valid">
              <p xml:id="para_2">
                This is my second paragraph.
              </p>
            </egMarkup>
            and your template is this:
            <egMarkup scheme="XSLT" type="valid">
              <xsl:template match="p[@xml:id eq 'para_2']">
                <xsl:copy />
              </xsl:template>
            </egMarkup>
            then your output will be this:
            <egMarkup scheme="XSLT" type="valid">
              <p></p>
            </egMarkup>
            </item>
            <item>Only the node (<gi>p</gi>) is copied. Its
            <att>xml:id</att> attribute and text content are
            ignored.</item>
            <item>However, <gi>xsl:copy</gi> has <emph>content</emph>
            that is also processed and put into the output tree.</item>
            <item>For instance, if your input is the same and your
            template is this:
            <egMarkup scheme="XSLT" type="valid">
              <xsl:template match="p[@xml:id eq 'para_2']">
                <xsl:copy>
                  <xsl:attribute name="oldID" select="@xml:id"/>
                  <xsl:text>Hi Martin! I just messed up your paragraph. :-)</xsl:text>
                </xsl:copy>
              </xsl:template>
            </egMarkup>
            then your output will be this:
            <egMarkup scheme="XSLT" type="valid">
              <p oldID="para_2">Hi Martin! I just messed up your paragraph. :-)</p>
            </egMarkup>
            </item>
          </list>
        </slide>
      </section>
      
      <section>
        <head>Why copy constructors are useful: the <soCalled>identity transform</soCalled></head>
        <slide>
          <list>
            <item>You're probably wondering why copy constructors
            would be useful. After all, usually we're converting our
            XML into something else such as XHTML, so we can't just
            copy TEI nodes to the output document.</item>
            <item>However, we also use XSLT to edit, amend or improve
            existing TEI documents, transforming TEI into TEI, with
            minor changes.</item>
            <item>This is done through the so-called identity
            transform(ation). One version of it looks like this:
            <egMarkup scheme="XSLT" type="valid">
              <xsl:template match="node()|@*">
                <xsl:copy>
                  <xsl:apply-templates select="node()|@*"/>
                </xsl:copy>
              </xsl:template> 
            </egMarkup>
            Can you figure out what this is doing?
            </item>
          </list>
        </slide>
      </section>
      
      <section>
        <head>An example use of the identity transform</head>
        <slide>
          <list>
            <item>Imagine you have an old TEI file which has a lot of
            <gi>div0</gi> and <gi>div1</gi> elements in it:
            <egMarkup scheme="TEI" type="valid">
              <!-- ... -->
              <text>
                <body>
                  <div0>
                    <head>Title...</head>
                    <div1><p>Some stuff...</p>[...]</div1>
                    <div1><p>Some more stuff...</p>[...]</div1>
                  </div0>
                </body>
              </text>
              <!-- ... -->
            </egMarkup>
            </item>
            <item>You have, quite sensibly, decided that both
            <gi>div0</gi> and <gi>div1</gi> should be turned into plain
            <gi>div</gi> elements. We can do this with an identity
            transform.</item>
          </list>
        </slide>
      </section>
      
      <section>
        <head>Changing <gi>div0</gi> and <gi>div1</gi> to <gi>div</gi>
        with an identity transform</head>
        <slide>
         <p>This is the identity transform we need:
           <egMarkup scheme="XSLT" type="valid">
             <xsl:template match="node()|@*" priority="-1">
               <xsl:copy>
                 <xsl:apply-templates select="node()|@*"/>
               </xsl:copy>
             </xsl:template>
             
             <xsl:template match="div0 | div1">
               <div>
                 <xsl:apply-templates select="node()|@*"/>
               </div>
             </xsl:template>
           </egMarkup>
         </p>
        </slide>
      </section>
      <!--  -->
      
      <section>
        <head>XSL constructors: Task 2</head>
        <slide>
          <list type="incremental">
            <item><emph>When would I ever actually use this?</emph></item>
            <item>We've already come across a perfect use-case in the Hamlet transformation:
            
            <egMarkup scheme="XSLT" type="valid">
              <xsl:template match="head">
                <h2>
                  <xsl:apply-templates/>
                </h2>
              </xsl:template>
            </egMarkup>
            </item>
            <item>
              This matches <gi>head</gi> elements for both <emph>Act</emph> headings and <emph>Scene</emph> headings.
            </item>
            <item>What's the problem with it?</item>
          </list>
        </slide>
        <lectureNote>
          <list>
            <item>Open hamlet.xml and the example_01.xsl file.</item>
            <item>Set up a transformation scenario (elicit the steps).</item>
            <item>Do the transform, and show the problem.</item>
            <item>Discuss possible solutions. Arrive at the counting of ancestor divs.</item>
            <item>Elicit the initial fix, which would use h{count(ancestor::div)+1}.</item>
            <item>Once that's working, elicit the problem with the general case (h7 etc.).</item>
            <item>Elicit the solution to it (h{min(count(ancestor::div)+1), 6)}.</item>
          </list>
        </lectureNote>
      </section>
      
    </presentation>
  </text>
</TEI>
