Re: [xsl] General algorithm for finding nodes between PIs

Subject: Re: [xsl] General algorithm for finding nodes between PIs
From: "Rick Quatro rick@xxxxxxxxxxxxxx" <xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx>
Date: Fri, 27 Jan 2017 14:24:24 -0000
I modified my input document slightly:

<?xml version="1.0" encoding="UTF-8"?>
<info>
    <?Fm Condstart VbV-VCO?>
    <p>For this, use <b>that </b>to do that.</p>
    <?Fm Condend VbV-VCO?>
    <p><?Fm Condstart USB?>If you need this, do that.<?Fm Condend USB?></p>
    <p>Outside paragraph.</p>
</info>

Here is how I have implemented Michael's stylesheet:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
 	xmlns:xs="http://www.w3.org/2001/XMLSchema";
 	exclude-result-prefixes="xs"
 	version="2.0">
 	
 	<xsl:output indent="yes"/>
    
 	<xsl:template match="/">
 		<results>
 			<xsl:apply-templates/>
 		</results>
 	</xsl:template>
 	
 	<xsl:template match="*[processing-instruction('Fm')[starts-with(.,
'Condstart')]]">
 		<xsl:for-each-group select="node()"
group-starting-with="processing-instruction('Fm')[starts-with(.,
'Condstart')]">
 			<xsl:if
test="self::processing-instruction('Fm')[starts-with(., 'Condstart')]">
 				<group name="{.}">
 					<xsl:variable name="pi-end-name"
select="replace(., 'Condstart', 'Condend')"/>
 					<xsl:for-each-group
select="current-group() except ."
group-ending-with="processing-instruction('Fm')[. = $pi-end-name]">
 						<xsl:if
test="current-group()[last()][self::processing-instruction('Fm')[. =
$pi-end-name]]">
 							<xsl:copy-of
select="current-group()[position() ne last()]"/>
 						</xsl:if>
 					</xsl:for-each-group>
 				</group>
 			</xsl:if>
 		</xsl:for-each-group>
 		<xsl:apply-templates/>
 	</xsl:template>
 	
 	<xsl:template match="text()"/>
 	
</xsl:stylesheet>

Here is my output:

<?xml version="1.0" encoding="UTF-8"?>
<results>
   <group name="Condstart VbV-VCO">
      <p>For this, use <b>that </b>to do that.</p>
    </group>
   <group name="Condstart USB">If you need this, do that.</group>
</results>

This is close, but I don't want to lose any elements from the output, like
the parents of the processing instructions (<info>, <p>). Also, I am not
picking up my last <p> element. Thank you for the generous help.

Rick

-----Original Message-----
From: Michael Kay mike@xxxxxxxxxxxx
[mailto:xsl-list-service@xxxxxxxxxxxxxxxxxxxxxx] 
Sent: Thursday, January 26, 2017 5:42 PM
To: xsl-list@xxxxxxxxxxxxxxxxxxxxxx
Subject: Re: [xsl] General algorithm for finding nodes between PIs

> 

I think this could be simplified:

> <xsl:template match="*[processing-instruction('Fm')[starts-with(.,
'Condstart')]]">
> 		<xsl:for-each-group select="node()"
group-starting-with="processing-instruction('Fm')[starts-with(.,
'Condstart')]">
> 			<xsl:if
test="self::processing-instruction('Fm')[starts-with(., 'Condstart')]">
> 				<group name="{.}">
> 					<xsl:variable name="pi-end-name"
select="replace(., 'Condstart', 'Condend')"/>
> 					<xsl:variable name="end"
select="following-sibling::processing-instruction('Fm')[. =
$pi-end-name][1]">
> 					<xsl:copy-of
select="current-group()[. &lt;&lt; $end]"/>
> 				</group>
> 			</xsl:if>
> 		</xsl:for-each-group>
> 		<xsl:apply-templates/>
> 	</xsl:template>

Michael Kay
Saxonica

> 
> Like this:
> 
> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform";
> 	xmlns:xs="http://www.w3.org/2001/XMLSchema";
> 	exclude-result-prefixes="xs"
> 	version="2.0">
> 	
> 	<xsl:template match="/">
> 		<results>
> 			<xsl:apply-templates/>
> 		</results>
> 	</xsl:template>
> 	
> 	<xsl:template match="*[processing-instruction('Fm')[starts-with(.,
'Condstart')]]">
> 		<xsl:for-each-group select="node()"
group-starting-with="processing-instruction('Fm')[starts-with(.,
'Condstart')]">
> 			<xsl:if
test="self::processing-instruction('Fm')[starts-with(., 'Condstart')]">
> 				<group name="{.}">
> 					<xsl:variable name="pi-end-name"
select="replace(., 'Condstart', 'Condend')"/>
> 					<xsl:for-each-group
select="current-group() except ."
group-ending-with="processing-instruction('Fm')[. = $pi-end-name]">
> 						<xsl:if
test="current-group()[last()][self::processing-instruction('Fm')[. =
$pi-end-name]]">
> 							<xsl:copy-of
select="current-group()[position() ne last()]"/>
> 						</xsl:if>
> 					</xsl:for-each-group>
> 				</group>
> 			</xsl:if>
> 		</xsl:for-each-group>
> 		<xsl:apply-templates/>
> 	</xsl:template>
> 	
> 	<xsl:template match="text()"/>
> 	
> </xsl:stylesheet>

Current Thread