<xsl:stylesheet xmlns:attr="http://www.xstandoff.net/2009/functions/attr" xmlns:bool="http://www.xstandoff.net/2009/functions/bool" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:doc="http://www.xstandoff.net/2009/functions/doc" xmlns:double="http://www.xstandoff.net/2009/functions/double" xmlns:all="http://www.xstandoff.net/2009/all" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xd="http://www.pnp-software.com/XSLTdoc" xmlns:xsf="http://www.xstandoff.net/2009/xstandoff/1.1" xmlns:string="http://www.xstandoff.net/2009/functions/string" xmlns:undef="http://www.xstandoff.net/2009/functions/undef" xmlns:elem="http://www.xstandoff.net/2009/functions/elem" version="2.0" exclude-result-prefixes="string undef elem attr bool double doc xs all xsf xd">

   

   

    
<!-- ############ STYLESHEET DOCUMENTATION ##########-->

    
            <xd:doc type="stylesheet">

        
<xd:author>Daniel Jettka; daniel.jettka@uni-bielefeld.de; Project Sekimo (A2), DFG Research Group 437</xd:author>

        
<xd:copyright>GNU Lesser General Public License, see below for details</xd:copyright>

        
<xd:short><p><b>extractXSFcontent.xsl - removing levels or layers (+segments) from an XSF instance</b></p></xd:short>

        
<xd:detail>

            
<p><b>Version 18.02.2011, 17:41 (GMT)</b></p>

            
<p>This program is free software: you can redistribute it and/or modify it under the terms of the GNU GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.</p>

            
<p>This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU GNU Lesser General Public License for more details.</p>

            
<p>You should have received a copy of the GNU GNU Lesser General Public License along with this program (file 'lgpl-3.0.txt').  If not, see <a href="http://www.gnu.org/licenses/">http://www.gnu.org/licenses/</a>.</p>

            
<p>Making it simple to delete or extract parts of the XStandoff annotation the stylesheet extractXSFcontent.xsl can be applied to an XStandoff file.

                During the transformation call one has to name the ID of the element (xsf:annotation, xsf:level or xsf:layer) to be deleted or extracted in the form 

                of the value of the corresponding parameter remove-ID or extract-ID. The matching element is removed/extracted from the XStandoff file and the list of segments is 

                updated, i.e. the segments which solely were referenced by descendant elements of the mentioned element are excluded. This, 

                admittedly, again leads to a reorganzation of the segments since these by default get a continuous numbering.
</p>

            
<p>Similar to the usage of the mergeXSF.xsl stylesheet the reorganization of the segments can be disabled by the stylesheet parameter 

                keep-segments. The value '1' lets the stylesheet keep the old segments, but without those only referenced by descendant elements 

                of the deleted element.
</p>

            
<p><b>Input XML file:</b> XSF instance</p>

            
<p><b>Stylesheet parameters:</b>

                
<ul>

                    
<li>remove-ID (xs:string) - ID of the element (&lt;xsf:annotation&gt;, &lt;xsf:level&gt; or &lt;xsf:layer&gt;) to be removed (with descendants)</li>

                    
<li>extract-ID (xs:string) - ID of the element (&lt;xsf:annotation&gt;, &lt;xsf:level&gt; or &lt;xsf:layer&gt;) to be extracted and returned in a new XStandoff instance</li>

                    
<li>keep-segments (xs:boolean) - determines if segments and corresponding IDs are to be kept or reorganized (default: false - reorganization)</li>

                
</ul>

            
</p>

            
<p><b>Execution via command line (XSLT processor Saxon9):</b> java -jar saxon9.jar [optional Saxon Parameters] -o [XSF output filename] [XSF input filename] extractXSFcontent.xsl [extract-ID | remove-ID]=[id of level/layer] [optional Stylesheet Parameters]</p>

        
</xd:detail>

    
</xd:doc>


    

    

    
<xsl:output indent="yes" method="xml" encoding="UTF-8" />

    

    
<!--#####Stylesheet-Parameters#####-->

    
            <xd:doc type="xs:string?"><xd:short><p>ID of the level or layer to be removed</p></xd:short></xd:doc>


    
<xsl:param name="remove-ID" as="xs:string?" required="no" />

    

    
            <xd:doc type="xs:boolean"><xd:short><p>ID of the level or layer to be extracted</p></xd:short></xd:doc>


    
<xsl:param name="extract-ID" as="xs:string?" required="no" />

    

    
            <xd:doc type="xs:boolean"><xd:short><p>Should segments and corresponding IDs be kept or reorganized? Default value is false</p></xd:short></xd:doc>


    
<xsl:param name="keep-segments" as="xs:boolean" select="false()" />

    

    
            <xd:doc type="xs:boolean"><xd:short><p>Should removed layer/level be output in additional new XSF instance? Default is false</p></xd:short></xd:doc>


    
<xsl:param name="return-removed" as="xs:boolean" select="false()" />

    
<!--##########################-->

    

    

    
<!--#####Keys#####-->

    
            <xd:doc><xd:short><p>Find elements by their segment reference @xsf:segment</p></xd:short></xd:doc>


    
<xsl:key name="elem-by-segRef" match="*" use="@xsf:segment" />

    

    
            <xd:doc><xd:short><p>Find &lt;xsf:segement&gt; by the value of their attribute @xml:id</p></xd:short></xd:doc>


    
<xsl:key name="seg-by-ID" match="xsf:segment" use="@xml:id" />

    
<!--##############-->

    

    

    
<!--#####Global Variables#####-->

    
            <xd:doc><xd:short><p>Root node for referencing.</p></xd:short></xd:doc>


    
<xsl:variable name="root" select="/" />

    

    
            <xd:doc><xd:short><p>Storing element which is to be deleted from the annotation.</p></xd:short></xd:doc>


    
<xsl:variable name="elem-by-id-in-stylesheet-param" select="//*[@xml:id=($remove-ID, $extract-ID)]" as="element()?" />

    

    
            <xd:doc><xd:short><p>Storing the sequence of segments which shall be transferred to the new segment list.</p></xd:short></xd:doc>


    
<xsl:variable name="newSegments">

        
<xsl:copy-of select="elem:sort-segments( elem:copy-segments-with-new-ID(//xsf:segment[@xml:id = //*[local-name()=$elem-by-id-in-stylesheet-param/local-name()][@xml:id!=($remove-ID, $extract-ID)]/descendant::*/@xsf:segment]) )" />

    
</xsl:variable>

        

    
            <xd:doc><xd:short><p>Containing the segments which are referenced by the elements which are to be deleted/extracted from the annotation (descendants of $elem-by-id-in-stylesheet-param).</p></xd:short></xd:doc>


    
<xsl:variable name="extractedSegments"><!--used by key, therefore document node-->

        
<xsl:copy-of select="elem:sort-segments( elem:copy-segments-with-new-ID( //xsf:segment[@xml:id = $elem-by-id-in-stylesheet-param/descendant::*/@xsf:segment] ) )" />

    
</xsl:variable>

    

    
            <xd:doc><xd:short><p>Textual content of inline annotation (primary data)</p></xd:short></xd:doc>


    
<xsl:variable name="primary-data" select="replace( if(//xsf:primaryDataRef/@uri) then unparsed-text(concat(string-join(tokenize(base-uri(/), '/')[position()!=last()], '/'), '/', //xsf:primaryDataRef/@uri), ((//xsf:primaryDataRef/@encoding, 'UTF-8')[.!=''])[1]) else //xsf:primaryData/*:textualContent/text() , ' ', '')" as="xs:string" />

    
<!--##########################-->

    

    

    
<!--##########Templates#########-->

    
            <xd:doc>

        
<xd:short><p>Initial template with several tasks → see detailed description</p></xd:short>

        
<xd:detail><p>

            Tasks fulfilled by this initial template:

            
<ol>

                
<li>Returning of messages containing information about provided stylesheet parameters</li>

                
<li>Applying other templates</li>

                
<li>Returning the deleted element in a separate XSF file if desired</li>

            
</ol>

        
</p></xd:detail>

    
</xd:doc>


    
<xsl:template match="/">

        
<xsl:copy-of select="undef:param-messages()" />

        
<xsl:choose>

            
<!--ERROR: no stylesheet paramater specified-->

            
<xsl:when test="empty(($remove-ID, $extract-ID))">

                
<xsl:message select="' ***ERROR: none of stylesheet parameters $remove-ID or $extract-ID specified!'" terminate="yes" />

            
</xsl:when>

            
<!--CORRECT: exactly one stylesheet paramater-->

            
<xsl:when test="count(($extract-ID, $remove-ID)) = 1">

                
<xsl:message select="if($elem-by-id-in-stylesheet-param) then concat(' # ', ('removing '[$remove-ID], 'extracting ')[1], $elem-by-id-in-stylesheet-param/local-name(), ' with ID ''', ($extract-ID, $remove-ID), '''') else concat(' ***ERROR: no element with ID ''', ($extract-ID, $remove-ID)[1], ''' found!')" terminate="{('no'[exists($elem-by-id-in-stylesheet-param)], 'yes')[1]}" />

            
</xsl:when>

            
<!--ERROR: both stylesheet parameters specified-->

            
<xsl:otherwise>

                
<xsl:message select="' ***ERROR: both of stylesheet parameters $remove-ID or $extract-ID specified (only one please)!'" terminate="yes" />

            
</xsl:otherwise>

        
</xsl:choose>

        

        
<xsl:apply-templates />

        

        
<xsl:if test="exists($remove-ID) and $return-removed">

            
<xsl:call-template name="return-removed-content" />

        
</xsl:if>

    
</xsl:template>

    

    

    
            <xd:doc><xd:short><p>Shallow copy of the matched element and application of further templates.</p></xd:short></xd:doc>


    
<xsl:template match="xsf:corpusData|xsf:annotation">

        
<xsl:copy>

            
<xsl:copy-of select="@*" />

            
<xsl:apply-templates />

        
</xsl:copy>

    
</xsl:template>

    

    

    
            <xd:doc><xd:short><p>Deep copy of the matched elements.</p></xd:short></xd:doc>


    
<xsl:template match="xsf:primaryData|xsf:meta">

        
<xsl:copy-of select="." />

    
</xsl:template>

    

    

    
            <xd:doc><xd:short><p>Creation of a new &lt;xsf:segmentation&gt; containing the segments which are present in the remaining layers and levels.</p></xd:short></xd:doc>


    
<xsl:template match="xsf:segmentation">

        
<xsf:segmentation>

            
<xsl:for-each select="if($remove-ID) then $newSegments/*:segment else $extractedSegments/xsf:segment">

                
<xsl:copy exclude-result-prefixes="double">

                    
<xsl:attribute name="xml:id" select="@newID" />

                    
<xsl:copy-of select="@*[name()!='xml:id' and name()!='newID']" />

                
</xsl:copy>

            
</xsl:for-each>

        
</xsf:segmentation>

    
</xsl:template>

    

    

    
            <xd:doc><xd:short><p>Copy or complex processing (depends on value of $keep-segments) of the &lt;xsf:level&gt; elements which do not match or contain the element that is to be deleted.</p></xd:short></xd:doc>


    
<xsl:template match="xsf:level[ if($remove-ID) then bool:compare2paramID(@xml:id, '!=') and exists(xsf:layer[bool:compare2paramID(@xml:id, '!=')]) else bool:compare2paramID(@xml:id, '=') or exists(xsf:layer[exists(@xml:id) and bool:compare2paramID(@xml:id, '=')]) ]">

        
<xsl:copy>

            
<xsl:copy-of select="@*" />

            
<xsl:for-each select="xsf:layer[ if($remove-ID) then (if(@xml:id) then @xml:id != $remove-ID else true()) else (if(bool:compare2paramID(../@xml:id, '=')) then true() else (exists(@xml:id) and bool:compare2paramID(@xml:id, '='))) ]">

                
<xsl:choose>

                    
<xsl:when test="$keep-segments">

                        
<xsl:copy-of select="." />

                    
</xsl:when>

                    
<xsl:otherwise>

                        
<xsl:call-template name="copyAnnotations">

                            
<xsl:with-param name="level" select="'new'" />

                        
</xsl:call-template>

                    
</xsl:otherwise>

                
</xsl:choose>

            
</xsl:for-each>

        
</xsl:copy>

    
</xsl:template>

    

    

    
            <xd:doc><xd:short><p>Explicitly ignoring the &lt;xsf:level&gt; being or containing the element which is to be deleted and the &lt;xsf:layer&gt; being the one to be deleted.</p></xd:short></xd:doc>


    
<xsl:template match="xsf:level[ (if(@xml:id) then (@xml:id=$remove-ID) else true()) or empty( xsf:layer[ bool:compare2paramID(@xml:id, '!=') ] ) ] | xsf:layer[ bool:compare2paramID(@xml:id, '=') ]" />

    

    

    
            <xd:doc><xd:short><p>Explicitly ignoring text nodes.</p></xd:short></xd:doc>


    
<xsl:template match="text()" />

    

    

     
            <xd:doc>

        
<xd:short><p>Copying annotation elements from levels or layers while returning the new segment references.</p></xd:short>

        
<xd:param name="level">If value is 'new' then the segment references from the $newSegments are used otherwise those from $removedSegments.</xd:param>

    
</xd:doc>


    
<xsl:template name="copyAnnotations">

        
<xsl:param name="level" as="xs:string" />

        
<xsl:copy>

            
<xsl:copy-of select="@* except @xsf:segment" />

            
<xsl:for-each select="@xsf:segment">

                
<xsl:attribute name="xsf:segment" select="if($level='new') then (if($remove-ID) then $newSegments/*:segment else $extractedSegments/xsf:segment)[@xml:id=current()]/@newID else $extractedSegments/*[@xml:id=current()]/@newID" />

            
</xsl:for-each>

            
<xsl:for-each select="*">

                
<xsl:call-template name="copyAnnotations">

                    
<xsl:with-param name="level" select="$level" />

                
</xsl:call-template>

            
</xsl:for-each>

        
</xsl:copy>

    
</xsl:template>

    

    

    
            <xd:doc><xd:short><p>Returning of the deleted annotation in a separate XSF file.</p></xd:short></xd:doc>


    
<xsl:template name="return-removed-content">

        
<xsl:result-document href="{concat(($remove-ID, 'removed-namespace')[1], '.xml')}">

            
<xsf:corpusData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsfVersion="1.1" xsi:schemaLocation="http://www.xstandoff.net/2009/xstandoff/1.1 http://www.xstandoff.net/2009/xstandoff/1.1/xsf.xsd" xml:id="{concat('cd-', $remove-ID)}">

                
<xsl:copy-of select="//xsf:primaryData" />

                
<xsf:segmentation>

                    
<xsl:for-each select="$extractedSegments/xsf:segment">

                        
<xsl:copy>

                            
<xsl:attribute name="xml:id" select="@newID" />

                            
<xsl:copy-of select="@*[name()!='xml:id' and name()!='newID']" />

                        
</xsl:copy>

                    
</xsl:for-each>

                
</xsf:segmentation>

                
<xsl:for-each select="$elem-by-id-in-stylesheet-param">

                    
<xsl:choose>

                        
<xsl:when test="local-name() = 'annotation'">

                            
<xsl:call-template name="copyAnnotations">

                                
<xsl:with-param name="level" select="'old'" />

                            
</xsl:call-template>

                        
</xsl:when>

                        
<xsl:when test="local-name() = 'level'">

                            
<xsf:annotation>

                                
<xsl:call-template name="copyAnnotations">

                                    
<xsl:with-param name="level" select="'old'" />

                                
</xsl:call-template>

                            
</xsf:annotation>

                        
</xsl:when>

                        
<xsl:when test="local-name() = 'layer'">

                            
<xsf:annotation>

                                
<xsf:level>

                                    
<xsl:call-template name="copyAnnotations">

                                        
<xsl:with-param name="level" select="'old'" />

                                    
</xsl:call-template>

                                
</xsf:level>

                            
</xsf:annotation>

                        
</xsl:when>

                        
<xsl:otherwise>

                            
<xsl:message select="'***ERROR: $remove-ID refers to wrong element, i.e. none of (xsf:annotation|xsf:level|xsf:layer) is matched'" terminate="yes" />

                        
</xsl:otherwise>

                    
</xsl:choose>

                
</xsl:for-each>

            
</xsf:corpusData>

        
</xsl:result-document>

    
</xsl:template>

    

    

    
            <xd:doc>

        
<xd:short><p>Sorting of segments by their @start and @end</p></xd:short>

        
<xd:param name="segments">Segments which shall be sorted.</xd:param>

    
</xd:doc>


    
<xsl:function name="elem:sort-segments" as="element()*">

        
<xsl:param name="segments" as="element()*" />

        
<xsl:for-each select="$segments">

            
<xsl:sort select="@start" data-type="number" order="ascending" />

            
<xsl:sort select="if(local-name()='milestone') then @x else @end" data-type="number" order="descending" />

            
<xsl:copy-of select="." />

        
</xsl:for-each>

    
</xsl:function>

    

    

    
            <xd:doc>

        
<xd:short><p>Copying segments and creating new IDs</p></xd:short>

        
<xd:param name="segments">Segments that shall be copied with their new ID.</xd:param>

    
</xd:doc>


    
<xsl:function name="elem:copy-segments-with-new-ID" as="element(xsf:segment)*">

        
<xsl:param name="segments" as="element(xsf:segment)*" />

        
<xsl:for-each select="$segments">

            
<xsl:copy>

                
<xsl:copy-of select="@*" />

                
<xsl:attribute name="newID" select="if($keep-segments) then @xml:id else concat('seg', position())" />

            
</xsl:copy>

        
</xsl:for-each>

    
</xsl:function>

    

    

    
            <xd:doc><xd:short><p>Returning messages about stylesheet parameters</p></xd:short></xd:doc>


    
<xsl:function name="undef:param-messages">

        
<xsl:message select="'--------------------'" />

        
<xsl:message select="' Provided stylesheet parameters:'" />

        
<xsl:message select="concat(' remove-ID=', $remove-ID)" />

        
<xsl:message select="concat(' extract-ID=', $extract-ID)" />

        
<xsl:message select="concat(' keep-segments=', $keep-segments)" />

        
<xsl:message select="'--------------------'" />

    
</xsl:function>

    

    

    
            <xd:doc>

        
<xd:short><p>Comparison of the provided $ID to the ($remove-id|$extract-ID).</p></xd:short>

        
<xd:param name="ID">String to be compared to ($remove-id|$extract-ID).</xd:param>

        
<xd:param name="comparation">Operator serving for equation: '!=' or '='</xd:param>

    
</xd:doc>


    
<xsl:function name="bool:compare2paramID" as="xs:boolean">

        
<xsl:param name="ID" as="xs:string?" />

        
<xsl:param name="comparation" as="xs:string" />

        
<xsl:copy-of select="if($ID) then (if($comparation='=') then ($ID=($remove-ID, $extract-ID)) else (if($comparation='!=') then not($ID=($remove-ID, $extract-ID)) else error((), '***ERROR: wrong parameter for bool:ID-vs-removeID()')) ) else true()" />

    
</xsl:function>

    

    

</xsl:stylesheet>













































































v