This conversion is :
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:template match="node()|@*"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:template> <xsl:template match="processing-instruction('PI_start')"> <tag> <xsl:apply-templates mode="copy" select= "following-sibling::node()[1][self::text()]"/> </tag> </xsl:template> <xsl:template match= "processing-instruction('PI_end') | text()[preceding-sibling::node()[1] [self::processing-instruction('PI_start')]] "/> </xsl:stylesheet>
when applied to the provided XML document :
<?xml version="1.0" encoding="utf-8"?> <root> <?PI_start?> SOME TEXT <?PI_end?> </root>
creates the desired, correct result :
<root> <tag> SOME TEXT </tag> </root>
Please note :
To copy all nodes as-is, an identification rule is used .
We have additional templates only for nodes that need to be changed in any way.
The pattern matching the first PI does almost all the work. It creates a tag element and applies the templates to the next sibling node, if it is PI,
We apply templates in "copy" mode for the node text of the closest relative of the first PI .
The "copy" mode is not declared anywhere, and this causes the selection of a default template for processing text nodes . Its action is to simply copy the text node. This is a trick that eliminates the need to define a template in copy mode.
We have an empty template that actually removes unwanted nodes : the second PI and what will be the second copy of the first text of the immediate text of the PI node.
Update : The OP indicated that he was also interested in the fact that there could be different nodes (not just text nodes) between the two PIs.
This is a much more difficult task, and here is one solution:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output omit-xml-declaration="yes" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:key name="kSurrounded" match="node()" use="concat( generate-id(preceding-sibling::processing-instruction('PI_start')[1]), '+++', generate-id(following-sibling::processing-instruction('PI_end')[1]) )"/> <xsl:template match="node()|@*" name="identity"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:template> <xsl:template match="processing-instruction('PI_start')"> <tag> <xsl:apply-templates mode="copy" select= "key('kSurrounded', concat(generate-id(), '+++', generate-id(following-sibling::processing-instruction('PI_end')[1]) ) )"/> </tag> </xsl:template> <xsl:template match= "processing-instruction('PI_end') | node()[(preceding-sibling::processing-instruction('PI_start') | preceding-sibling::processing-instruction('PI_end') ) [last()][self::processing-instruction('PI_start')] and (following-sibling::processing-instruction('PI_start') | following-sibling::processing-instruction('PI_end') ) [1][self::processing-instruction('PI_end')] ] "/> <xsl:template match="node()" mode="copy"> <xsl:call-template name="identity"/> </xsl:template> </xsl:stylesheet>
when the specified conversion is applied to the following XML document :
<root> <?PI_start?> <strong>Some</strong> TEXT <?PI_end?> XA <?PI_end?> </root>
the correct output is correct :
<root> <tag> <strong>Some</strong> TEXT </tag> XA </root>
Dimitre novatchev
source share