Convert Processing Instructions

I want to convert processing instructions in source xml to some tag in output file

Enter

<?xml version="1.0" encoding="utf-8"?> <root> <?PI_start?> SOME TEXT <?PI_end?> </root> 

I want the output XML file to be like this

 <root> <tag> SOME TEXT </tag> </root> 

Can I do it? If so, which xsl should I use for the conversion?

I only found a way to convert PI to opening and closing tags. PI may contain some content.

XML input

 <root> <?PI SOME TEXT?> </root> 

XSL

 <xsl:template match="processing-instruction('PI')"> <tag><xsl:value-of select="."/></tag> </xsl:template> 

Exit

 <tag>SOME TEXT</tag> 

But it's a little not my thing

+6
xslt
source share
2 answers

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> 
+10
source share

I suggest another way to solve my problem. Hope this is correct.

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output omit-xml-declaration="yes" indent="yes" /> <xsl:template match="node()|@*"> <xsl:copy> <xsl:apply-templates select="node()|@*" /> </xsl:copy> </xsl:template> <xsl:template match="processing-instruction('PI_start')"> <xsl:text disable-output-escaping="yes"><![CDATA[<tag>]]></xsl:text> </xsl:template> <xsl:template match="processing-instruction('PI_end')"> <xsl:text disable-output-escaping="yes"><![CDATA[</tag>]]></xsl:text> </xsl:template> 

Enter

 <root> <?PI_start?> <strong>Some</strong> TEXT <?PI_end?> XA <?PI_end?> </root> 

The correct conclusion is made.

 <root> <tag> <strong>Some</strong> TEXT </tag> XA </tag> </root> 
+1
source share

All Articles