xmlxslttei

how to use following-sibling correctly


I have an XML that sort of looks like this:

<desc year="1879">
      <date from="1879-08-30" to="1879-08-30"/> 
            <placeName>New York</placeName> 
            <placeName>New Jersey</placeName>
            <note>visiting my grandma</note>
      <date from="1879-10-30" to="1879-11-01"/> 
            <placeName>Berlin</placeName> 
            <note>with my mother</note>
            <placeName>Hamburg</placeName>
</desc>

I want to transfer the desc Elements to event Elements for each placeName. This works out, but either every note is transferred to every event and not just the one from placeName before it or no note elements at all.

This is my current code:

    <xsl:template match="//tei:desc">
     <xsl:variable name="note-content">
                <xsl:for-each select="//tei:placeName">
                    <xsl:if test="following-sibling::tei:note[1]">
                        <xsl:element name="note" namespace="http://www.tei-c.org/ns/1.0">
                            <xsl:value-of select="following-sibling::tei:note[1]"/>
                        </xsl:element>
                    </xsl:if>
                </xsl:for-each>
            </xsl:variable>
<xsl:for-each-group select="*" group-starting-with="tei:date">
      <!-- other specifications -->

      <xsl:for-each select="current-group()[name()='placeName']">
               <xsl:element name="event" namespace="http://www.tei-c.org/ns/1.0">
                 <!-- other specifications -->

                   <xsl:element name="desc" namespace="http://www.tei-c.org/ns/1.0">
                   <xsl:element name="placeName" namespace="http://www.tei-c.org/ns/1.0">
                           <xsl:attribute name="ref"/>
                           <xsl:value-of select="."/>
                   </xsl:element>
                   </xsl:element>
                   <xsl:if test="$note-content !=''">
                       <xsl:element name="note" namespace="http://www.tei-c.org/ns/1.0">
                           <xsl:value-of select="$note-content"/>
                       </xsl:element>
                   </xsl:if>
               </xsl:element>
            </xsl:for-each>
        </xsl:for-each-group>
    </xsl:template>

Solution

  • I'm not 100% sure I know exactly what output you want (it is generally a good idea to show your desired output rather than relying on a description of what you're trying to do), but it looks like you want to group the desc child elements starting with each date, and within that group you want to create a distinct event for every placeName which would then contain the placeName and also the note? Possibly also the date?

    Anyway, I hope this suggestion gets you closer to what you want:

    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
      xmlns:tei="http://www.tei-c.org/ns/1.0"
      xpath-default-namespace="http://www.tei-c.org/ns/1.0">
    
      <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
      
        <!-- this template is just to provide a root element for the example outut -->
        <xsl:template match="/">
          <xsl:element name="listEvent" namespace="http://www.tei-c.org/ns/1.0">
            <xsl:apply-templates/>
          </xsl:element>
        </xsl:template>
    
        <xsl:template match="desc">
          <xsl:for-each-group select="*" group-starting-with="date">
            <xsl:for-each select="current-group()[self::placeName]">
              <xsl:element name="event" namespace="http://www.tei-c.org/ns/1.0">
                <xsl:element name="desc" namespace="http://www.tei-c.org/ns/1.0">
                  <!-- copy everything except notes and placeNames -->
                  <xsl:copy-of select="current-group()[not(self::note | self::placeName)]"/>
                  <!-- copy the current placeName -->
                  <xsl:copy-of select="."/>
                </xsl:element>
                <!-- finally copy the note(s) -->
                <xsl:copy-of select="current-group()[self::note]"/>
              </xsl:element>
            </xsl:for-each>
          </xsl:for-each-group>
        </xsl:template>
        
    </xsl:stylesheet>
    
    

    Result:

    <listEvent xmlns="http://www.tei-c.org/ns/1.0">
       <event>
          <desc>
             <date from="1879-08-30" to="1879-08-30"/>
             <placeName>New York</placeName>
          </desc>
          <note>visiting my grandma</note>
       </event>
       <event>
          <desc>
             <date from="1879-08-30" to="1879-08-30"/>
             <placeName>New Jersey</placeName>
          </desc>
          <note>visiting my grandma</note>
       </event>
       <event>
          <desc>
             <date from="1879-10-30" to="1879-11-01"/>
             <placeName>Berlin</placeName>
          </desc>
          <note>with my mother</note>
       </event>
       <event>
          <desc>
             <date from="1879-10-30" to="1879-11-01"/>
             <placeName>Hamburg</placeName>
          </desc>
          <note>with my mother</note>
       </event>
    </listEvent>