<?xml version="1.0" encoding="UTF-8"?>
<schema xmlns="http://purl.oclc.org/dsdl/schematron" queryBinding="xslt2">
  <title>ISO Schematron rules</title>
  <!-- This file generated 2026-06-10T16:23:09Z by 'extract-isosch.xsl'. -->
  <!--
      And then modified by the build procedure as follows:
      * All namespace declarations removed except those for
        - TEI, bound to main TEI namespace;
        - wwp, bound to main WWP namespace;
        - xi,  bound to the XInclude namespace.
      * Changed tei: to wwp: passim. (Note that this does NOT
        change the TEI: prefix — the change is made case senstively.)
      * This bloc comment added.
      See the Makefile (target wwp-store.isosch:) for details.
  -->
  <!-- ********************* -->
  <!-- namespaces, declared: -->
  <!-- ********************* -->
  <ns prefix="TEI" uri="http://www.tei-c.org/ns/1.0"/>
  <ns prefix="wwp" uri="http://www.wwp.northeastern.edu/ns/textbase"/>
  <ns prefix="xi" uri="http://www.w3.org/2001/XInclude"/>
  <ns prefix="xs" uri="http://www.w3.org/2001/XMLSchema"/>
  <ns prefix="xs" uri="http://www.w3.org/2001/XMLSchema"/>
  <!-- ******************************************************** -->
  <!-- constraints in en, und, mul, zxx, of which there are 111 -->
  <!-- ******************************************************** -->
  <pattern id="schematron-constraint-CMC_generatedBy_within_post-1">
    <rule context="wwp:*[@generatedBy]">
      <assert test="ancestor-or-self::wwp:post">The @generatedBy attribute is for use within a &lt;post&gt; element.</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-att-datable-w3c-when-2">
    <rule context="wwp:*[@when]">
      <report test="@notBefore|@notAfter|@from|@to" role="nonfatal">The @when attribute cannot be used with any other att.datable.w3c attributes.</report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-att-datable-w3c-from-3">
    <rule context="wwp:*[@from]">
      <report test="@notBefore" role="nonfatal">The @from and @notBefore attributes cannot be used together.</report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-att-datable-w3c-to-4">
    <rule context="wwp:*[@to]">
      <report test="@notAfter" role="nonfatal">The @to and @notAfter attributes cannot be used together.</report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-only_1_ODD_source-5">
    <rule context="wwp:*[@source]">
      <let name="srcs" value="tokenize( normalize-space(@source),' ')"/>
      <report test="(   self::wwp:classRef                                 | self::wwp:dataRef                                 | self::wwp:elementRef                                 | self::wwp:macroRef                                 | self::wwp:moduleRef                                 | self::wwp:schemaSpec )                                   and                                   $srcs[2]"> When used on a schema description element (like <value-of select="name(.)"/>), the @source attribute should have only 1 value. (This one has <value-of select="count($srcs)"/>.)</report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-only_1_ODD_source-6">
    <rule context="wwp:*[@source]">
      <let name="srcs" value="tokenize( normalize-space(@source),' ')"/>
      <report test="(   self::wwp:classRef                                 | self::wwp:dataRef                                 | self::wwp:elementRef                                 | self::wwp:macroRef                                 | self::wwp:moduleRef                                 | self::wwp:schemaSpec )                                   and                                   $srcs[2]"> When used on a schema description element (like <value-of select="name(.)"/>), the @source attribute should have only 1 value. (This one has <value-of select="count($srcs)"/>.)</report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-unit_iff_in_extent-7">
    <rule context="wwp:extent/wwp:measure">
      <assert test="@unit">When &lt;measure&gt; is used inside &lt;extent&gt; (typically in the &lt;teiHeader&gt;) it should have a @unit.</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-unit_iff_in_extent-8">
    <rule context="wwp:measure[ not( parent::wwp:extent ) ]">
      <report test="@unit">When &lt;measure&gt; is used as a transcriptional element (i.e., inside &lt;text&gt;, not &lt;teiHeader&gt;) it should not have a @unit.</report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-targetLang-9">
    <rule context="wwp:*[not(self::wwp:schemaSpec)][@targetLang]">
      <assert test="@target">@targetLang should only be used on <name/> if @target is specified.</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-spanTo-points-to-following-10">
    <rule context="wwp:*[ starts-with( @spanTo, '#') ]">
      <assert test="id( substring( @spanTo, 2 ) ) &gt;&gt; ."> The element indicated by @spanTo (<value-of select="@spanTo"/>) must follow the current <name/> element</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-spanTo-to-anchor-11">
    <rule context="wwp:*[@spanTo]">
      <let name="spanTo" value="substring(@spanTo,2)"/>
      <let name="spanEnd" value="id( $spanTo )"/>
      <assert test="$spanEnd/self::wwp:anchor"> The @spanTo of <gi xmlns="http://www.tei-c.org/ns/1.0" xmlns:rng="http://relaxng.org/ns/structure/1.0" xmlns:sch="http://purl.oclc.org/dsdl/schematron" xmlns:sqf="http://www.schematron-quickfix.com/validator/process" xmlns:teix="http://www.tei-c.org/ns/Examples" xmlns:xi="http://www.w3.org/2001/XInclude"><name xmlns="http://purl.oclc.org/dsdl/schematron"/></gi> must point to an <gi xmlns="http://www.tei-c.org/ns/1.0" xmlns:rng="http://relaxng.org/ns/structure/1.0" xmlns:sch="http://purl.oclc.org/dsdl/schematron" xmlns:sqf="http://www.schematron-quickfix.com/validator/process" xmlns:teix="http://www.tei-c.org/ns/Examples" xmlns:xi="http://www.w3.org/2001/XInclude">anchor</gi>; this one (<val xmlns="http://www.tei-c.org/ns/1.0" xmlns:rng="http://relaxng.org/ns/structure/1.0" xmlns:sch="http://purl.oclc.org/dsdl/schematron" xmlns:sqf="http://www.schematron-quickfix.com/validator/process" xmlns:teix="http://www.tei-c.org/ns/Examples" xmlns:xi="http://www.w3.org/2001/XInclude"><value-of xmlns="http://purl.oclc.org/dsdl/schematron" select="@spanTo"/></val>) points to a <gi xmlns="http://www.tei-c.org/ns/1.0" xmlns:rng="http://relaxng.org/ns/structure/1.0" xmlns:sch="http://purl.oclc.org/dsdl/schematron" xmlns:sqf="http://www.schematron-quickfix.com/validator/process" xmlns:teix="http://www.tei-c.org/ns/Examples" xmlns:xi="http://www.w3.org/2001/XInclude"><value-of xmlns="http://purl.oclc.org/dsdl/schematron" select="local-name($spanEnd)"/></gi>.</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-schemeVersionRequiresScheme-12">
    <rule context="wwp:*[@schemeVersion]">
      <assert test="@scheme and not(@scheme = 'free')"> @schemeVersion can only be used if @scheme is specified.</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-subtypeTyped-13">
    <rule context="wwp:*[@subtype]">
      <assert test="@type">The <name/> element should not be categorized in detail with @subtype unless also categorized in general with @type</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-calendar_points_to_calendar-14">
    <rule context="*[@calendar]">
      <assert test="/wwp:TEI/wwp:teiHeader/wwp:profileDesc/wwp:calendarDesc/wwp:calendar/@xml:id = substring( normalize-space(@calendar), 2 )">The @calendar attribute of <value-of select="name(.)"/> should point to a <gi xmlns="http://www.tei-c.org/ns/1.0" xmlns:rng="http://relaxng.org/ns/structure/1.0" xmlns:sch="http://purl.oclc.org/dsdl/schematron" xmlns:sqf="http://www.schematron-quickfix.com/validator/process" xmlns:teix="http://www.tei-c.org/ns/Examples" xmlns:xi="http://www.w3.org/2001/XInclude">calendar</gi> element, but this one ("<value-of select="normalize-space(@calendar)"/>") does not; this error will always occur unless you perform XInclude processing before validation (to do so in oXygen check “Enable XInclude Processing” in the XML / XML Parser / XInclude Options preferences pane)</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-xmlID-is-unique-15">
    <rule context="@xml:id">
      <let name="thisID" value="normalize-space(.)"/>
      <report test="../(ancestor::*|preceding::*)/@xml:id[ normalize-space(.) eq $thisID ]                                  ">The @xml:id "<value-of select="$thisID"/>" on &lt;<value-of select="name(..)"/>&gt; duplicates an @xml:id found earlier in the document</report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-calendar_attr_on_empty_element-16">
    <rule context="wwp:*[@calendar]">
      <assert test="string-length( normalize-space(.) ) gt 0"> @calendar indicates one or more systems or calendars to which the date represented by the content of this element belongs, but this <name/> element has no textual content.</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-abstractModel-structure-p-in-ab-or-p-17">
    <rule context="wwp:p">
      <report test="(ancestor::wwp:ab or ancestor::wwp:p) and                        not( ancestor::wwp:floatingText                           | parent::wwp:exemplum                           | parent::wwp:item                           | parent::wwp:note                           | parent::wwp:q                           | parent::wwp:quote                           | parent::wwp:remarks                           | parent::wwp:said                           | parent::wwp:sp                           | parent::wwp:stage                           | parent::wwp:cell                           | parent::wwp:figure )"> Abstract model violation: Paragraphs may not occur inside other paragraphs or ab elements.</report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-abstractModel-structure-p-in-l-18">
    <rule context="wwp:l//wwp:p">
      <assert test="ancestor::wwp:floatingText | parent::wwp:figure | parent::wwp:note"> Abstract model violation: Metrical lines may not contain higher-level structural elements such as div, p, or ab, unless p is a child of figure or note, or is a descendant of floatingText.</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-some_must_have_rend-19">
    <rule context="wwp:text//wwp:hi | wwp:text//wwp:mcr | wwp:text//wwp:emph">
      <let name="myName" value="local-name(.)"/>
      <let name="myDefaultRendition" value="/wwp:TEI/wwp:teiHeader/wwp:encodingDesc/wwp:tagsDecl/wwp:rendition[ $myName = tokenize( @selector,'[ ,]+') ]"/>
      <let name="myRealRend" value="concat( $myDefaultRendition, @rend )"/>
      <assert test="contains( $myRealRend, '(')">Wha? This <gi xmlns="http://www.tei-c.org/ns/1.0" xmlns:rng="http://relaxng.org/ns/structure/1.0" xmlns:sch="http://purl.oclc.org/dsdl/schematron" xmlns:sqf="http://www.schematron-quickfix.com/validator/process" xmlns:teix="http://www.tei-c.org/ns/Examples" xmlns:xi="http://www.w3.org/2001/XInclude"><value-of xmlns="http://purl.oclc.org/dsdl/schematron" select="$myName"/></gi> element has no (usable) rendition</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-quotation_cit-1">
    <rule context="wwp:quote[ starts-with( @cit,'#' ) ]">
      <assert test="//wwp:bibl[ @xml:id eq substring-after( current()/@cit,'#' ) ]">cit= attribute of &lt;<name/>&gt; does not point to a &lt;bibl&gt;.</assert>
    </rule>
    <rule context="wwp:quote[ contains(@cit,'#') ]">
      <assert test="document( substring-before( @cit,'#') )//wwp:bibl[ @xml:id = substring-after( current()/@cit,'#') ]">cit= attribute of &lt;<name/>&gt; does not point to a &lt;bibl&gt;.</assert>
    </rule>
    <rule context="wwp:quote[ @cit ]">
      <report test="not( contains( @cit,'#') )">cit= attribute of &lt;<name/>&gt; must point to particular &lt;bibl&gt; element via its xml:id=</report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-deprecationInfo-only-in-deprecated-23">
    <rule context="wwp:desc[ @type eq 'deprecationInfo']">
      <assert test="../@validUntil">Information about a deprecation should only be present in a specification element that is being deprecated: that is, only an element that has a @validUntil attribute should have a child &lt;desc type="deprecationInfo"&gt;.</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-no_correction_of_erroneous_metawork-24">
    <rule context="wwp:sic[@type eq 'metawork']">
      <report test="parent::wwp:choice or (preceding-sibling::*[1]|following-sibling::*[1])[self::wwp:corr]">At the WWP we do not correct metawork errors</report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-no_content_in_erroneous_metawork_flag-25">
    <rule context="wwp:sic[@type eq 'metawork']">
      <report test=".//* | .//text()[ normalize-space(.) != '']">Metawork error flags should not have content</report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-orig-not-belong-26">
    <rule context="wwp:orig">
      <report test="ancestor::wwp:mw">An <gi xmlns="http://www.tei-c.org/ns/1.0" xmlns:rng="http://relaxng.org/ns/structure/1.0" xmlns:sch="http://purl.oclc.org/dsdl/schematron" xmlns:sqf="http://www.schematron-quickfix.com/validator/process" xmlns:teix="http://www.tei-c.org/ns/Examples" xmlns:xi="http://www.w3.org/2001/XInclude">orig</gi> should not be inside an <gi xmlns="http://www.tei-c.org/ns/1.0" xmlns:rng="http://relaxng.org/ns/structure/1.0" xmlns:sch="http://purl.oclc.org/dsdl/schematron" xmlns:sqf="http://www.schematron-quickfix.com/validator/process" xmlns:teix="http://www.tei-c.org/ns/Examples" xmlns:xi="http://www.w3.org/2001/XInclude">mw</gi>
         </report>
      <report test="ancestor::wwp:orig" role="warning">Generally speaking, an <gi xmlns="http://www.tei-c.org/ns/1.0" xmlns:rng="http://relaxng.org/ns/structure/1.0" xmlns:sch="http://purl.oclc.org/dsdl/schematron" xmlns:sqf="http://www.schematron-quickfix.com/validator/process" xmlns:teix="http://www.tei-c.org/ns/Examples" xmlns:xi="http://www.w3.org/2001/XInclude">orig</gi> should not be within an <gi xmlns="http://www.tei-c.org/ns/1.0" xmlns:rng="http://relaxng.org/ns/structure/1.0" xmlns:sch="http://purl.oclc.org/dsdl/schematron" xmlns:sqf="http://www.schematron-quickfix.com/validator/process" xmlns:teix="http://www.tei-c.org/ns/Examples" xmlns:xi="http://www.w3.org/2001/XInclude">orig</gi>
         </report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-gap-attr-combo-27">
    <rule context="wwp:gap">
      <report role="error" test="                                   (                                     @reason = ('damaged','deleted','obscured','flawed-reproduction','excerpt','other')                                     and                                     @desc = ('attachment','embossing')                                   )                                   or                                   ( @reason eq 'obscured'  and  @desc eq 'unknown' )                                   ">reason="<value-of select="@reason"/>" and desc="<value-of select="@desc"/>" of &lt;gap&gt; is an invalid combination</report>
      <report role="warning" test="                                   (                                     @reason = ('deleted','flawed-reproduction','excerpt','omitted','illegible-handwriting')                                     and                                     @desc eq 'unknown'                                   )                                   or                                   (                                     @reason eq 'other'  and  @desc = ('handwriting','printed')                                   )                                   ">are you sure the combination of reason="<value-of select="@reason"/>" and desc="<value-of select="@desc"/>" of &lt;gap&gt; makes sense?</report>
      <assert role="error" test="if ( @desc eq 'other' )                                   then id( substring( normalize-space( @corresp ), 2 ) )[self::wwp:note]                                   else true()">When the description is just "other", there should be a <gi xmlns="http://www.tei-c.org/ns/1.0" xmlns:rng="http://relaxng.org/ns/structure/1.0" xmlns:sch="http://purl.oclc.org/dsdl/schematron" xmlns:sqf="http://www.schematron-quickfix.com/validator/process" xmlns:teix="http://www.tei-c.org/ns/Examples" xmlns:xi="http://www.w3.org/2001/XInclude">note</gi> explaining the gap (and @corresp should point to that note)</assert>
      <report role="error" test="@reason eq 'illegible-handwriting'                                   and                                   @desc ne 'handwriting'">When the reason a gap is not readable is 'illegible-handwriting', then the description of that which is unreadable should be 'handwriting'</report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-hand_checks-2">
    <rule context="*[ starts-with( @hand,'#') ]">
      <assert test="//wwp:handNote[ @xml:id = substring-after( current()/@hand,'#') ]">hand= attribute of &lt;<name/>&gt; does not point to a &lt;handNote&gt; (local)</assert>
    </rule>
    <rule context="*[ contains( @hand,'#') ]">
      <assert test="document( substring-before( @hand,'#') )                                 //wwp:handNote[ @xml:id = substring-after( current()/@hand,'#') ]">hand= attribute of &lt;<name/>&gt; does not point to a &lt;handNote&gt; (external)</assert>
    </rule>
    <rule context="*[@hand]">
      <report test="not(contains(@hand,'#'))">hand= attribute of &lt;<name/>&gt; must point to particular &lt;handNote&gt; element via its xml:id=</report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-hand_checks-3">
    <rule context="wwp:gap[@hand|@agent|@degree|@group]">
      <assert test="substring-before( @reason, '-') ='damaged'"> The hand=, agent=, degree=, and group= attributes of &lt;<name/>&gt; should only be specified if the reason= attribute is one that indicates damage in the source (i.e., starts with “damaged-”).</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-handwritten_additions_must_have_hand_attr-32">
    <rule context="wwp:add[ not( @hand )]">
      <assert test="@type = ('printed','stamped')"> A handwritten addition must have a @hand attribute</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-datingAttr_required-4">
    <rule context="wwp:application                                   |wwp:date[ not(@prev) and ( @calendar = ('#cal_Gregorian','#cal_NS','#cal_Julian') or not( @calendar ) ) ]                                   |wwp:time[ not(@prev) and ( @calendar = ('#cal_Gregorian','#cal_NS','#cal_Julian') or not( @calendar ) ) ]">
      <assert test="@when or @when-custom or @when-iso or                                     @notBefore or @notBefore-custom or @notBefore-iso or                                     @notAfter or @notAfter-iso or @notAfter-custom or                                     @from or @from-custom or @from-iso or                                     @to or @to-custom or @to-iso">At least one temporal normalization attribute should be specified on a &lt;<value-of select="name(.)"/>&gt;<value-of select="if (@calendar) then concat(' with calendar=', @calendar) else ''"/> (unless it has @prev).</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-datingAttr_notAllowed-5">
    <rule context="wwp:date[ @prev or @calendar = ('#cal_Mundi','#cal_undetermined') ]                                   |wwp:time[ @prev or @calendar = ('#cal_Mundi','#cal_undetermined') ]">
      <report test="@when or @when-custom or @when-iso or                                     @notBefore or @notBefore-custom or @notBefore-iso or                                     @notAfter or @notAfter-iso or @notAfter-custom or                                     @from or @from-custom or @from-iso or                                     @to or @to-custom or @to-iso">No temporal normalization attributes may be specified on a &lt;<value-of select="name(.)"/>&gt; that has <value-of select="if (@prev) then 'a @prev attriute' else concat('has calendar=', @calendar )"/>.</report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-date_in_docDate-35">
    <rule context="wwp:docDate/wwp:date">
      <let name="dateLen" value="string-length(normalize-space(.) )"/>
      <let name="docDateLen" value="string-length(normalize-space(..))"/>
      <report test="$docDateLen - $dateLen gt 2" role="warn">Having a date element nested inside a docDate is rarely required</report>
      <report test="$docDateLen - $dateLen le 2" role="error">The date element is not used inside docDate to represent the same date as the docDate — just use the attributes of docDate.</report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-cert_on_date-36">
    <rule context="wwp:date/@cert">
      <assert test="ancestor::wwp:sourceDesc">Here at the WWP we only indicate uncertain dates inside the &lt;sourceDesc&gt;.</assert>
      <assert test="normalize-space(.) eq 'low'">The value of @cert on &lt;date&gt; should be "low" (or there should be no @cert).</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-issuance_dates-37">
    <rule context="wwp:imprint/wwp:date[2]">
      <let name="numDates" value="count( ../wwp:date )"/>
      <let name="numIssua" value="count( ../wwp:date[@type eq 'issuance'] )"/>
      <assert test="$numDates - $numIssua = 1">One and only of these &lt;date&gt; elements should NOT have type=issuance; all the others should.</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-type_of_date_only_in_sourceDesc-38">
    <rule context="wwp:date/@type">
      <assert test="../parent::wwp:imprint/parent::wwp:monogr/ancestor::wwp:sourceDesc"> An issuance date should only occur in a monogr element inside a source description in the TEI header.</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-ptrAtts-39">
    <rule context="wwp:ptr">
      <report test="@target and @cRef">Only one of the attributes @target and @cRef may be supplied on <name/>.</report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-refAtts-40">
    <rule context="wwp:ref">
      <report test="@target and @cRef">Only one of the attributes @target and @cRef may be supplied on <name/>.</report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-gloss-list-must-have-labels-41">
    <rule context="wwp:list[@type='gloss']">
      <assert test="wwp:label">The content of a "gloss" list should include a sequence of one or more pairs of a label element followed by an item element</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-non-reference-lists-do-not-point-6">
    <rule context="wwp:list[ not( @type = ('toc', 'reference', 'index' ) ) ]">
      <report test="child::wwp:item/@target">&lt;item&gt; elements should only have target= attributes if the list is a table of contents, index, or other reference list</report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-items-point-to-same-author-43">
    <rule context="wwp:list[ @type = ('index','reference','toc') ]/wwp:item/@target">
      <let name="targets" value="tokenize(.)"/>
      <let name="myFileName" value="( base-uri(/) =&gt; tokenize('/') )[last()]"/>
      <let name="myAuthorName" value="substring-before( $myFileName, '.')"/>
      <let name="regexp" value="'^((\./)?'||$myAuthorName||'\.[a-z0-9_-]+\.xml)?#\i\c*$'"/>
      <let name="every_target_resolvable" value="every $t in $targets satisfies                                                                    if ( starts-with( $t,'#') )                                                                    then id( substring( $t, 2 ) )                                                                    else document( substring-before( $t,'#'), . )/id( substring-after( $t, '#') )"/>
      <assert test="every $t in $targets satisfies matches( $t, $regexp )"> one (or more) of the pointers in this target is not in the proper format</assert>
      <assert test="$every_target_resolvable"> one (ore more) of the pointers in this target is not resolvable</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-note-has-target-44">
    <rule context="wwp:text//wwp:note[not(@target)]">
      <report test="ancestor::wwp:hyperDiv | ancestor::wwp:div[@type='endnotes']">ERROR: <value-of select="if (@xml:id) then concat('the note with id=', @xml:id ) else concat('note #',count( preceding::wwp:note))"/> does not have a @target, but should (because it is an endnote or is inside &lt;hyperDiv&gt;)</report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-note-not-point-to-self-45">
    <rule context="wwp:note[@target|@targetEnd]">
      <let name="ptr2me" value="concat('#', @xml:id )"/>
      <report test="tokenize(                                     normalize-space(                                       string-join( ( @target, @targetEnd ), ' ')                                     ),                                     ' '                                   ) = $ptr2me">ERROR: the note element with id=<value-of select="@xml:id"/> refers to itself</report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-textual-note-in-notesStmt-46">
    <rule context="wwp:note[ @type eq 'public']">
      <assert test="parent::wwp:notesStmt">public notes should be in the <gi xmlns="http://www.tei-c.org/ns/1.0" xmlns:rng="http://relaxng.org/ns/structure/1.0" xmlns:sch="http://purl.oclc.org/dsdl/schematron" xmlns:sqf="http://www.schematron-quickfix.com/validator/process" xmlns:teix="http://www.tei-c.org/ns/Examples" xmlns:xi="http://www.w3.org/2001/XInclude">notesStmt</gi> in the TEI header.</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-non-modern-note-not-in-notesStmt-47">
    <rule context="wwp:note[ @type = ('editorial','authorial') ]">
      <report test="parent::wwp:notesStmt"><value-of select="@type"/> notes should not be in the <gi xmlns="http://www.tei-c.org/ns/1.0" xmlns:rng="http://relaxng.org/ns/structure/1.0" xmlns:sch="http://purl.oclc.org/dsdl/schematron" xmlns:sqf="http://www.schematron-quickfix.com/validator/process" xmlns:teix="http://www.tei-c.org/ns/Examples" xmlns:xi="http://www.w3.org/2001/XInclude">notesStmt</gi> in the TEI header.</report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-target-points-back-48">
    <rule context="wwp:note[ ( not(@type)  or  @type eq 'authorial' )  and  @target ]">
      <report test="                   (: open outer sequence of values :)                   (                     (: take each separate pointer in my @target, generate an item that is that pointer with the '#' stripped off :)                     for $T in tokenize( @target )!substring-after( .,'#')                     return                       (: and, for each of those #-less targets (stored as $T),                          a) get the element that it refers to;                          b) take that element’s @corresp;                          c) tokenize that @corresp value string into separate pointers                             (As a side comment, there will generally be only 1, rarely 2,                             and we don’t have any 3+ as of 2023-03-17;                          d) strip the '#' off each of those pointers;                          e) compare each if those #-less pointers to the current &lt;note&gt; elment’s @xml:id.                          If any one of them is equal, then we return true; otherwise false :)                       tokenize( id( $T )/@corresp )!substring-after( .,'#') = @xml:id                   (: close outer sequence of values :)                   )                   (: So we now have a sequence of xs:boolean values, one for each separate pointer in this &lt;note&gt; element’s                      @target, each of which is true iff at least one of the target’s @corresp values points back to the same                      &lt;note&gt;. :)                   (: Ask “is any one of these values false?” Iff so, then we have a problem, warn the user. :)                   = false()">One or more of the values of target of the note with ID <value-of select="@xml:id"/> points to an element whose corresp does not point back</report>
      <assert test="count( tokenize( @target ) ) &gt; 0">Empty @target of &lt;note&gt;</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-note_with_only_add_should_be_add_with_note-49">
    <rule context="wwp:note">
      <report test="*/wwp:add  and  not( */text()[ normalize-space(.) ne '' ] )"><value-of select="if (@xml:id)                               then concat('the note with id=', @xml:id )                               else concat('note #', count( preceding::wwp:note ) )                               "/> should probably be an <gi xmlns="http://www.tei-c.org/ns/1.0" xmlns:rng="http://relaxng.org/ns/structure/1.0" xmlns:sch="http://purl.oclc.org/dsdl/schematron" xmlns:sqf="http://www.schematron-quickfix.com/validator/process" xmlns:teix="http://www.tei-c.org/ns/Examples" xmlns:xi="http://www.w3.org/2001/XInclude">add</gi> with a <gi xmlns="http://www.tei-c.org/ns/1.0" xmlns:rng="http://relaxng.org/ns/structure/1.0" xmlns:sch="http://purl.oclc.org/dsdl/schematron" xmlns:sqf="http://www.schematron-quickfix.com/validator/process" xmlns:teix="http://www.tei-c.org/ns/Examples" xmlns:xi="http://www.w3.org/2001/XInclude">note</gi> inside instead, as it seems to have no content other than an <gi xmlns="http://www.tei-c.org/ns/1.0" xmlns:rng="http://relaxng.org/ns/structure/1.0" xmlns:sch="http://purl.oclc.org/dsdl/schematron" xmlns:sqf="http://www.schematron-quickfix.com/validator/process" xmlns:teix="http://www.tei-c.org/ns/Examples" xmlns:xi="http://www.w3.org/2001/XInclude">add</gi>.</report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-idealSignature-50">
    <rule context="wwp:milestone">
      <let name="me" value="normalize-space(@n)"/>
      <assert test="matches( $me,'((facing|preceding) )?(\p{L}|\p{M}|\p{N}|\p{P}|\p{S})*[0-9]+[\])]?[rv]')"> The idealized signature “<value-of select="@n"/>” does not match the defintion thereof.</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-authors-have-refs-in-metadata-51">
    <rule context="wwp:teiHeader/wwp:fileDesc/wwp:titleStmt/wwp:author/wwp:persName                                 |wwp:teiHeader/wwp:fileDesc/wwp:sourceDesc//wwp:author/wwp:persName">
      <assert test="@ref">Authors should have a reference to the personography.</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-no-nested-metrical-line-52">
    <rule context="wwp:l">
      <report test="descendant::wwp:l">A metrical line should not contain a metrical line</report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-abstractModel-structure-l-in-l-53">
    <rule context="wwp:l">
      <report test="ancestor::wwp:l[not(.//wwp:note//wwp:l[. = current()])]">Abstract model violation: Lines may not contain lines or lg elements.</report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-atleast1oflggapl-54">
    <rule context="wwp:lg">
      <assert test="count(descendant::wwp:lg|descendant::wwp:l|descendant::wwp:gap) &gt; 0">An lg element must contain at least one child l, lg, or gap element.</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-abstractModel-structure-lg-in-l-55">
    <rule context="wwp:lg">
      <report test="ancestor::wwp:l[not(.//wwp:note//wwp:lg[. = current()])]">Abstract model violation: Lines may not contain line groups.</report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-who-points-to-role-56">
    <rule context="wwp:sp[@who]">
      <let name="whos" value="tokenize( normalize-space( @who ), ' ')"/>
      <let name="WHOs" value="for $w in $whos return substring-after( $w,'#')"/>
      <let name="points2something" value="for $w in $WHOs return exists( id( $w ) )"/>
      <let name="pointed2by_who" value="for $w in $WHOs return id($w)"/>
      <report test="$points2something = false()">One or more of the pointers in this @who does not point to a local element.</report>
      <assert test="count( $pointed2by_who ) eq count( $pointed2by_who[self::wwp:role|self::wwp:actor] )">The @who of &lt;sp&gt; is supposed to point a &lt;role&gt; or an &lt;actor&gt;, but this one points to: <value-of select="for $e in $pointed2by_who return concat('&lt;', $e/name(.), '&gt; ')"/>.</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-no_details_in_speaker-57">
    <rule context="wwp:speaker">
      <report test="wwp:persName" role="warning">We do not normally put <gi xmlns="http://www.tei-c.org/ns/1.0" xmlns:rng="http://relaxng.org/ns/structure/1.0" xmlns:sch="http://purl.oclc.org/dsdl/schematron" xmlns:sqf="http://www.schematron-quickfix.com/validator/process" xmlns:teix="http://www.tei-c.org/ns/Examples" xmlns:xi="http://www.w3.org/2001/XInclude">persName</gi> inside of a <gi xmlns="http://www.tei-c.org/ns/1.0" xmlns:rng="http://relaxng.org/ns/structure/1.0" xmlns:sch="http://purl.oclc.org/dsdl/schematron" xmlns:sqf="http://www.schematron-quickfix.com/validator/process" xmlns:teix="http://www.tei-c.org/ns/Examples" xmlns:xi="http://www.w3.org/2001/XInclude">speaker</gi>
         </report>
      <report test="wwp:choice/wwp:abbr|wwp:abbr|wwp:expan" role="warning">We do not typically record or normalize abbreviations (or expansions) inside of a <gi xmlns="http://www.tei-c.org/ns/1.0" xmlns:rng="http://relaxng.org/ns/structure/1.0" xmlns:sch="http://purl.oclc.org/dsdl/schematron" xmlns:sqf="http://www.schematron-quickfix.com/validator/process" xmlns:teix="http://www.tei-c.org/ns/Examples" xmlns:xi="http://www.w3.org/2001/XInclude">speaker</gi>
         </report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-g-points-to-char-58">
    <rule context="wwp:g[@ref][/wwp:TEI/wwp:teiHeader/wwp:encodingDesc/wwp:listPrefixDef]">
      <let name="ref" value="substring( normalize-space( @ref ), 2 )"/>
      <let name="reffed" value="if ( //wwp:charDecl )                                     then id( $ref )                                     else document('../common-boilerplate.xml', /) // *[ @xml:id eq $ref ]"/>
      <let name="test" value="$reffed[ self::wwp:char ]"/>
      <assert test="$test">The @ref of &lt;g&gt; should point to a &lt;char&gt;; this one (<value-of select="@ref"/>) points to <value-of select="if ($reffed)                             then concat('a &lt;', name($reffed),'&gt;')                             else 'nothing'"/>.</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-required_header_bits-10">
    <rule context="wwp:teiHeader">
      <assert test="wwp:profileDesc/wwp:textClass">The WWP requires at least one &lt;textClass&gt; element be present.</assert>
      <assert test="wwp:fileDesc/wwp:editionStmt                                     or                                     wwp:fileDesc/xi:include[                                       contains( @xpointer, 'WWPedition')                                     ]">The WWP requires at least one &lt;editionStmt&gt; element be present or included.</assert>
      <assert test="wwp:encodingDesc/wwp:projectDesc                                     or                                     wwp:encodingDesc/xi:include[                                       contains( @xpointer, 'WWPprojectDescription')                                     ]">The WWP requires at least one &lt;projectDesc&gt; element be present or included.</assert>
      <assert test="wwp:encodingDesc/wwp:samplingDecl                                     or                                     wwp:encodingDesc/xi:include[                                       contains( @xpointer, 'WWPsamplingDeclaration')                                     ]">The WWP requires at least one &lt;samplingDecl&gt; element be present or included.</assert>
      <assert test="wwp:encodingDesc/wwp:editorialDecl                                     or                                     wwp:encodingDesc/xi:include[                                       contains( @xpointer, 'WWPeditorialDeclaration')                                     ]">The WWP requires at least one &lt;editorialDecl&gt; element be present or included.</assert>
      <assert test="wwp:encodingDesc/wwp:charDecl                                     or                                     wwp:encodingDesc/xi:include[                                       contains( @xpointer, 'WWPcharacterDeclaration')                                     ]">The WWP requires at least one &lt;charDecl&gt; element be present or included.</assert>
      <assert test="wwp:encodingDesc/wwp:classDecl                                     or                                     wwp:encodingDesc/xi:include[                                       contains( @xpointer, 'WWPclassificationDeclaration')                                     ]">The WWP requires at least one &lt;classDecl&gt; element be present or included.</assert>
      <assert test="wwp:encodingDesc/wwp:listPrefixDef                                     or                                     wwp:encodingDesc/xi:include[                                       contains( @xpointer, 'WWPlistPrefixDefinitions')                                     ]">The WWP requires at least one &lt;listPrefixDef&gt; element be present or included.</assert>
      <assert test="wwp:encodingDesc/wwp:listPrefixDef">WARNING: &lt;listPrefixDef&gt; not found, so values of @ref will not be tested — if you are using the supraSchemas project, just ignore this warning; otherwise, to validate @refs, perform XInclude processing before validation (to do so in oXygen check “Enable XInclude Processing” in the XML / XML Parser / XInclude Options preferences pane)</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-quotationContents-60">
    <rule context="wwp:quotation">
      <report test="not( @marks )  and  not( wwp:p )"> On <name/>, either the @marks attribute should be used, or a paragraph of description provided</report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-selector-required-if-pointed-at-61">
    <rule context="wwp:rendition">
      <let name="myIDref" value="concat('#', normalize-space( @xml:id ) )"/>
      <assert test="@selector                                   or                                   ( @xml:id and /wwp:TEI/wwp:text//@rendition[ $myIDref = tokenize( normalize-space( . ),' ') ] )                 ">default <gi xmlns="http://www.tei-c.org/ns/1.0" xmlns:rng="http://relaxng.org/ns/structure/1.0" xmlns:sch="http://purl.oclc.org/dsdl/schematron" xmlns:sqf="http://www.schematron-quickfix.com/validator/process" xmlns:teix="http://www.tei-c.org/ns/Examples" xmlns:xi="http://www.w3.org/2001/XInclude">rendition</gi> #<value-of select="(@xml:id, count( preceding::wwp:rendition )+1 )[1]"/> is not the default for anything (no <att xmlns="http://www.tei-c.org/ns/1.0" xmlns:rng="http://relaxng.org/ns/structure/1.0" xmlns:sch="http://purl.oclc.org/dsdl/schematron" xmlns:sqf="http://www.schematron-quickfix.com/validator/process" xmlns:teix="http://www.tei-c.org/ns/Examples" xmlns:xi="http://www.w3.org/2001/XInclude">selector</att> and not pointed to by any <att xmlns="http://www.tei-c.org/ns/1.0" xmlns:rng="http://relaxng.org/ns/structure/1.0" xmlns:sch="http://purl.oclc.org/dsdl/schematron" xmlns:sqf="http://www.schematron-quickfix.com/validator/process" xmlns:teix="http://www.tei-c.org/ns/Examples" xmlns:xi="http://www.w3.org/2001/XInclude">rendition</att>)</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-both-next-and-prev-62">
    <rule context="*[@xml:id]">
      <let name="isAprev" value="//@prev/normalize-space(.) = concat('#',@xml:id)"/>
      <let name="isAnext" value="//@next/normalize-space(.) = concat('#',@xml:id)"/>
      <report xmlns:sqf="http://www.schematron-quickfix.com/validator/process" test="@next and not( $isAprev )" sqf:fix="notpreved">Element <value-of select="@xml:id"/> has a next= but is not pointed at by a prev=</report>
      <report xmlns:sqf="http://www.schematron-quickfix.com/validator/process" test="@prev and not( $isAnext )" sqf:fix="notnexted">Element <value-of select="@xml:id"/> has a prev= but is not pointed at by a next=</report>
      <report xmlns:sqf="http://www.schematron-quickfix.com/validator/process" test="not( @next ) and $isAprev" sqf:fix="nextless">Element <value-of select="@xml:id"/> is pointed at by a prev= but does not have a next=</report>
      <report xmlns:sqf="http://www.schematron-quickfix.com/validator/process" test="not( @prev ) and $isAnext" sqf:fix="prevless">Element <value-of select="@xml:id"/> is pointed at by a next= but does not have a prev=</report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-next-prev-point-appropriately-63">
    <rule context="@prev|@next">
      <let name="element" value=".."/>
      <let name="me" value="normalize-space(.)"/>
      <let name="ptr" value="if ( starts-with( $me,'#') ) then substring-after( $me,'#') else 'ERROR!?!'"/>
      <let name="hasSpace" value="contains( $me,' ')"/>
      <let name="points2local" value="exists( id( $ptr ) )"/>
      <let name="points2same" value="id( $ptr ) is $element"/>
      <let name="points2sameGI" value="name( $element ) eq name( id( $ptr ) )"/>
      <let name="pointsAfter" value="id( $ptr ) &gt;&gt; $element"/>
      <let name="pointsBefore" value="$element &gt;&gt; id( $ptr )"/>
      <let name="msg_part_1" value="concat(                                   '@',                                   name(.),                                   ' of &lt;',                                   name( $element ),                                   '&gt; ',                                   if (../@xml:id)                                     then concat('(with @xml:id &quot;', ../@xml:id,'&quot;)')                                     else ''                                 )"/>
      <report test="$hasSpace"><value-of select="$msg_part_1"/> has more than 1 pointer (a space in a URI should be written '%20')</report>
      <assert test="if ( not( $hasSpace ) ) then ( $points2local ) else true()"><value-of select="$msg_part_1"/> does not point to a local element.</assert>
      <report test="if ( not( $hasSpace ) ) then ( $points2same ) else false()"><value-of select="$msg_part_1"/> points to itself.</report>
      <assert test="if ( not( $hasSpace ) and $points2local ) then ( $points2sameGI ) else true()"><value-of select="$msg_part_1"/> points to a &lt;<value-of select="name( id( $ptr ) )"/>&gt; (it should point to another &lt;<value-of select="name( $element )"/>&gt;).</assert>
      <assert test="if ( not( $hasSpace ) and $points2local and local-name(.) eq 'prev' and not( $points2same ) ) then ( $pointsBefore ) else 'true()'"><value-of select="$msg_part_1"/> points to a &lt;<value-of select="name( id( $ptr ) )"/>&gt; that is after itself.</assert>
      <assert test="if ( not( $hasSpace ) and $points2local and local-name(.) eq 'next' and not( $points2same ) ) then ( $pointsAfter ) else 'true()'"><value-of select="$msg_part_1"/> points to a &lt;<value-of select="name( id( $ptr ) )"/>&gt; that is prior to itself.</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-linkTargets3-64">
    <rule context="wwp:link">
      <assert test="contains(normalize-space(@target),' ')">You must supply at least two values for @target or on <name/>
         </assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-abstractModel-structure-ab-in-l-65">
    <rule context="wwp:l//wwp:ab">
      <assert test="ancestor::wwp:floatingText | parent::wwp:figure | parent::wwp:note"> Abstract model violation: Metrical lines may not contain higher-level divisions such as p or ab, unless ab is a child of figure or note, or is a descendant of floatingText.</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-rend-of-anchor-uses-pre-not-post-66">
    <rule context="wwp:anchor/@rend">
      <report test="contains( ., 'post(')" role="warning">We do not normally use the post() keyword on the @rend of &lt;anchor&gt;, we use pre() instead.</report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-alt-type-element-has-viable-subtype-67">
    <rule context="wwp:alt[ @type eq 'element']">
      <assert test="@subtype castable as xs:Name">When the @type of &lt;alt&gt; is "element", the @subtype must be an element name</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-alt-of-type-gi-point-to-subtype-gis-68">
    <rule context="wwp:alt[ @type eq 'element'][/wwp:TEI/wwp:teiHeader/wwp:encodingDesc/wwp:listPrefixDef]">
      <let name="path" value="'https://www.wwp-test.northeastern.edu/wwo/texts/'"/>
      <let name="TARGETs" value="tokenize( normalize-space( @target ) )"/>
      <let name="TPREFs" value="for $t in $TARGETs return substring-before( $t,':')"/>
      <let name="URLs" value="for $p in $TPREFs return                                   concat( $path, substring-before( /wwp:TEI/wwp:teiHeader/wwp:encodingDesc/wwp:listPrefixDef//wwp:prefixDef[ @ident eq $p ]/@replacementPattern, '#' ) )"/>
      <let name="KEYs" value="for $t in $TARGETs return substring-after( $t,':')"/>
      <let name="ALTERNATEs" value="for $k in $KEYs return                                     if ( count( index-of( $KEYs, $k ) ) eq 1 )                                     then                                       if ( doc-available( $URLs[ index-of( $KEYs, $k )] ) )                                       then                                         if ( document( $URLs[ index-of( $KEYs, $k )] )//TEI:*[ @xml:id eq $k ] )                                         then                                           document( $URLs[ index-of( $KEYs, $k )] )//TEI:*[ @xml:id eq $k ]                                         else .                                       else .                                     else ."/>
      <let name="CORRECTs" value="for $gi in $ALTERNATEs return name($gi) eq @subtype"/>
      <report test="count( $TARGETs ) eq 0">Empty @target of &lt;alt&gt;</report>
      <report test="$CORRECTs = false()">Each pointer in the @target of &lt;alt&gt; should point to a &lt;<value-of select="@subtype"/>&gt;, but at least one of the pointers in this one ("<value-of select="normalize-space( @target )"/>") point to: <value-of select="if ( not( ALTERNATEs ) )                           then 'nowhere'                           else for $a in $ALTERNATEs return                             if ( $a is . )                             then ' nothing'                             else concat(' &lt;', name($a), '&gt;')"/>.</report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-duplicateDim-69">
    <rule context="wwp:dimensions">
      <report test="count(wwp:width) gt 1"> The element <name/> may appear once only</report>
      <report test="count(wwp:height) gt 1"> The element <name/> may appear once only</report>
      <report test="count(wwp:depth) gt 1"> The element <name/> may appear once only</report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-persName-refers-to-person-or-alt-22">
    <rule context="wwp:persName/@ref [/wwp:TEI/wwp:teiHeader/wwp:encodingDesc/wwp:listPrefixDef]                                    | wwp:change/@who [/wwp:TEI/wwp:teiHeader/wwp:encodingDesc/wwp:listPrefixDef]                                    | */@author       [/wwp:TEI/wwp:teiHeader/wwp:encodingDesc/wwp:listPrefixDef]                                    | */@resp         [/wwp:TEI/wwp:teiHeader/wwp:encodingDesc/wwp:listPrefixDef]">
      <let name="path" value="'https://www.wwp.northeastern.edu/wwo/texts/'"/>
      <let name="myElement" value="."/>
      <let name="gi" value="local-name(..)"/>
      <let name="att" value="local-name(.)"/>
      <let name="val" value="normalize-space(.)"/>
      <let name="TOKs" value="tokenize( normalize-space( $val ), ' ')"/>
      <let name="REFs" value="for $t in $TOKs return if ( matches( $t, '\i\c*:\i\c*') ) then $t else '∅'"/>
      <let name="SHRTs" value="for $t in $TOKs return if ( matches( $t, '#\i\c*') ) then $t else '∅'"/>
      <let name="NOTs" value="$TOKs[ not( matches( ., '(#|\i\c*:)\i\c*') ) ]"/>
      <let name="TARs" value="for $s in $SHRTs return if ( $s eq '∅') then $s else substring-after( $s,'#')"/>
      <let name="PREFs" value="for $r in $REFs return if ( $r eq '∅') then $r else substring-before( $r,':')"/>
      <let name="KEYs" value="for $r in $REFs return if ( $r eq '∅') then $r else substring-after( $r,':')"/>
      <let name="URLs" value="for $p in $PREFs return concat(                                               $path,                                               substring-before( /wwp:TEI/wwp:teiHeader/wwp:encodingDesc/wwp:listPrefixDef//wwp:prefixDef[ @ident eq $p ]/@replacementPattern, '#' )                                               )"/>
      <let name="PERSONs_via_prefix" value="for $k in $KEYs return                                     if ( count( index-of( $KEYs, $k ) ) eq 1 )                                     then                                       if ( doc-available( $URLs[ index-of( $KEYs, $k )] ) )                                       then                                         if ( document( $URLs[ index-of( $KEYs, $k )] )//TEI:*[ @xml:id eq $k ] )                                         then                                           document( $URLs[ index-of( $KEYs, $k )] )//TEI:*[ @xml:id eq $k ]                                         else $myElement                                       else $myElement                                     else $myElement"/>
      <let name="PERSONs_via_short" value="for $t in $TARs return //*[ @xml:id eq $t ]"/>
      <let name="nodes_via_prefix" value="$PERSONs_via_prefix[ not( . eq ''  or  . eq '∅'  or  . is $myElement ) ]"/>
      <let name="nodes_via_short" value="$PERSONs_via_short[self::*]"/>
      <let name="num_not_via_prefix" value="count( $nodes_via_prefix ) - count( $nodes_via_prefix[ self::TEI:person | self::TEI:personGrp | self::TEI:alt ])"/>
      <let name="num_not_via_short" value="count( $nodes_via_short  ) - count( $nodes_via_short [ self::wwp:person | self::wwp:personGrp | self::wwp:alt ])"/>
      <let name="node_names" value="string-join( for $p in ( $nodes_via_prefix, $nodes_via_short ) return concat(' &lt;', name($p), '&gt;'), ', ')"/>
      <report test="count( $NOTs ) eq count( $TOKs )">No usable pointers in @<value-of select="$att"/> of &lt;<value-of select="$gi"/>&gt;</report>
      <report test="count( $NOTs ) gt 0  and  count( $NOTs ) lt count( $TOKs )">At least one of the pointers in @<value-of select="$att"/> of &lt;<value-of select="$gi"/>&gt; is not processable as a pointer (problemetic value(s): "<value-of select="$NOTs"/>").</report>
      <report test="false()">
        <value-of select="concat('debug: ',count($TOKs), ' TOKs=', string-join( $TOKs,'^'),  '; ')"/>
        <value-of select="concat('debug: ',count($REFs), ' REFs=', string-join( $REFs,'^'),  '; ')"/>
        <value-of select="concat('debug: ',count($SHRTs),' SHRTs=',string-join( $SHRTs,'^'), '; ')"/>
        <value-of select="concat('debug: ',count($NOTs), ' NOTs=', string-join( $NOTs,'^'),  '; ')"/>
        <value-of select="concat('debug: ',count($PREFs),' PREFs=',string-join( $PREFs,'^'), '; ')"/>
        <value-of select="concat('debug: ',count($URLs), ' URLs=', string-join( $URLs,'^'),  '; ')"/>
        <value-of select="concat('debug: ',count($KEYs), ' KEYs=', string-join( $KEYs,'^'),  '; ')"/>
        <value-of select="concat('debug: ',count($TARs), ' TARs=', string-join( $TARs,'^'),  '; ')"/>
        <value-of select="concat('debug: ',count($PERSONs_via_prefix), ' PERSONs_via_prefix; ')"/>
        <value-of select="concat('debug: ',count($PERSONs_via_short), ' PERSONs_via_short=', string-join( $PERSONs_via_short,'^'), '; ')"/>
        <value-of select="concat('debug: ',count($nodes_via_prefix), ' nodes_via_prefix; ')"/>
        <value-of select="concat('debug: ',count($nodes_via_short), ' nodes_via_short; ')"/>
        <value-of select="concat('debug: num_not_via_prefix=', $num_not_via_prefix, '; ')"/>
        <value-of select="concat('debug: num_not_via_short=', $num_not_via_short, '; ')"/>
        <value-of select="concat('debug: ',count($NOTs), ' NOTs=', string-join( $NOTs,'^'),  '; ')"/>
        <value-of select="'debug: counts of nodes ='"/>
        <value-of select="for $n in ( $nodes_via_prefix, $nodes_via_short ) return count( $n )"/>
        <value-of select="'; '"/>
      </report>
      <report test="count( $nodes_via_prefix ) + count( $nodes_via_short ) eq 0">Each pointer in the <value-of select="$att"/> attribute of &lt;<value-of select="$gi"/>&gt; should point to a &lt;person&gt; (or &lt;personGrp&gt; or an &lt;alt&gt;), but the pointer(s) in this one ("<value-of select="$val"/>") point to nothing</report>
      <report test="$num_not_via_prefix + $num_not_via_short gt 0"> Each pointer in the <value-of select="$att"/> attribute of &lt;<value-of select="$gi"/>&gt; should point to a &lt;person&gt; (or &lt;personGrp&gt; or an &lt;alt&gt;), but at least one of the pointers in this one ("<value-of select="$val"/>") does not. <value-of select="if ( $nodes_via_prefix | $nodes_via_short )                                           then concat(' Those that point to elements point to:', $node_names, ' (not necessarily in that order).')                                           else ''"/>
         </report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-placeName-refers-to-place-23">
    <rule context="wwp:placeName[@ref][/wwp:TEI/wwp:teiHeader/wwp:encodingDesc/wwp:listPrefixDef]">
      <let name="path" value="'https://www.wwp-test.northeastern.edu/wwo/texts/'"/>
      <let name="val" value="normalize-space( @ref )"/>
      <let name="gi" value="local-name(.)"/>
      <let name="REFs" value="tokenize( $val, ' ')"/>
      <let name="PREFs" value="for $r in $REFs return substring-before( $r,':')"/>
      <let name="URLs" value="for $p in $PREFs return                                   concat( $path, substring-before( /wwp:TEI/wwp:teiHeader/wwp:encodingDesc/wwp:listPrefixDef//wwp:prefixDef[ @ident eq $p ]/@replacementPattern, '#' ) )"/>
      <let name="KEYs" value="for $r in $REFs return substring-after( $r,':')"/>
      <let name="PLACEs" value="for $k in $KEYs return                                     if ( doc-available( $URLs[ index-of( $KEYs, $k )] ) )                                     then                                       if ( document( $URLs[ index-of( $KEYs, $k )] )//TEI:*[ @xml:id eq $k ] )                                       then                                         document( $URLs[ index-of( $KEYs, $k )] )//TEI:*[ @xml:id eq $k ]                                       else .                                     else ."/>
      <report test="count( $REFs ) eq 0">Empty @ref of &lt;placeName&gt;</report>
      <report test="count( $PLACEs[ not(                                     self::TEI:place ) ] ) gt 0">Each pointer in the @ref attribute of &lt;placeName&gt; should point to a &lt;place&gt;, but the pointers in this one ("<value-of select="$val"/>") point to: <value-of select="if ( not( $PLACEs ) )                           then 'nowhere'                           else for $p in $PLACEs return                             if ( $p is . )                             then ' nothing'                             else concat(' &lt;', name($p), '&gt;')"/>.</report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-sub-text-ID-matches-text-72">
    <rule context="/wwp:TEI/wwp:teiHeader/wwp:text//wwp:text">
      <let name="textID" value="normalize-space( /wwp:TEI/wwp:text/@xml:id )"/>
      <assert test="substring( normalize-space( @xml:id ), 1, 7 ) eq substring( $textID, 1, 7 )">sub-text TR# <value-of select="@xml:id"/> does not match main text TR# <value-of select="$textID"/>.</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-has_some_sort_of_content-73">
    <rule context="/*/wwp:text//*                                  except (                                     self::wwp:ref[ @type = ('correction','error') ]                                  | self::wwp:sic                                  | self::wwp:ab[ @type eq 'placeholder']                                  | self::wwp:addSpan                                  | self::wwp:alt                                  | self::wwp:altGrp                                  | self::wwp:anchor                                  | self::wwp:cb                                  | self::wwp:cell                                  | self::wwp:choice                                  | self::wwp:corr                                  | self::wwp:delSpan                                  | self::wwp:format                                  | self::wwp:g[ @ref ]                                  | self::wwp:gap                                  | self::wwp:lb                                  | self::wwp:link                                  | self::wwp:linkGrp                                  | self::wwp:milestone                                  | self::wwp:mw[ @type = ('border','border-rule','border-ornamental','unknown','other') ]                                  | self::wwp:pb                                  | self::wwp:ptr                                  | self::wwp:space                                  | self::wwp:substJoin                                  | self::wwp:transpose                                  | self::xi:include                                  )">
      <assert role="warning" test="   normalize-space(.) ne ''                                   or descendant-or-self::*/@copyOf                                   or descendant-or-self::*/@sameAs                                   or descendant::wwp:g                                   or descendant::wwp:gap                                   or descendant::wwp:anchor  (: see [1] below :)                                   or descendant::wwp:ab[ @type eq 'placeholder']                                   or descendant::wwp:ref[ @type = ('error','correction') ]                                   or descendant-or-self::wwp:anagram[ contains( normalize-space( @target ), ' ') ]                                   or child::comment()[matches( ., '\$\$\$') ]                                   or @wwp:affirmed                                  "> element requires some sort of representation of actual content from the source.</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-floating-text-ID-matches-text-74">
    <rule context="wwp:floatingText">
      <let name="textID" value="normalize-space( /wwp:TEI/wwp:text/@xml:id )"/>
      <assert test="substring( normalize-space( @xml:id ), 1, 7 ) eq substring( $textID, 1, 7 )">floatingText TR# <value-of select="@xml:id"/> does not match main text TR# <value-of select="$textID"/>.</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-something_in_div-24">
    <rule context="wwp:div[ @type eq 'epigraph'][ descendant::wwp:epigraph ]">
      <assert test="true()"/>
    </rule>
    <rule context="wwp:div[ not( @type eq 'epigraph') ]">
      <assert test="descendant::wwp:div or                                     descendant::wwp:l[ not( ancestor::wwp:epigraph )] or                                     descendant::wwp:ab[ not( ancestor::wwp:epigraph )] or                                     descendant::wwp:p[ not( ancestor::wwp:epigraph )] or                                     descendant::wwp:floatingText[ not( ancestor::wwp:epigraph )] or                                     descendant::wwp:lg[ not( ancestor::wwp:epigraph )] or                                     descendant::wwp:sp[ not( ancestor::wwp:epigraph )] or                                     descendant::wwp:bibl[ not( ancestor::wwp:epigraph )] or                                     descendant::wwp:biblFull or                                     descendant::wwp:biblStruct[ not( ancestor::wwp:epigraph )] or                                     descendant::wwp:list[ not( ancestor::wwp:epigraph )] or                                     descendant::wwp:listBibl[ not( ancestor::wwp:epigraph )] or                                     descendant::wwp:table[ not( ancestor::wwp:epigraph )] or                                     descendant::wwp:listEvent or                                     descendant::wwp:quote[ not( ancestor::wwp:epigraph )] or                                     descendant::wwp:stage[ not( ancestor::wwp:epigraph )] or                                     descendant::wwp:castList[ not( ancestor::wwp:epigraph )] or                                     descendant::wwp:gap[ not( ancestor::wwp:epigraph )] or                                     descendant::wwp:join or                                     descendant::wwp:joinGrp or                                     descendant::wwp:advertisement[ not( ancestor::wwp:epigraph )] or                                     descendant::wwp:note[ not( ancestor::wwp:epigraph )] or                                     descendant::wwp:figure[ not( ancestor::wwp:epigraph )] or                                     descendant::wwp:unknown[ not( ancestor::wwp:epigraph )] or                                     descendant::wwp:trailer or                                     descendant::wwp:elision[ not( ancestor::wwp:epigraph )]">&lt;<name/>&gt; with no significant content (i.e., none of: ab advertisement bibl biblFull biblStruct castList div elision figure floatingText gap join joinGrp l lg list listBibl listEvent note p quote sp stage trailer unknown)</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-contents_must_have_toc-77">
    <rule context="wwp:div[ @type eq 'contents']">
      <assert test=".//wwp:*[ @type eq 'toc']"> A division intended for a table of contents should have one (e.g., a &lt;list type="toc"&gt;).</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-abstractModel-structure-div-in-l-78">
    <rule context="wwp:l//wwp:div">
      <assert test="ancestor::wwp:floatingText"> Abstract model violation: Metrical lines may not contain higher-level structural elements such as div, unless div is a descendant of floatingText.</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-abstractModel-structure-div-in-ab-or-p-79">
    <rule context="wwp:div">
      <report test="(ancestor::wwp:p or ancestor::wwp:ab) and not(ancestor::wwp:floatingText)"> Abstract model violation: p and ab may not contain higher-level structural elements such as div, unless div is a descendant of floatingText.</report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-handwritten_addition_spans_must_have_hand_attr-80">
    <rule context="wwp:addSpan[ not( @hand )]">
      <assert test="@type = ('printed','stamped')"> A handwritten addition must have a @hand attribute</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-addSpan-requires-spanTo-81">
    <rule context="wwp:addSpan">
      <assert test="@spanTo">The @spanTo attribute of <name/> is required.</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-damageSpan-requires-spanTo-83">
    <rule context="wwp:damageSpan">
      <assert test="@spanTo">The @spanTo attribute of <name/> is required.</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-delSpan-requires-spanTo-85">
    <rule context="wwp:delSpan">
      <assert test="@spanTo">The @spanTo attribute of <name/> is required.</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-catchword_ufo_phrase_level-87">
    <rule context="wwp:mw[ @type eq 'catch'] |                                  wwp:rs[ @type eq 'ufo'  ]">
      <let name="me" value="if ( self::wwp:mw )                                           then 'a catchword'                                           else 'an unspecified feature used for organization'"/>
      <report test="  wwp:persName                                   | wwp:placeName                                   | wwp:name                                   | wwp:vuji                                   | wwp:choice                                   | wwp:mcr                                   | wwp:date                                   | wwp:regMe                                   | wwp:title                                   | wwp:orgName                                   | wwp:rs                                   | wwp:ref[ @type ne 'error' ]                                   | wwp:abbr                                   | wwp:emph                                   | wwp:term                                   | wwp:bibl"> Precise phrase-level encoding (persName, placeName, name, vuji, mcr, date, regMe, title, orgName, etc.) should not occur in <value-of select="$me"/>.</report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-catchword_delimiters_in_content-88">
    <rule context="wwp:mw[@type eq 'catch']">
      <report test="matches(@rend,'pre\([^#)]*\)')"> Generally speaking, delimters in a catchword are encoded as content, not on @rend.</report>
      <report test="matches(@rend,'post\([^#)]*\)')"> Generally speaking, delimters in a catchword are encoded as content, not on @rend.</report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-substContents1-89">
    <rule context="wwp:subst">
      <assert test="child::wwp:add and (child::wwp:del or child::wwp:surplus)"><name/> must have at least one child add and at least one child del or surplus</assert>
    </rule>
  </pattern>
  <pattern id="nest_me_part_not">
    <rule context="*[@part][.//@part]">
      <let name="myGI" value="name(.)"/>
      <let name="descendentGIs" value=".//*[@part]/name()"/>
      <report test="$myGI = $descendentGIs"> This <value-of select="$myGI"/> element has an @part, but also has a descendant <value-of select="$myGI"/> that has an @part. (This is not allowed, use @next &amp; @prev instead.)</report>
    </rule>
  </pattern>
  <pattern id="LessThan3InitialCharsDropped">
    <rule context="*[ matches( @rend,'class\s*\(#DIC\)') ]">
      <let name="len" value="if ( .//wwp:sic | .//wwp:corr )                                 then max((                                   string-length( string-join(.//wwp:sic/normalize-space(), '') ),                                   string-length(string-join( .//wwp:corr/normalize-space(), ''))                                   ))                                 else string-length( normalize-space(.) )"/>
      <assert test="$len lt 3"> A dropped initial capital is typically only 1 or at most 2 characters long; this one is <value-of select="$len"/> characters long.</assert>
    </rule>
  </pattern>
  <pattern id="concrete_rend_keyword_checker" is-a="abstract_rendition_keyword_checker">
    <param name="rendLadderContext" value="wwp:rendition"/>
  </pattern>
  <pattern id="concrete_rendition_keyword_checker" is-a="abstract_rendition_keyword_checker">
    <param name="rendLadderContext" value="wwp:*/@rend"/>
  </pattern>
  <pattern id="abstract_rendition_keyword_checker" abstract="true">
    <rule context="$rendLadderContext">
      <let name="me" value="normalize-space(.)"/>
      <let name="myself" value="replace( replace( $me, ' ?\) ?',')'), ' ?\( ?','(')"/>
      <let name="I" value="replace( replace( $myself,'\\\)','⸩'), '\\\(','⸨')"/>
      <let name="we" value="replace( $I,                                         'be(stow|queath)                                         \(                                           \(([a-z-]+\([^)]*\))+\)                                           \(([A-Za-z][A-Za-z0-9._-]*[ ]?)+\)                                         \)',                                         '','x')"/>
      <let name="us" value="tokenize( $we, '\([^)]*\)')"/>
      <assert test="every $ego in $us satisfies (                             $ego = ('align', 'bestow', 'border', 'braced', 'bracing', 'break', 'case', 'columns', 'face', 'fill', 'first-indent', 'indent', 'place', 'pos', 'post', 'pre', 'rotate', 'slant', 'space-above', 'sub', 'sup', 'underline', 'underscore')                             or                             $ego = ('', 'class', 'inverted', 'myAnchor', 'right-indent', 'rotate', 'rotate-y')                             )"> I parsed the <value-of select="if (self::wwp:rendition) then concat('content of &lt;rendition&gt; #', (@xml:id,count( preceding::wwp:rendition)+1)[1]) else concat('@rend of a &lt;', local-name(..),'&gt;' )"/>, "<value-of select="."/>", into the keywords "<value-of select="for $ego in ($us) return concat('{',$ego,'}')"/>", at least one of which is not a proper keyword.</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-TR_and_OT_nums-93">
    <rule context="wwp:teiHeader">
      <let name="hdr" value="substring-before( normalize-space( @xml:id ),'.hdr')"/>
      <let name="idno" value="normalize-space( wwp:fileDesc/wwp:publicationStmt/wwp:idno[@type eq 'WWP'] )"/>
      <let name="textID" value="normalize-space( ../wwp:text/@xml:id )"/>
      <let name="sourceDescs" value="/wwp:TEI/wwp:teiHeader/wwp:fileDesc/wwp:sourceDesc"/>
      <let name="sourceDesc" value="$sourceDescs[ not( @default eq 'false') ]"/>
      <let name="source" value="normalize-space( $sourceDesc/@n )"/>
      <assert test="matches( $hdr,   '^TR[0-9]{5}(\.[0-9]{2})?$')">TEI Header ID is not in correct format</assert>
      <assert test="matches( $idno,  '^TR[0-9]{5}(\.[0-9]{2})?$')">WWP idno is not in correct format</assert>
      <assert test="matches( $textID,'^TR[0-9]{5}(\.[0-9]{2})?$')"><att xmlns="http://www.tei-c.org/ns/1.0" xmlns:rng="http://relaxng.org/ns/structure/1.0" xmlns:sch="http://purl.oclc.org/dsdl/schematron" xmlns:sqf="http://www.schematron-quickfix.com/validator/process" xmlns:teix="http://www.tei-c.org/ns/Examples" xmlns:xi="http://www.w3.org/2001/XInclude">xml:id</att> of <gi xmlns="http://www.tei-c.org/ns/1.0" xmlns:rng="http://relaxng.org/ns/structure/1.0" xmlns:sch="http://purl.oclc.org/dsdl/schematron" xmlns:sqf="http://www.schematron-quickfix.com/validator/process" xmlns:teix="http://www.tei-c.org/ns/Examples" xmlns:xi="http://www.w3.org/2001/XInclude">text</gi> is not a proper TR number</assert>
      <assert test="matches( $source,'^OT[0-9]{5}(\.[0-9]{2})?$')"><att xmlns="http://www.tei-c.org/ns/1.0" xmlns:rng="http://relaxng.org/ns/structure/1.0" xmlns:sch="http://purl.oclc.org/dsdl/schematron" xmlns:sqf="http://www.schematron-quickfix.com/validator/process" xmlns:teix="http://www.tei-c.org/ns/Examples" xmlns:xi="http://www.w3.org/2001/XInclude">n</att> of <gi xmlns="http://www.tei-c.org/ns/1.0" xmlns:rng="http://relaxng.org/ns/structure/1.0" xmlns:sch="http://purl.oclc.org/dsdl/schematron" xmlns:sqf="http://www.schematron-quickfix.com/validator/process" xmlns:teix="http://www.tei-c.org/ns/Examples" xmlns:xi="http://www.w3.org/2001/XInclude">sourceDesc</gi> is not a proper OT number</assert>
      <assert test="$idno eq $textID                                 and                                 substring( $idno, 3 ) eq substring( $source, 3 )                                 and                                 $idno eq $hdr">TR and OT numbers do not all match.</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-filenames_match-94">
    <rule context="/*">
      <let name="training" value="contains( base-uri(/), '/training/' )"/>
      <let name="myfn" value="tokenize( base-uri(/),'/')[last()]"/>
      <let name="mybase" value="replace( $myfn, '\.x(m|inc)l$','')"/>
      <let name="URLidno" value="wwp:teiHeader/wwp:fileDesc/wwp:publicationStmt/wwp:idno[@type eq 'URL']"/>
      <let name="URLidnobase" value="substring-before( tokenize( $URLidno,'/')[last()],'.html')"/>
      <let name="svnIDnot" value="exists( /comment()[contains( ., concat('$','Id','$') ) ] )"/>
      <let name="SVN" value="tokenize( normalize-space( /comment()[contains( ., concat('$','Id',':') ) ] ), ' ')"/>
      <let name="SVNfn" value="$SVN[2]"/>
      <let name="SVNbase" value="substring-before( $SVNfn,'.xml')"/>
      <assert test="$URLidnobase eq $mybase">URL idno "<value-of select="$URLidnobase"/>" does not match filename "<value-of select="$mybase"/>"</assert>
      <report test="count( $SVN ) eq 0  and  not( $svnIDnot )">Subversion 'Id' keyword comment not found</report>
      <report test="count( $SVN ) eq 0  and  $svnIDnot">Subversion 'Id' keyword has not been substituted</report>
      <assert test="$training  or  matches( $URLidno,'^https?://www\.wwp\.northeastern\.edu/texts/[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.html$')">URL idno is not in correct format</assert>
      <assert test="$training  or  $SVNbase eq $mybase">Subversion 'Id' filename "<value-of select="$SVNbase"/>" does not match actual filename "<value-of select="$mybase"/>" (because myfn=<value-of select="$myfn"/>)</assert>
      <assert test="$training  or  $SVNbase eq $URLidnobase">Subversion 'Id' filename "<value-of select="$SVNbase"/>" does not match URL idno "<value-of select="$URLidnobase"/>"</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-corresp-not-point-to-self-95">
    <rule context="*[ @corresp ]">
      <let name="ptr2me" value="concat('#', @xml:id )"/>
      <report test="tokenize( normalize-space( @corresp ),' ') = $ptr2me">ERROR: the <value-of select="name()"/> element with id=<value-of select="@xml:id"/> corresponds to itself</report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-shyTests-96">
    <rule context="text()[contains(.,'­')]">
      <let name="len" value="43"/>
      <let name="me" value="normalize-space(.)"/>
      <let name="ellipsis" value="if (string-length($me) &gt; $len) then '…' else ''"/>
      <let name="snippet" value="concat( substring( $me, 1, $len), $ellipsis )"/>
      <report test="ancestor::wwp:teiHeader">“<value-of select="$snippet"/>”: shy in metadata!</report>
      <report test="matches(.,'­.*­')">“<value-of select="$snippet"/>”: two shy!</report>
      <assert test="matches(.,'­\s*$')">“<value-of select="$snippet"/>”: non-whitespace after shy!</assert>
      <assert test="following::text()">“<value-of select="$snippet"/>”: nothing follows shy!</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-one_ptr_iff_content-97">
    <rule context="anagram[normalize-space(.) eq '']">
      <let name="targets" value="tokenize( normalize-space( @target ),' ')"/>
      <assert test="count( $targets ) gt 1">An empty &lt;anagram&gt; element should point to 2 or more targets</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-one_ptr_iff_content-98">
    <rule context="anagram[normalize-space(.) ne '']">
      <let name="targets" value="tokenize( normalize-space( @target ),' ')"/>
      <assert test="count( $targets ) eq 1">An &lt;anagram&gt; element that contains an anagram should point to only 1 target</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-adds_in_adds_have_note-99">
    <rule context="wwp:adds/wwp:add/child::*">
      <assert test="self::wwp:note">An &lt;add&gt; inside &lt;adds&gt; inside the &lt;hyperDiv&gt; should not have any children other than &lt;note&gt; (and there is a &lt;<name/>&gt; here).</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-structural-catagorizations-of-body-100">
    <rule context="wwp:body[@type]">
      <assert test="@type = ('act',                                            'confession',                                            'dialogue',                                            'drama',                                            'dramaPart',                                            'essay',                                            'examination',                                            'letter',                                            'meditation',                                            'narrative',                                            'nonfictionProse',                                            'novel',                                            'novelPart',                                            'petition',                                            'poem',                                            'poemGroup',                                            'prayer',                                            'speech',                                            'tract',                                            'undetermined')">warning: the "<value-of select="@type"/>" value of @type is not intended to be used on &lt;body&gt;.</assert>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-type-of-div-required-101">
    <rule context="wwp:div[ not( @type ) ]">
      <report test="true()">divisions should be catagorized, but this one is not (i.e., @type is required, but is missing here)</report>
    </rule>
  </pattern>
  <pattern id="schematron-constraint-structural-catagorizations-of-div-102">
    <rule context="wwp:div">
      <assert test="@type = ('act',                                            'advert',                                            'argument',                                            'book',                                            'calendar',                                            'castlist',                                            'chapter',                                            'colophon',                                            'concluding',                                            'confession',                                            'contents',                                            'corrigenda',                                            'ded',                                            'dialogue',                                            'docAuthorization',                                            'drama',                                            'endnotes',                                            'entry',                                            'epigraph',                                            'epilogue',                                            'essay',                                            'examination',                                            'frontispiece',                                            'imprimatur',                                            'index',                                            'letter',                                            'meditation',                                            'narrative',                                            'part',                                            'petition',                                            'poem',                                            'poemGroup',                                            'prayer',                                            'prefatory',                                            'prologue',                                            'recipe',                                            'scene',                                            'section',                                            'speech',                                            'subsection',                                            'timeline',                                            'tract',                                            'undetermined',                                            'vignette')">warning: the "<value-of select="@type"/>" value of @type is not intended to be used on &lt;div&gt;.</assert>
    </rule>
  </pattern>
  <!-- *********************** -->
  <!-- schematron quick fixes: -->
  <!-- *********************** -->
  <sqf:fixes xmlns="http://www.tei-c.org/ns/1.0" xmlns:rng="http://relaxng.org/ns/structure/1.0" xmlns:sch="http://purl.oclc.org/dsdl/schematron" xmlns:sqf="http://www.schematron-quickfix.com/validator/process" xmlns:teix="http://www.tei-c.org/ns/Examples" xmlns:xi="http://www.w3.org/2001/XInclude">
    <sqf:fix id="notpreved">
      <sqf:description>
        <sqf:title>Point at me with a @prev</sqf:title>
        <sqf:p>Add a @prev that points to me to the element I point to with @next</sqf:p>
      </sqf:description>
      <sch:let name="next" value="id( substring(@next,2) )"/>
      <sch:let name="ptr2me" value="concat('#', @xml:id )"/>
      <sqf:add target="prev" node-type="attribute" match="$next" select="$ptr2me"/>
    </sqf:fix>
    <sqf:fix id="notnexted">
      <sqf:description>
        <sqf:title>Point at me with a @next</sqf:title>
        <sqf:p>Add a @next that points to me to the element I point to with @prev</sqf:p>
      </sqf:description>
      <sch:let name="prev" value="id( substring(@prev,2) )"/>
      <sch:let name="ptr2me" value="concat('#', @xml:id )"/>
      <sqf:add target="next" node-type="attribute" match="$prev" select="$ptr2me"/>
    </sqf:fix>
    <sqf:fix id="nextless">
      <sqf:description>
        <sqf:title>Add missing @next</sqf:title>
        <sqf:p>For an element that is pointed to by a @prev but does not have an @next, add the @next</sqf:p>
      </sqf:description>
      <sch:let name="myID" value="@xml:id"/>
      <sqf:add node-type="attribute" target="next" select="concat('#',//*[@prev/normalize-space(.) eq concat('#',$myID)][1]/@xml:id)"/>
    </sqf:fix>
    <sqf:fix id="prevless">
      <sqf:description>
        <sqf:title>Add missing @prev</sqf:title>
        <sqf:p>For an element that is pointed to by a @next but does not have an @prev, add the @prev</sqf:p>
      </sqf:description>
      <sch:let name="myID" value="@xml:id"/>
      <sqf:add node-type="attribute" target="prev" select="concat('#',//*[@next/normalize-space(.) eq concat('#',$myID)][1]/@xml:id)"/>
    </sqf:fix>
  </sqf:fixes>
</schema>
