0

Following this post Compare variable in preceding-sibling with current node, I tried to compare current node in order to remove duplicate occurrences.

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE stylesheet [
 <!ENTITY menu SYSTEM "verb.xml">   
]>    

<xsl:variable name="gram" as="xs:string*" select="*//gramGrp/string-join((iType/@value, mood/@value, tns/@value, subc/@value), '. ')"/>
<xsl:variable name="actor-affixes" as="xs:string*" select="*//gramGrp/string-join((per/@value, gen/@value, number/@value), '')"/>

<xsl:for-each select="w[@n | @lemma]">

  <ul>
    <li><xsl:variable name="inflected">
       <xsl:for-each select="*/m[@type='pref']"> 
         <xsl:value-of select="current()"/>
           <xsl:choose>
             <xsl:when test="."><xsl:text>-</xsl:text></xsl:when>
             <xsl:otherwise/>
           </xsl:choose>
        </xsl:for-each> 

        <xsl:for-each select="*//m[@type='baseForm']"> 
          <xsl:variable name="str1">
            <xsl:value-of select="current()[not != c[@type['infix']]] |node()"/>
          </xsl:variable>
          <xsl:value-of select="translate(normalize-space($str1), ' ', '-')"/>  
        </xsl:for-each>

        <xsl:for-each select="*//m[@type='suff']">
            <xsl:variable name="str2">
              <xsl:if test="position() = last()"><xsl:text>-</xsl:text><xsl:value-of select="."/></xsl:if>
            </xsl:variable>
            <xsl:value-of select="concat($str2, '')"/>  
        </xsl:for-each>

        </xsl:variable>
        <xsl:value-of select="$inflected"/>

        <xsl:text>: </xsl:text>

        <xsl:variable name="gram-affixes">            
          <xsl:if test="$gram = preceding-sibling::node()/$gram">
            <xsl:value-of select="$gram"/>
          </xsl:if>
          <xsl:text>.</xsl:text>
          <xsl:value-of select="$actor-affixes" separator=", "/><xsl:text>.</xsl:text>
        </xsl:variable>
        <xsl:value-of select="$gram-affixes"/>
     </li>
  </ul>
</xsl:for-each>

Content from TEI-XML

<w n="1" lemma="tmtḫṣ" xml:id="tmtḫṣ" ana="#mḫṣ">
  <m type="base">
    <m type="pref" ana="#pref-t">t</m>
    <m type="baseForm">m<c type="infix" ana="#infix-t">t</c>ḫṣ</m>
  </m>               
</w>
<w n="2" lemma="tmḫṣ" xml:id="tmḫṣ" ana="#mḫṣ">
   <m type="base">
     <m type="pref" ana="#pref-t">t</m>
     <m type="baseForm">mḫṣ</m>
   </m>
</w>
<gramGrp type="baseForm" ana="#mḫṣ">
   <gramGrp n="1" ana="#tmtḫṣ">
     <iType ana="#sstem.Gt" value="Gt" type="semantic-variations"/>
     <mood ana="#mood.ind" value="ind"/>
     <tns ana="#sasp.imperf" value="imperf"/>
     <subc ana="#strans" value="trans"/>
     <gramGrp n="1.1" ana="#actor-affixes">
        <per ana="#s2" value="2"/>
        <gen ana="#smasc" value="m"/>
        <number ana="#ssing" value="sg"/>
     </gramGrp>
     <gramGrp n="1.2" ana="#actor-affixes">
        <per ana="#s3" value="3"/>
        <gen ana="#sfem" value="f"/>
        <number ana="#ssing" value="sg"/>
     </gramGrp>
    </gramGrp>
  <gramGrp n="2" ana="#tmḫṣ">
     <iType ana="#sstem.D" value="D" type="semantic-variations"/>
     <mood ana="#mood.ind" value="ind"/>
     <tns ana="#sasp.perf" value="perf"/>
     <subc ana="#strans" value="trans"/>
     <gramGrp n="1.1" ana="#actor-affixes">
        <per ana="#s2" value="2"/>
        <gen ana="#smasc" value="m"/>
        <number ana="#ssing" value="sg"/>
     </gramGrp>
     <gramGrp n="1.2" ana="#actor-affixes">
       <per ana="#s3" value="3"/>
       <gen ana="#sfem" value="f"/>
       <number ana="#ssing" value="sg"/>
      </gramGrp>
    </gramGrp>
</gramGrp>

I have also tried: <xsl:for-each select="distinct-values($gram)"><xsl:value-of select="normalize-space(.)"/></xsl:for-each> (follwing Compare variable in preceding-sibling with current node) and <xsl:for-each select="$gram[not(. = preceding-sibling::node()/$gram)]"><xsl:value-of select="$gram"/></xsl:for-each>. But it doesn't work...

The current output is:

<ul><li>t-m-t-ḫṣ: Gt. ind. imperf. transD. ind. perf. trans., 2msg, 3fsg, , 2msg, 3fsg.</li></ul>
<ul><li>t-mḫṣ: Gt. ind. imperf. transD. ind. perf. trans., 2msg, 3fsg, , 2msg, 3fsg.</li></ul>

But as you can see, occurrences following ':' are the same. It should be:

<ul><li>t-m-t-ḫṣ: Gt. ind. imperf. trans., 2msg, 3fsg.</li></ul>
<ul><li>t-mḫṣ: D. ind. perf. trans., 2msg, 3fsg.</li></ul>

UPDATE:

According to advice, I have updated a new version in order to include all TEI element. It's working fine. But I have added in comment <!-- --> additional problem. I think I still don't understand how key is working. I don't know if I need to add a new post -- if yes, apologize please -- : can you explain how key is working?

TEI:

<entryFree n="6" xml:id="mḫṣ">
  <form type="verb">
    <orth>mḫṣ</orth>
  </form>
  <form type="inflected">
    <w n="1" lemma="tmtḫṣ" xml:id="tmtḫṣ" ana="#mḫṣ">
       <m type="base">
         <m type="pref" ana="#pref-t">t</m>
         <m type="baseForm">m<c type="infix" ana="#infix-t">t</c>ḫṣ</m>
       </m> 
    </w>
    <w n="2" lemma="tmḫṣ" xml:id="tmḫṣ" ana="#mḫṣ">
        <m type="base">
          <m type="pref" ana="#pref-t">t</m>
          <m type="baseForm">mḫṣ</m>
        </m>
    </w>
    <gramGrp type="baseForm" ana="#mḫṣ">
      <gramGrp n="1" ana="#tmtḫṣ">
        <iType ana="#sstem.Gt" value="Gt" type="semantic-variations"/>
        <mood ana="#mood.ind" value="ind"/>
        <tns ana="#sasp.imperf" value="imperf"/>
        <subc ana="#strans" value="trans"/>
        <gramGrp n="1.1" ana="#actor-affixes">
           <per ana="#s2" value="2"/>
           <gen ana="#smasc" value="m"/>
           <number ana="#ssing" value="sg"/>
        </gramGrp>
        <gramGrp n="1.2" ana="#actor-affixes">
           <per ana="#s3" value="3"/>
           <gen ana="#sfem" value="f"/>
           <number ana="#ssing" value="sg"/>
        </gramGrp>
       </gramGrp>
       <gramGrp n="2" ana="#tmḫṣ">
         <iType ana="#sstem.D" value="D" type="semantic-variations"/>
         <mood ana="#mood.ind" value="ind"/>
         <tns ana="#sasp.perf" value="perf"/>
         <subc ana="#strans" value="trans"/>
         <gramGrp n="1.1" ana="#actor-affixes">
           <per ana="#s2" value="2"/>
           <gen ana="#smasc" value="m"/>
           <number ana="#ssing" value="sg"/>
         </gramGrp>
         <gramGrp n="1.2" ana="#actor-affixes">
           <per ana="#s3" value="3"/>
           <gen ana="#sfem" value="f"/>
           <number ana="#ssing" value="sg"/>
         </gramGrp>
        </gramGrp>
       </gramGrp>
      </form>
      <sense n="1" ana="#mḫṣ" xml:id="mḥṣ01">to fight</sense>
      <sense n="2" ana="#mḥṣ" xml:id="mḥṣ02">to destroy</sense>
       <re n="1" ana="#tmtḫṣ #mḫṣ01" type="inflected" >
        <sense>She fought <span>iterative function // with <ref
                    target="../computation/corpus_ilimilku.xml#ktu1-3_ii_l6b_tḫtṣb">tḫtṣb</ref></span>
           <span type="interp"><ref target="../computation/corpus_ilimilku.xml#ktu1-3_ii_l5b_6a_int">Hermeneutics</ref></span>
           <span ana="../computation/corpus_ilimilku.xml#contend"><reftarget="../computation/corpus_ilimilku.xml#mḫṣ01">Taxonomy, subcategory ofcompetition verb: contend</ref></span>
        </sense>
       </re>
       <re n="2" ana="#tmḫṣ #mḫṣ02" type="inflected">
         <sense>She destroyed <span type="interp"><ref target="../computation/corpus_ilimilku.xml#ktu1-3_ii_l7_int">Hermeneutics</ref></span>
            <span ana="../computation/corpus_ilimilku.xml#humiliation"><ref target="../computation/corpus_ilimilku.xml#mḫṣ02">Taxonomy, subcategory of emotion's verb as a concept of: humiliation</ref></span>
         </sense>
        </re>
      </entryFree>

XSL updated:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
xmlns:map="http://www.w3.org/2005/xpath-functions/map"
xmlns:array="http://www.w3.org/2005/xpath-functions/array"
exclude-result-prefixes="xs math map array" version="3.0">

<xsl:output method="html" encoding="utf-8" doctype system="about:legacy-compat"/>

<xsl:mode on-no-match="shallow-copy"/>
<xsl:key name="gramGrp" match="gramGrp[@n and @ana]" composite="yes" use="@n, substring(@ana, 2)"/>
<!-- <xsl:key name="re" match="re[@n and @ana[1]]" composite="yes" use="@n, substring(@ana, 2)" /> -->



<xsl:template match="entryFree">
     <xsl:variable name="orth" select="*/orth/text()" />
           <h3><xsl:value-of select="$orth"/></h3>
            <xsl:text>&#10; Mean.: </xsl:text><xsl:value-of select="*//following-sibling::sense[@xml:id]" separator=", " /><xsl:text>.</xsl:text>
            <ul><xsl:for-each select="*/w[@n | @lemma]">

                <xsl:variable name="pref" as="xs:string*" select="string-join(m[@type = 'base']/m, '')"/>
                <xsl:variable name="referenced-gramGrp" select="key('gramGrp', (@n, @lemma))"/>
                <xsl:variable name="gram" as="xs:string*" select="$referenced-gramGrp/string-join((iType/@value, mood/@value, tns/@value, subc/@value), '. ')"/>
                <xsl:variable name="actor-affixes" as="xs:string*" select="$referenced-gramGrp/gramGrp/string-join((per/@value, gen/@value, number/@value), '')"/>
                <!-- <xsl:variable name="referenced-re" select="key('re', (ancestor-or-self::w/@xml:id))" />
                <xsl:variable name="trans" as="xs:string*" select="$referenced-re/string-join(following::re/sense, '')"/> -->


                <li>
                    <xsl:value-of select="$pref"/>
                    <xsl:text>: </xsl:text>
                    <xsl:value-of select="$gram, $actor-affixes" separator=", "/>
                    <xsl:text>. </xsl:text>Trans.
                    <!-- <xsl:value-of select="$trans" separator=". "/> --> 

                </li>

            </xsl:for-each></ul>


 </xsl:template>

 <xsl:template match="gramGrp"/>
 <!-- <xsl:template match="re"/> -->

</xsl:stylesheet>

Output:

 <h3>mḫṣ</h3>
 Mean.: to fight, to destroy.
 <ul>
  <li>tmtḫṣ: Gt. ind. imperf. trans, 2msg, 3fsg. Trans.
  <!-- '$trans'-->
  </li>
  <li>tmḫṣ: D. ind. perf. trans, 2msg, 3fsg. Trans.
  <!-- $trans' -->
  </li>
 </ul>

Unfortunately, there is no output for $trans. What do I get wrong? The updated version can be found here: http://xsltfiddle.liberty-development.net/3Nqn5Y4

In advance, thanks for your kind support to a xsl newbie.

Vanessa
  • 121
  • 12

2 Answers2

1

There are two ways of answering a question like this: (a) pointing out what's wrong with your code, and (b) providing a working solution. I'm going to do (a); perhaps someone else will do (b).

There's some pretty dreadful code here. Let's start with the critical area:

      <xsl:if test="$gram = preceding-sibling::node()/$gram">
        <xsl:value-of select="$gram"/>
      </xsl:if>

Using a variable reference on the right-hand side of "/" really makes no sense. In fact, using any expression whose value doesn't depend on the context item makes no sense. X/$gram gives you a sequence containing N occurrences of $gram (where N is the size of X), and since all of these will be equal to $gram, your condition will always be true. I have no idea what this code was trying to achieve.

There are other things here that make little sense.

   <xsl:choose>
     <xsl:when test="."><xsl:text>-</xsl:text></xsl:when>
     <xsl:otherwise/>
   </xsl:choose>

Since "." is a node, its effective boolean value is always true, so this code is equivalent to

<xsl:text>-</xsl:text>

Now:

<xsl:variable name="str1">
      <xsl:value-of select="
          current()[not != c[@type['infix']]] |node()"/>
</xsl:variable>
<xsl:value-of select="
         translate(normalize-space($str1), ' ', '-')"/>

Firstly, the construct

<xsl:variable name="V"><xsl:value-of select="X"/></xsl:variable>

should nearly always be rewritten as

<xsl:variable name="V" select="X"/>

Secondly, the keyword "not" here means "child::not" - it's looking for an element named "not". Is that what was intended?

Finally, current() is an m element, and m elements in the source have a single text node child. Taking the union of an element (subject to conditions) and its text node child, and then forming the string value of the result, seems a very strange operation and it's hard to imagine what it is trying to achieve.

Michael Kay
  • 156,231
  • 11
  • 92
  • 164
  • Thanks @michael-kay for having pointing out all my mistakes. I will look to it, especially this solution ``. I will update correct solution as soon as possible — I hope!! – Vanessa Dec 23 '17 at 13:18
1

I think you want to move the variables into a template or for-each with the right context node and you want to reference the grammar section with a key, here is an XSLT 3 stylesheet (can be run with Saxon 9.8 any edition or earlier PE or EE releases and Altova 2017 or 2018) trying to do that:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:math="http://www.w3.org/2005/xpath-functions/math"
    xmlns:map="http://www.w3.org/2005/xpath-functions/map"
    xmlns:array="http://www.w3.org/2005/xpath-functions/array"
    exclude-result-prefixes="xs math map array"
    version="3.0">

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:key name="gramGrp" match="gramGrp[@n and @ana]" composite="yes" use="@n, substring(@ana, 2)"/>

  <xsl:template match="w[@n | @lemma]">
      <ul>
          <xsl:variable name="pref" as="xs:string" select="string-join(m[@type = 'base']/m, '')"/>
          <xsl:variable name="referenced-gramGrp" select="key('gramGrp', (@n, @lemma))"/>
          <xsl:variable name="gram" as="xs:string*" select="$referenced-gramGrp/string-join((iType/@value, mood/@value, tns/@value, subc/@value), '. ')"/>
          <xsl:variable name="actor-affixes" as="xs:string*" select="$referenced-gramGrp/gramGrp/string-join((per/@value, gen/@value, number/@value), '')"/>
          <li>
              <xsl:value-of select="$pref" separator="-"/>
              <xsl:text>: </xsl:text>
              <xsl:value-of select="$gram, $actor-affixes" separator=", "/>
          </li>

      </ul>
  </xsl:template>

  <xsl:template match="gramGrp"/>

</xsl:stylesheet>

At http://xsltfiddle.liberty-development.net/jyyiVhf you can see that the result is

<root>
    <ul><li>tmtḫṣ: Gt. ind. imperf. trans, 2msg, 3fsg</li></ul>
<ul><li>tmḫṣ: D. ind. perf. trans, 2msg, 3fsg</li></ul>

</root>

you will need to add your code breaking up the strings like tmtḫṣ into components as I have not been able to figure out how that works.

As for the edited problem with the other key, it is not clear which value(s) you want to select to form the key as the re elements in the ana attribute have a list of ids. Assuming you only want to use the first id as the key value you can use

   <xsl:key name="re" match="re[@n and @ana]" composite="yes" use="@n, tokenize(@ana, '\s+')[1]!substring(., 2)" />

and then

<xsl:variable name="referenced-re" select="key('re', (@n, @xml:id))" />

should find a re element for your sample data.

Martin Honnen
  • 160,499
  • 6
  • 90
  • 110
  • Thank you so much @martin-honnen. Well I have to reframe all my file since it was just a section. I will look to it. Currently, I have changed the version 2.0 to 3.0 and added `xmlns` `map`, `math`, `array`. A question related to ``: (1) The composite is not implemented yet. How do I process? (2) `substring(@ana, 2)`, I can have many other `@ana` since it was just an example, so I replace the value `2` by `*`. Correct? Thanks again! – Vanessa Dec 23 '17 at 12:47
  • Regarding my second question, I just understood who it works. So `substring(@ana, 2)` is right, no matter how much gramGrp I have. Thanks. I'm still trying to understand `composite`. – Vanessa Dec 23 '17 at 13:05
  • I have updated the last version of Oxygen. So no more composite problem when I run with Saxon-PE 9.7.0.19. – Vanessa Dec 23 '17 at 13:36
  • 1
    A composite key consists in a sequence of values to identify a node, in this case the `gramGrp` elements are identified by the `n` attribute value and the substring of the `ana` attribute starting with the second letter, that is, stripping of the leading hash `#` symbol, as the elements `w` in the `lemma` attribute use the value without a hash. HTH – Martin Honnen Dec 23 '17 at 15:03
  • I have updated the post. I think I didn't understand how `key` is working. I have added a new `key`, `variable`. But something is wrong again. Your explanation for `composite` was very good. Thank you. – Vanessa Dec 24 '17 at 15:49
  • 1
    @Vanessa, I have added two snippets to define the key and use it which for your sample select some data then: http://xsltfiddle.liberty-development.net/3Nqn5Y4/1. Not sure if you really wanted the `following` elements so I have only selected the child `sense` but you can change that back to the following if needed. – Martin Honnen Dec 24 '17 at 17:11
  • Thank you very much @Martin! What I understood for `tokenize(@ana, '\s+')[1]!substring(., 2)"`: display content of `@ana[1]` after `#`symbol. But why do I need to use regex expression `\s+` which means more than one whitespace character, right? – Vanessa Dec 25 '17 at 15:36
  • 1
    With `ana="#tmtḫṣ #mḫṣ01"` I assumed the value to be a list of `#id`s separated by white space so with `tokenize('#tmtḫṣ #mḫṣ01', '\s+')` we get a sequence of id strings e.g. `('#tmtḫṣ', '#mḫṣ01')`, the predicate `[1]` takes the first id string and the `substring` strips off the leading hash sign. There might be other ways but I ended up doing it this way after some struggle to identify whether all those id values or only the first should be part of the composite key. I finally decided to use only the first id for the key as I couldn't relate the other value. – Martin Honnen Dec 25 '17 at 16:31
  • Thank you so much for this explanation @Martin. It is now very clear. – Vanessa Dec 25 '17 at 16:39