<?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: node-predicates_functions.xml 51709 2026-05-28 23:29:13Z syd $ -->
<TEI xmlns="http://www.wwp.northeastern.edu/ns/yaps" version="5.0">
  <teiHeader>
    <fileDesc>
      <titleStmt>
        <title>XPath node predicates and functions</title>
        <author xml:id="sstanley.fxj">Sarah Stanley</author>
        <editor role="suggestions" xml:id="ebb">Elisa Beshero-Bondar</editor>
      </titleStmt>
      <editionStmt>
        <edition>TEI Summer School, University of Graz, Fri, 13 Sep 19</edition>
      </editionStmt>
      <publicationStmt>
        <distributor>Women Writers Project (via website)</distributor>
        <address>
          <addrLine>url:mailto:wwp@northeastern.edu</addrLine>
        </address>
        <date when="2019-09-13"/>
        <availability status="restricted">
          <p>Copyright 2018 Sarah Stanley, Martin D. Holmes, and the Women Writers Project</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="2019-09-12" who="#sb">Updated for 2019 Graz Summer School — mostly minor tweaks</change>
      <change when="2018-08-31" who="#ebb">Added comments and suggestions, especially to show how to return a count of the number of times Hamlet speaks.</change>
      <change when="2018-08-27" who="#sstanley.fxj">Adapted slides from MDH and DJB Node Predicates and Ten Functions slide sets.</change> 
    </revisionDesc>
  </teiHeader>
  <text>
    <presentation>
      <section>
        <head>XPath Functions</head>
        <slide>
          <list type="incremental">
            <item>Functions in XPath work just like functions in other programming languages.</item>
            <item>A function is called by <emph>name</emph>, with following <emph>parentheses</emph>,
              containing <emph>parameters</emph>:<lb/><code>functionName( param1, param2 )</code></item>
            <item>Functions can wrap around the entire XPath expression or can be used within an expression to further refine results.</item>
            <item>Parameters are <q>things you want the function to work on</q>.</item>
          </list>
        </slide>
      </section>
          
      <section>
        <head>Some Essential Functions</head>
        <slide>
          <list type="incremental">
            <item><code>name()</code>
              <list>
                <item><code>//sp/*/name()</code></item>
                <item>returns a list of all of the names of elements that occur within <gi>sp</gi></item>
              </list>
            </item>
            <item><code>distinct-values()</code>
              <list>
                <item><code>distinct-values( //sp/*/name() )</code></item>
                <item>returns a list of all of the element types that occur inside speeches</item>
              </list>
            </item>
            <item><code>count()</code>
              <list>
                <item><code>count( //sp/p )</code></item>
                <item>gives us the number of paragraphs that occur as a child of speech</item>
              </list>
            </item>
          </list>
        </slide>
      </section>
      
      <section>
        <head>Some more functions</head>
        <slide>
          <list type="incremental">
            <item><code>contains()</code>
              <list>
                <item><code>//stage[ contains( .,'exit') ]</code></item>
                <item>Shows us all the stage directions that contain the string <q>exit</q></item>
                <item><q><hi style="font-size: larger;">.</hi></q> means <q>search within the current element (self)</q> and the string to be searched for is within quotes after the comma</item>
                <item>Note: straight quotes, never curly</item>
                <item>Question: why single quotes instead of double?</item>
              </list>
            </item>
            <item>
              <code>substring-after()</code>
              <list>
                <item><code>//sp/substring-after( @who,'#')</code></item>
                <item>Returns the part of param1 that is after param2</item>
                <item>Useful if you want to find everything after a specific, consistent prefix</item>
                <item>Thus <code>id( substring-after( ancestor::sp/@who,'#') )</code> gets you
                the <gi>role</gi> element of whoever is speaking at the moment (i.e., where
                the cursor is in oXygen), except fails silently when there is more than
                one speaker</item>
              </list>
            </item>
          </list>
        </slide>
      </section>
       
      <section>
        <head>XPath Predicates</head>
        <slide>
          <list type="incremental">
            <item>You use paths and axes in XPath to arrive at specific nodes in your XML.</item>
            <item>You use predicates to further filter or test those nodes.</item>
            <item>Only nodes which satisfy the predicate will be selected.</item>
            <item>Predicates <emph>follow</emph> the step they apply to, and use <emph>square brackets</emph>.</item>
            <item><code>/TEI/text/body/div</code> means <q>all the
            <gi>div</gi> nodes which are children of
            <gi>body</gi></q>.
            </item>
            <item><code>/TEI/text/body/div[ @type eq 'act']</code> means
            <q>only those <gi>div</gi> nodes which are children of
            <gi>body</gi> <emph>and also have a type attribute
            with the value <val>act</val></emph></q>.</item>
          </list>
        </slide>
      </section>
      
      <section>
        <head>Some Essential Predicates</head>
        <slide>
          <list type="incremental">
            <item>
              <code>//div[1]</code>, <code>//div/p[3]</code>, <code>//list/item[12]</code>
              <list>
                <item>Numbers as predicates allow you to search for the <emph>Nth</emph> child</item>
              </list>
            </item>
            <item>Axes (e.g., <code>descendant::</code>, <code>parent::</code>, and <code>ancestor::</code>) can be used in predicates
              <list>
                <item><code>//div[descendant::persName]</code> searches for divisions that have descendants of <gi>persName</gi><lb/>— what you get back is a sequence of <gi>div</gi>s</item>
                <item>(as opposed to <code>//div//persName</code>, which searches for the <gi>persName</gi> elements that are descendants of <gi>div</gi><lb/>— what you get back is a sequence of <gi>persName</gi>s)</item>
              </list>
            </item>
          </list>
        </slide>
      </section>
      
      <section>
        <head>XPath Predicates: some examples</head>
        <slide>
          <list type="incremental">
            <item><code>//div[head]</code></item>
            <item> = all <gi>div</gi> nodes which have a direct child <gi>head</gi> element.</item>
            <item><code>//sp//stage[contains(.,"Ghost")]</code></item>
            <item> = all <gi>stage</gi> nodes that are inside an <gi>sp</gi> and contain the text <q>Ghost</q>.</item>
            <item><code>/TEI/teiHeader/fileDesc/titleStmt/editor[2]</code></item>
            <item> = the second <gi>editor</gi> node in the <gi>titleStmt</gi>.</item>
            <item><code>(//div)[position() = last()]</code></item>
            <item> = the last <gi>div</gi> node in the document.</item>
            <item>Any guesses about why <code>(//div)</code> is wrapped in parentheses here?</item>
          </list>
        </slide>
      </section>
      
      <section>
        <head>XPath Predicates can be chained</head>
        <slide>
          <list type="incremental">
            <item><code>//div[ @type eq 'scene'][ count(descendant::l) gt 200 ]</code></item>
            <item> = all scenes containing more than 200 lines.</item>
            <item><code>//div[ contains( head, 'Scene') ][ descendant::sp/@who eq '#Horatio']</code></item>
            <item> = all scenes in which Horatio speaks.</item>
            <item><code>//sp[ position() eq last() ][ @who eq '#Hamlet']</code></item>
            <item> = speeches by Hamlet which are the last speeches in their scene.</item>
          </list>
        </slide>
        <lectureNote><p>The Hamlet file actually has lots of
        <gi>ab</gi> elements in speeches as well as <gi>l</gi>
        elements, so this line count stuff is not a true reflection of
        the length of speeches. It might be worth telling the students
        there's something wrong with it, and asking them to look at
        the XML source to see if they can figure out what it is. Then
        you could amend the first item in this slide, and some of the
        ones in the next slide, to account for this.</p></lectureNote>
        <tutorial><p>The Hamlet file actually has lots of <gi>ab</gi>
        elements in speeches as well as <gi>l</gi> elements, so this
        line count stuff is not a true reflection of the length of
        speeches. It might be worth telling the students there's
        something wrong with it, and asking them to look at the XML
        source to see if they can figure out what it is. Then you
        could amend the first item in this slide, and some of the ones
        in the next slide, to account for this.</p></tutorial>
      </section>
      
      <section>
        <head>XPath Predicates can be nested</head>
        <slide>
          <list type="incremental">
            <item><code>//sp[ descendant::l[ contains(., "Ophelia") ] ]</code></item>
            <item> = all speeches which contain metrical lines which mention Ophelia.</item>
            <item><code>//div[ contains( head, "Scene") ][ count( descendant::sp[ @who eq '#Hamlet']) gt 30 ]</code></item>
            <item> = all scenes in which Hamlet has more than 30 speeches.</item>
            <item><code>//sp[ count( descendant::l[ contains( .,'love') ] ) gt 2]</code></item>
            <item> = speeches with three or more lines that mention <mentioned>love</mentioned>.</item>
            <item><code>//sp[ count( l[contains( .,'love') ] ) gt 2]</code></item>
            <item>How does this differ from the XPath above? Under what circumstances would this difference matter?</item>
          </list>
        </slide>
      </section>

      <section>
        <head>More fun with XPath Node Predicates and Functions</head>
        <slide>
          <list type="incremental">
            <item>What is the last speech that Hamlet gives in any given scene?</item>
            <item> - <code>//sp[@who eq '#Hamlet'][ position() eq last() ]</code></item>
            <item>How do we modify this to find Hamlet's last speech <emph>overall</emph>?</item>
            <item><label>BONUS!</label> What happens if we switch those two predicates?</item>
          </list>
        </slide>
      </section>
      
      <section>
        <head>Let's try some exercises together</head>
        <slide>
          <list>
            <item>How many speeches contain prose (encoded with <gi>ab</gi>)?</item>
            <item>How many lines of poetry are there in speeches within Hamlet?</item>
            <item>What elements occur within poetic lines in speeches? Prose within speeches?</item>
            <item>Find all of the exits where multiple people leave the stage (hint: <q>exeunt</q> is usually usedin stage directions where multiple characters leave the stage)</item>
            <item>How many times does Hamlet speak in the play?</item>
            <!--2018-08-31 ebb: To determine when and where you need a predicate, you need to be clear about whether you want your XPath expression to result in a node on the tree that meets X conditions, or if you want the result of the function instead. 
                For example, say we are working with the play Hamlet in the Shakespeare collection. Do you want the count of the number of times Hamlet speaks in the play? Then you want a function that wraps around a path expression containing the predicate inside it. We need to do this in stages to think it out:
                Step 1: Find all the speeches in the play spoken by Hamlet:
                a) Look up Hamlet's id: I found it by first finding the personography in the Hamlet file, and skimming through the @xml:ids with //listPerson/person/@xml:id and reading through until I found Hamlet: F-ham-ham.
                b) Now I go and find the speeches in the play by Hamlet with:
                //sp[@who="#F-ham-ham"]
                
                Step 2: Count them by wrapping the expression with the count() function:
                count(//sp[@who="#F-ham-ham"]) This returns just one thing: the number. 
                Imagine creating a new XML or HTML document, or a simple graph, that compares and ranking all of the characters in the play by the count of their speakers! We will make a little chart like this in the next section of this workshop where we show some fun applications of XPath.
            -->
            <item>Find all of the scenes where Hamlet has more than 10 speeches.</item>
          </list>
        </slide>
      </section>
      
</presentation>
</text>
</TEI>

