The backstory is that this is an old ColdFusion Application that is being upgraded to ColdFusion 11. I've already determined the subject error I'm now seeing is because XSLT 1.0 processors were allowed to ignore this error and "recover" by ignoring the xsl:attribute instruction. (Thank you ref Michael Kay.)
I can't quite wrap my brain around a solution, so here's some simplified code:
The XML
<?xml version="1.0" encoding="UTF-8"?>
<Organization>
<Subscriber>
<data>
<struct>
<var name='DEPENDENT'>
<array length='1'>
<struct>
<var name='PROVIDER'>
<struct>
<var name='PROVIDERCODE'>
<string>A4321</string>
</var>
<var name='TYPE'>
<string>Primary Care Provider</string>
</var>
</struct>
</var>
</struct>
</array>
</var>
</struct>
</data>
</Subscriber>
</Organization>
You may recognize this as old WDDX format. The XSLT below converts this ugly, deeply-nested format to a cleaner/simpler XML format.
The XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:template match="/">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="var">
<xsl:choose>
<xsl:when test="translate(@name, 'TEX', 'tex') = 'text'">
<xsl:value-of select="./string"/>
</xsl:when>
<xsl:when test="translate(@name, 'TYPE', 'type') = 'type'">
<xsl:attribute name="type">
<xsl:value-of select="./string"/>
</xsl:attribute>
</xsl:when>
<xsl:when test="child::array">
<xsl:apply-templates/>
</xsl:when>
<xsl:otherwise>
<xsl:element name="{translate(@name,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')}">
<xsl:apply-templates/>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="struct">
<xsl:apply-templates/>
</xsl:template>
<xsl:template match="array">
<xsl:param name="parentname" select="translate(../@name,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')"/>
<xsl:for-each select="struct">
<xsl:element name="{$parentname}">
<xsl:if test="./var[translate(@name, 'RELATIONSHPCD', 'relationshpcd') = 'relationshipcode']">
<xsl:attribute name="relationshipcode"><xsl:value-of select="./var[translate(@name, 'RELATIONSHPCD', 'relationshpcd') = 'relationshipcode']"/></xsl:attribute>
</xsl:if>
<xsl:apply-templates/>
</xsl:element>
</xsl:for-each>
</xsl:template>
<xsl:template match="string|number">
<xsl:value-of select="."/>
</xsl:template>
<xsl:template match="boolean">
<xsl:value-of select="@value"/>
</xsl:template>
<xsl:template match="Subscriber">
<subscriber>
<xsl:apply-templates/>
</subscriber>
</xsl:template>
<xsl:template match="Organization">
<organization>
<xsl:apply-templates/>
</organization>
</xsl:template>
</xsl:stylesheet>
Unfortunately, the case of the WDDX name attributes is inconsistent, so the translate commands are there to address that, and unfortunately, make the code a bit more complex.
The Expected Output
<?xml version="1.0" encoding="UTF-8"?>
<organization>
<subscriber>
<dependent>
<provider type="Primary Care Provider">
<providercode>A4321</providercode>
</provider>
</dependent>
</subscriber>
</organization>
The Problem
The problem arises from the fact that, in the example above, the "providercode" could get added to the "provider" node before the "type" node gets encountered, resulting in the "attribute node cannot be created after the children of the containing element" error.o
Note that I've simplified the example above for clarity. There are roughly a half-dozen "var" nodes with specific "name" attributes that should be inserted as attributes while the others simple get added directly as nodes.
Any help in how to solve this would be greatly appreciated.
Thanks in advance.
Paul
Unfortunately, the case of the WDDX name attributes is inconsistent, so the translate commands are there to address that, and unfortunately, make the code a bit more complex.
It's too bad you did not take this (and other non-essentials) out of your example - see: https://stackoverflow.com/help/mcve
IIUC, something like the following would solve your problem. The idea is to apply templates creating attributes before templates that create children.
...
<xsl:template match="var[not(@name='TYPE')]">
<xsl:choose>
<xsl:when test="translate(@name, 'TEX', 'tex') = 'text'">
<xsl:value-of select="./string"/>
</xsl:when>
<xsl:when test="child::array">
<xsl:apply-templates/>
</xsl:when>
<xsl:otherwise>
<xsl:element name="{translate(@name,'ABCDEFGHIJKLMNOPQRSTUVWXYZ','abcdefghijklmnopqrstuvwxyz')}">
<xsl:apply-templates select="struct/var[@name='TYPE']"/>
<xsl:apply-templates/>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="var[@name='TYPE']">
<xsl:attribute name="type">
<xsl:value-of select="./string"/>
</xsl:attribute>
</xsl:template>
<xsl:template match="struct">
<xsl:apply-templates select="var[not(@name='TYPE')]"/>
</xsl:template>
...