A recent requirement entailed the round-tripping of elements to processing instructions and then back again to their original elements using a second transformation. This presented a few challanges.
The elements concerned were off the form
<err:Warning
foo="1234567"
bar="abcd/efgh/jklm">content that records "some message"</err:Warning>
The first part of the round trip, is to take the elements that were all in a single namespace, and recast them as PI's. The attributes are taken through as name-value pairs and the content is taken through as a name value pair of the form content={content}.
<xsl:template match="err:*">
<xsl:processing-instruction name="err-{local-name()}">
<xsl:for-each select="@*">
<xsl:value-of select="name()"/>
<xsl:text>="</xsl:text>
<xsl:value-of select="."/>
<xsl:text>" </xsl:text>
</xsl:for-each>
<xsl:text>content="</xsl:text>
<xsl:value-of select='.'/>
<xsl:text>"</xsl:text>
</xsl:processing-instruction>
</xsl:template>
Running this transformation in Saxon gives the end result of:
<?err-Warning foo="1234567" bar="abcd/efgh/jklm" content="content that records "some message""?>
It must be remembered that PIs do not have attributes, although the result looks to all intents and purposes as an attribute, they are not and you cannot target a PI attribute with an xpath as it does not exists! Therefore, it is a little more of a challange to get this back to their original attributes. In XSLT 2 we can use regular expresions to recreate the attributes.
Firstly, filter out the content={value} name value pair, then use the remaining string as the source for an analyze-string and a regualr expression of ([\c]+)="(.*?") where the second group targets the end quote of the name-value pair. This end quote then needs removing with the translate() or replace() function
<xsl:template match="processing-instruction()[starts-with(name(),'err-')]">
<xsl:variable name="PI" select="substring-before(.,'content=')" />
<xsl:variable name="PIname" select="substring-after(name(), 'err-')"/>
<xsl:variable name="content" select="substring-after(., 'content="')"/>
<xsl:element name="err:{$PIname}">
<xsl:analyze-string select="$PI" regex='([\c]+)="(.*?")'>
<xsl:matching-substring>
<xsl:attribute name="{regex-group(1)}">
<xsl:value-of select='translate(regex-group(2),"""", "")'/>
</xsl:attribute>
</xsl:matching-substring>
</xsl:analyze-string>
<!-- remove the last double quote from the content -->
<xsl:value-of select='replace($content,"""$", "")' />
</xsl:element>
</xsl:template>
Running this transformation in Saxon returns us back to the original element:
<?err-Warning foo="1234567" bar="abcd/efgh/jklm" content="content that records "some message""?>
No comments:
Post a Comment