Thursday, 16 October 2014

XSLT: Copy All, but 'cut-and-paste' some content



Background


A more more general version of my problem was recently posted but due to the quality of the post, it received no responses. Here's my attempt!


I have the following XML structure that I want to transform


Pre-processed XML



<schema>

<!-- element to be imbedded -->

<element name="tryCatch.catch">
<complexType>
<complexContent>
<extension base="escalateContainer">
<attribute name="var" type="_var" />
</extension>
</complexContent>
</complexType>
</element>

<complexType name="tryCatch">
<complexContent>
<extension base="scriptElement">
<sequence>
<element name="try" type="escalateContainer" />
<element name="catch" type="tryCatch.catch" minOccurs="0" />
<element name="finally" type="escalateContainer" minOccurs="0" />
</sequence>
</extension>
</complexContent>
</complexType>

</schema>


...into the following structure:


Post XSLT-Structure



<schema>

<complexType name="tryCatch">
<complexContent>
<extension base="scriptElement">
<sequence>
<element name="try" type="escalateContainer" />

<!-- Change here! -->

<element name="tryCatch.catch" minOccurs="0">
<complexType>
<complexContent>
<extension base="escalateContainer">
<attribute name="var" type="_var" />
</extension>
</complexContent>
</complexType>

</element>
<element name="finally" type="escalateContainer" minOccurs="0" />
</sequence>
</extension>
</complexContent>
</complexType>

</schema>


Overview of the Process


Basically, I just want to



  1. Copy everything


  2. Then find all element children of a complexType that have a . in their name (by construction - I have ensured this pattern works interally in my XML). A simplified version of my match is:



    complexType.element.type = element.name





  3. Last, replace that element with the corresponding global element. Bonus points if the attributes on the element being replaced are also copied.




What I have So Far



<xsl:template match="@* | node()">

<xsl:copy>

<xsl:apply-templates select="@* | node()" />

</xsl:copy>

</xsl:template>

<xsl:template match="schema">

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

<xsl:variable name="self" select="current()" />

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

<xsl:for-each select="/schema/complexType//element[@type=$name]">

<xsl:copy-of select="$self" />

</xsl:for-each>

</xsl:for-each>

</xsl:template>


I think I'm off to the right start - copy everything with the identity template, then process what I want to change. The problem is that my second template only returns the copied element! The match appears to work great, I just lose all the other content I'm trying to preserve.


No comments:

Post a Comment