Search code examples
xmlxsltxslt-2.0tei

XSL for-each on space-separated attribute values


for my research project, I have this document in XML/TEI

<TEI xmlns="http://www.tei-c.org/ns/1.0" >
<body>
    <div>
        <p>
            <span target="#" type="passage" ana="Tag957 Tag874">
                <span target="#" ana=""/>
            </span>
            <seg><date when="1980-01-01" type="date_seg"/>blabla blabla
                 blabla blablablabla blablablabla blablablabla blablablabla bl
            </seg>
            <span target="#" type="passage" ana="Tag1657 ">
                <span target="#" ana=""/>
            </span>
            <seg><date from="1980-01-03" to="1980-01-05" type="date_seg"/>blabla
            </seg>
        </p>
    </div>
</body>
</TEI>

I need to extract for each Tag contained in span/@ana : the date and the string length of the following node seg. With the condition that if we incounter the date attribute @from or @to, I just need the value of the @from. What I need would look like that :

Tag957;1980-01-01;88
Tag874;1980-01-01;88
Tag1657;1980-01-03;11

I tried this, but I don't know how to express that for-each is applyed to one attribute's value at a time

<xsl:template match="tei:p">
        <xsl:for-each select="tei:span">
                <xsl:value-of select="./@ana"/>
                <xsl:text>;</xsl:text>
            <xsl:if test="following-sibling::tei:seg/tei:date/@from or following-sibling::tei:seg/tei:date/@to">
                <xsl:value-of select="following-sibling::tei:seg/tei:date/@from"/>
            </xsl:if>
            <xsl:if test="following-sibling::tei:seg/tei:date/@when">
                <xsl:value-of select="following-sibling::tei:seg/tei:date/@when"/>
            </xsl:if>
                <xsl:text>;</xsl:text>
                <xsl:value-of select="string-length(following-sibling::tei:seg)"/>
                <xsl:text>;</xsl:text>
                <xsl:value-of select="$newLine"/>
        </xsl:for-each>
</xsl:template>

Solution

  • Using XSLT 2.0 you can use tokenize to identify the different values in the attribute value, then you can rewrite your code as

    <xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0" xpath-default-namespace="http://www.tei-c.org/ns/1.0">
        <xsl:template match="p">
            <xsl:for-each select="span">
                <xsl:variable name="span" select="."/>
                <xsl:for-each select="tokenize(@ana, '\s+')[normalize-space()]">
                  <xsl:value-of select="."/>
                  <xsl:text>;</xsl:text>
                  <xsl:if test="$span/following-sibling::seg[1]/date/@from or $span/following-sibling::seg[1]/date/@to">
                    <xsl:value-of select="$span/following-sibling::seg[1]/date/@from"/>
                  </xsl:if>
                  <xsl:if test="$span/following-sibling::seg/date/@when">
                    <xsl:value-of select="$span/following-sibling::seg/date/@when"/>
                  </xsl:if>
                  <xsl:text>;</xsl:text>
                  <xsl:value-of select="string-length($span/following-sibling::seg[1])"/>
                  <xsl:text>;</xsl:text>
                  <xsl:value-of select="'&#10;'"/>
                </xsl:for-each>    
            </xsl:for-each>
        </xsl:template>
    </xsl:transform>
    

    Online at http://xsltransform.net/jz1PuPL.